Skip to content

Releases: topcheer/ggcode

v1.3.81

22 Jun 10:59

Choose a tag to compare

v1.3.81

Three-End Interaction Reliability

Comprehensive hardening of the desktop ↔ relay ↔ mobile communication chain, guided by two principles: messages must never be lost, and messages must never be redundantly replayed at the network layer.

Relay Server

  • Duplicate event forwarding eliminatedappendEvent now returns whether an event is new or a duplicate. handleServerBroadcast skips forwarding duplicate events to connected clients, preventing redundant replay when desktop reconnects and replays its event history.

  • Mobile→Desktop message persistence — Client-to-server messages are now persisted to room history and SQLite before forwarding. If desktop is offline, messages are buffered and recovered via cursor-based replay on reconnect. Previously these messages were silently dropped.

  • sendCh buffer reduced (10000 → 512) — Prevents goroutine starvation under slow-peer backpressure.

  • Non-blocking sendRaw with grace period — Events are persisted before live-forward, so a dropped real-time delivery is recoverable via cursor replay. A 2s grace period prevents indefinite blocking.

  • Active WebSocket ping (30s interval) in writeLoop for half-open connection detection. Read deadline shortened 120s → 75s (3 missed pongs).

Desktop (CLI/GUI/Daemon)

  • writePump write deadline — All WriteMessage calls now set a 30s SetWriteDeadline, preventing indefinite blocking on network black holes. Failed writes push messages back to pending queue for retry after reconnect.

  • Progressive backoff schedule — 5s, 10s, 20s, 40s (×4), 2min (×6), then 5min indefinitely. Previously capped at 40s forever, causing excessive requests during long outages.

  • Daemon message queue fixdaemonTunnelShareController.userOverride was a single pointer; rapid mobile messages overwrote each other. Changed to a FIFO queue ([]MessageData), bringing daemon to parity with TUI's pendingQueue.

Mobile

  • Exponential backoff (2^n, capped 60s) replacing linear (2n). After 15 fast attempts, switches to 5-minute slow retry — never gives up. Previously gave up permanently after 30 linear attempts (~15 min).

  • Pong timeout detection — 3 consecutive missed pongs (60s) triggers _forceReconnect for half-open connection detection, complementing the relay's server-side ping.

v1.3.80

21 Jun 17:11

Choose a tag to compare

v1.3.80

Mobile Release Pipeline Overhaul

This release fixes a critical gap in the iOS App Store release workflow: pending review submissions were never automatically rejected, causing new versions to be blocked indefinitely.

iOS App Store Review

  • Auto-reject pending review submissions — When a previous version is stuck in READY_FOR_REVIEW, the pipeline now automatically removes the old review submission item (via raw ASC API DELETE v1/reviewSubmissionItems/{id}) before submitting the new version. This unblocks the version and allows a fresh submission.

  • Developer reject for IN_REVIEW versions — Versions in WAITING_FOR_REVIEW or IN_REVIEW are now developer-rejected via DELETE v1/appStoreVersionSubmissions/{id}.

  • Separated TestFlight from App Store Reviewdeploy_external lane now handles TestFlight External Testing only. A new submit_for_review lane handles App Store Review submission independently. The CI workflow runs them as separate steps (continue-on-error: true on the review step), so TestFlight success is not blocked by App Store Review issues.

CI Fixes

  • check_build_version actually queries App Store Connect — The check_build_version lane used app_store_build_data() which doesn't exist in fastlane. The call always threw an exception, was caught by rescue, and unconditionally printed NOT_UPLOADED. The check never actually queried ASC. Replaced with Spaceship::ConnectAPI + get_builds (same pattern as expire_and_promote and inspect lanes).

  • BUILD_VERSION extraction fixedgrep 'CFBundleVersion' only matched the <key> line, not the <string> value line. The version number was always empty. Replaced with PlistBuddy (same tool used elsewhere in the pipeline).

Commits

96ca611c fix: auto-cancel pending App Store review submission before new submit
923a5bd6 fix: separate TestFlight External from App Store Review, fix developer reject
5da1add2 fix: check_build_version never actually queried App Store Connect
b001c47b fix: use raw API for review submission item deletion (Spaceship doesn't have it)

v1.3.79

21 Jun 13:40

Choose a tag to compare

v1.3.79

Bug Fixes

MCP OAuth

  • OAuth resource param inversion — The resource parameter merge logic was inverted. When an OAuth provider's authorization_endpoint already contains a resource parameter (e.g. Railway's backboard.railway.com), it now correctly takes priority over the server-URL-derived value. Previously the code-supplied value would override the endpoint's built-in value.

  • DCR redirect_uri port mismatch — The OAuth Dynamic Client Registration (DCR) was registering redirect_uri=http://localhost:0/callback because the callback HTTP server hadn't started yet. The callback server is now started before DCR registration, ensuring the registered port matches the actual listening port.

Terminal & TUI

  • TTY watchdog race condition — After program.Run() returns, bubbletea restores the terminal (disables raw mode). The TTY watchdog's 250ms ticker would detect ICANON/ECHO being re-enabled and re-apply forceRawMode(), leaving the terminal stuck in raw mode after exit. The stop() function now waits for the goroutine to exit before restoring terminal state.

  • tmux command pane targeting — When a user switched tmux tabs, new command panes were created in the currently-active tab instead of ggcode's own tab. split-window now uses -t <selfPane> to always target ggcode's pane. paneExists also searches all windows (-a) instead of just the active one.

Session Management

  • Stale lock file auto-cleanup — Session lock files from crashed or killed processes (SIGKILL, panic, power loss) are now automatically cleaned up: (1) Release() deletes the lock file after releasing the flock, (2) IsSessionLocked() removes stale lock files it encounters, (3) CleanupStaleLocks() runs at startup to scan and remove stale locks.

Code Quality (from Claude review)

  • OAuth token body no longer logged — OAuth token response bodies (containing access/refresh tokens) are no longer written to the debug log. Only the body length is logged.

  • OAuth nil-state guardsExchangeCode and PollDeviceToken now check for nil authorizationServerMeta before accessing its fields, preventing a panic if called before OAuth discovery completes.

  • Lock path cross-platform fixLockFilePath uses filepath.Join instead of string concatenation with /, fixing potential path corruption on Windows.

  • Stale lock deletion race fixedIsSessionLocked now removes stale lock files while holding the flock, before unlock+close, preventing a TOCTOU race where another process could create a new file between unlock and remove.

  • Broker goroutine crash safety — Bare go func() calls in the tunnel broker's relay replay paths are replaced with safego.Go for panic recovery.

Documentation

  • Full documentation cleanup — Deleted 38 stale files (old reviews round3-8, pre-implementation research, old plans), moved stray docs to proper subdirectories, and rewrote ARCHITECTURE.md to reflect the current codebase (Wails desktop, all new packages).

  • New delegation guide — Added docs/guide/delegation.md covering the delegate tool and all 16 supported external agents (Copilot, Claude, Cursor, Codex, Gemini, Kimi, Qwen, etc.).

  • README updates — Added missing features (ACP/Editor integration, WebUI, Scheduled tasks) and doc links to both English and Chinese READMEs.

Test Coverage

  • Added tests for OAuth nil-state guards (ExchangeCode_NilStateGuard, PollDeviceToken_NilStateGuard, ExchangeCode_EmptyMetadataGuard)
  • Added tests for stale lock cleanup (SessionLock_ReleaseDeletesFile, IsSessionLocked_RemovesStaleLock, CleanupStaleLocks)
  • Fixed LockFilePath test assertion to use filepath.Join

Commits

9ec4c357 fix: OAuth resource param logic was inverted
914e0d2f fix: OAuth DCR redirect_uri port mismatch
237acb6d fix: TTY watchdog re-applies raw mode after bubbletea restores terminal on exit
7ea71c98 fix: auto-cleanup stale session lock files
a71bdb4c fix: tmux command pane created in wrong tab
ea4e70de fix: address Critical and High findings from Claude code review
0a62837a revert: remove outbound queue soft cap
8c1e1011 docs: explain why outbound queue is intentionally unbounded
5bbd0b76 test: add tests for review fix coverage
3a0fc228 docs: full documentation cleanup
e64e6060 docs: add missing features to README
12301693 docs: add delegation guide

v1.3.77

21 Jun 09:19

Choose a tag to compare

v1.3.77

MCP OAuth Fixes: Railway Support & Per-Server Credential Isolation

Three fixes that make MCP OAuth work with providers like Railway and enable multi-account support for same-URL servers.

Fixes

  • Authorization URL construction — When an OAuth provider's authorization_endpoint already contains query parameters (e.g. Railway embeds ?resource=backboard.railway.com), the URL is now properly parsed and merged instead of producing malformed URLs with double ? or duplicate resource parameters. The endpoint's own resource value takes priority over the server-URL-derived value (RFC 8707).

  • Session locking for concurrent instances — When multiple ggcode instances start in the same workspace, they no longer auto-load the same session. New sessions acquire a lock, locked sessions are filtered from the resume picker, and LatestForWorkspace normalizes workspace paths for reliable comparison.

New Features

  • Per-server OAuth credential isolation — OAuth tokens are now saved under a server-name key (mcp:<name>) with a canonical shared key (mcp-shared:<issuer>|<resource>) as fallback. This means you can configure multiple MCP servers with the same URL but different accounts:

    mcp_servers:
      cf:
        name: cf
        type: http
        url: https://mcp.cloudflare.com/mcp
      cf2:
        name: cf2
        type: http
        url: https://mcp.cloudflare.com/mcp

    Each server maintains its own credential. Token refresh only updates the server-name key.

  • Reset Auth (switch account) — Re-authenticate a specific MCP server without affecting others:

    • TUI: Press a in the MCP panel
    • Desktop: Click the key icon next to an HTTP/WS server in Settings > MCP Servers

    This deletes the server-specific credential, skips the shared fallback, and triggers a fresh OAuth flow for account switching.

Documentation

  • Updated MCP guide with OAuth token storage, load priority, reset auth, and multi-account configuration examples.

v1.3.76

21 Jun 07:14

Choose a tag to compare

v1.3.76

LSP Desktop Integration with One-Click Install

The desktop app now fully integrates Language Server Protocol (LSP) support — the same code intelligence powering the CLI/TUI agent is now visible and manageable from the desktop UI.

New Features

  • Settings > Integrations > Language Servers panel — view auto-detected LSP servers for your workspace with status badges (available/not found) and binary paths
  • One-click install — install missing language servers directly from the desktop UI with scope priority:
    • User (recommended) — installs to home directory, no sudo needed
    • Global — system-wide installation
    • Project — workspace-local installation (last resort)
  • Config overrides — new lsp_servers config key to override auto-detected binary paths per language:
    lsp_servers:
      go:
        binary: /usr/local/bin/gopls
        args: ["-vv"]

Language Server Install Methods

Language User (Recommended) Global Project
Go go install golang.org/x/tools/gopls@latest
Rust rustup component add rust-analyzer
Python pip install --user pyright project venv
TypeScript npm install -g typescript-language-server
YAML npm install -g yaml-language-server --save-dev
JSON npm install -g vscode-langservers-extracted --save-dev
Dockerfile npm install -g dockerfile-language-server-nodejs --save-dev
Shell npm install -g bash-language-server --save-dev
C# dotnet tool install -g csharp-ls --tool-path .ggcode/tools

Improvements

  • dotnet install commands set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 to avoid first-run setup issues
  • Install health check for dotnet: detects broken ~/.dotnet symlinks and provides actionable error messages

Documentation

  • Updated docs/guide/configuration.md with LSP Servers section
  • Updated docs/guide/desktop.md features list
  • Updated GGCODE.md with lsp_servers config key and LSP tool descriptions
  • Updated ggcode.example.yaml with commented lsp_servers section

v1.3.75

20 Jun 12:45

Choose a tag to compare

ggcode v1.3.75

Highlights

  • multi_file_write tool: Create or overwrite multiple files in a single call with atomic mode (all-or-nothing) or partial_success mode. Parent directories are created automatically.
  • iOS beta auto-expire: The mobile release pipeline now automatically expires previous TestFlight builds and cancels stale beta reviews before promoting a new build, fixing the "Another build is already in beta review" error.
  • Command pane resize handling: Terminal command pane now correctly detects window resize, portrait/landscape orientation (including pixel-accurate detection via TIOCGWINSZ), and recreates panes when direction or size changes significantly.
  • Exit path pane cleanup: /restart and remote restart now properly clean up command panes via shutdownAll(), preventing orphan tmux panes.

New tool: multi_file_write

Batch-create or overwrite files in one tool call instead of repeated write_file invocations.

  • atomic mode (default): If any file fails (e.g., sandbox violation), no files are written.
  • partial_success mode: Successfully writes valid files while reporting failures.
  • Parent directories are created automatically via MkdirAll.
  • Duplicate path detection within a single batch.
  • Sandbox validation on all paths before any writes.

iOS beta expire & promote

  • New _expire_previous_beta_builds fastlane method: cancels WAITING_FOR_REVIEW beta submissions and expires old VALID builds.
  • Integrated into _promote_to_external — runs automatically before submitting new beta review.
  • New standalone expire_and_promote lane for manual fixes via workflow_dispatch.
  • New expire-and-promote job in mobile-release.yml with expire_and_promote boolean input.
  • Build jobs correctly skip when only doing expire & promote.

Command pane improvements

  • EnsurePane now calls shouldRecreatePane() on every invocation instead of early-returning when a pane exists.
  • Pane is recreated when: direction changes (right ↔ bottom), size drifts >50% in same direction, or pane was killed externally.
  • Pixel-based portrait detection via TIOCGWINSZ syscall (ws_xpixel/ws_ypixel) for accurate physical orientation detection.
  • Fallback to cell-based detection when pixels unavailable.
  • New pixel_unix.go (TIOCGWINSZ) and pixel_other.go (stub) platform-specific files.

Fixes and improvements

  • Fixed CI build failure from missing sizing.go, pixel_unix.go, pixel_other.go files (untracked files not committed).
  • Fixed CI build failure from missing StartCommandTool fields (OutputTee, OnPreExec, OnPostExec).
  • Fixed /restart and remote restart not calling shutdownAll(), leaving orphan command panes.

Upgrade notes

  • The new multi_file_write tool is automatically available — no configuration changes needed.
  • iOS beta expiration runs automatically during tag-driven releases; use the expire_and_promote workflow input for manual fixes.
  • Command pane resize detection is automatic; tmux handles small proportional resizes.

Compare

v1.3.74...v1.3.75

v1.3.74

19 Jun 15:31

Choose a tag to compare

ggcode v1.3.74

Highlights

  • Extpane for sub-agent/teammate tabs: Sub-agents and teammates now open real terminal tabs (tmux windows, Kitty tabs, or iTerm2 tabs) that stream their output live via tail -f. Tabs auto-close when the agent finishes.
  • Sub-agent completion no longer interrupts busy main agent: When a sub-agent or teammate finishes while the main agent is running, the completion is shown as a system message only — no longer injected into the main agent's conversation.

Extpane terminal tabs

  • New internal/tui/extpane/ package with three auto-detected backends: tmux (highest priority when $TMUX is set), Kitty (KITTY_WINDOW_ID), and iTerm2 (TERM_PROGRAM == "iTerm2")
  • Each sub-agent or teammate gets its own tab showing live output
  • Safety: maxPanes=10 hard cap, permanent blocklist after first failure, self-window ID capture prevents closing ggcode's own tab
  • Kitty backend uses --type=tab (consistent with iTerm2 and tmux)
  • tmux backend suppresses user after-new-window hooks during programmatic tab creation to avoid interactive rename prompts

Fixes

  • Fixed Kitty extpane creating new OS windows instead of tabs (--type=window--type=tab)
  • Fixed tmux extpane blocked by user after-new-window rename prompt hooks
  • Fixed sub-agent/teammate completion injecting hidden pending submissions into busy main agent
  • Prevented extpane tab explosion and self-closure with failed-agent blocklist and self-ID capture

v1.3.73

19 Jun 02:55

Choose a tag to compare

ggcode v1.3.73

Highlights

  • iTerm2 terminal tool: Full pane/session management for macOS iTerm2 users. 16 actions including split, new_tab, new_window, focus, close, input, send_key, resize, get_text, set_title, profile switch, badge, mark, and clear.
  • Kitty terminal tool: Complete remote control protocol integration for Kitty terminal. 17 actions including split, tabs, zoom, get_text, resize, and arbitrary action execution.
  • Warp terminal tool: Pane and block management for Warp terminal.
  • Ghostty Linux support: Ghostty tool now works on Linux via GIO DBus IPC, in addition to existing macOS AppleScript support.
  • Winget duplicate PR prevention: Release workflow now checks for existing winget PRs before submitting, preventing duplicates on re-run.

New terminal tools

iTerm2 (macOS)

  • Detection: TERM_PROGRAM == "iTerm.app"
  • All actions use native AppleScript or TTY escape sequences — no Accessibility permissions required for core operations
  • Session targeting via JavaScript-based window→tab→session traversal
  • send_key: TTY escape sequences for all special keys (arrows, F1-F12, enter, escape, etc.)
  • resize: Native AppleScript columns/rows adjustment
  • profile: ESC]1337;SetProfile escape sequence (AppleScript property is read-only)
  • badge, mark, clear: TTY escape sequences
  • broadcast, action, reload_config: System Events (graceful degrade without Accessibility)

Kitty (all platforms)

  • Detection: TERM_PROGRAM == "kitty" or KITTY_WINDOW_ID env var
  • Uses kitty remote control protocol (kitten @)
  • Full 17-action coverage including get_text (screen content reading), zoom, and reload_config

Fixes and improvements

Terminal tools

  • Ghostty split resize now computes pixels from terminal grid size (TIOCGWINSZ)
  • Ghostty new_tab uses correct AppleScript syntax (new tab in window 1)
  • Ghostty select_tab uses ordinal tab specifiers (first, second, etc.)
  • Ghostty split resize targets the correct terminal (original, not new pane)
  • Ghostty split now respects the size parameter for pane ratios

A2A

  • Instance discovery is now fully async, eliminating UI stutter when scanning for peers
  • Discovered A2A instances are injected into the system prompt for agent awareness
  • Auto-migration of legacy a2a.api_key to auth.api_key
  • Removed legacy A2A.APIKey field — all code paths now use a2aAPIKey() helper
  • Fixed A2A client tools using legacy field instead of resolved helper

CI/Release

  • Winget publish jobs now check for existing open PRs before submitting (gh pr list --search)
  • Defense-in-depth: both workflow-level (gh pr list) and script-level (GitHub Search API) checks

Other

  • start_command now supports detach parameter for true no-timeout execution
  • Fixed Ctrl+G conflict between reasoning effort cycling and image paste
  • Image paste now uses Ctrl+Shift+V instead of Ctrl+I for cross-platform compatibility

v1.3.72

17 Jun 15:25

Choose a tag to compare

ggcode v1.3.72

Highlights

  • CLI version subcommand and global flags: ggcode version, ggcode --version, and ggcode -v now print the version and exit immediately — no config loading, no TUI. Critical for install scripts and agent automation.
  • CLI help overhaul: Removed hardcoded help text that hid acp, completion, daemon, harness, llm-probe, mcp, version subcommands. All commands now visible via cobra dynamic rendering.
  • MCP install wizard: ggcode mcp install with no args launches an interactive wizard (name, transport, command/URL, env vars, headers).
  • IM config wizard: ggcode im config add with no args launches an interactive wizard (adapter name, platform picker, platform-specific config).
  • Interactive installer: New install.sh and install.ps1 with perUser default (no sudo/admin required), scope selection, and dual-scope detection on Windows.
  • Desktop Windows ARM64: Desktop MSI now builds both amd64 (x64) and arm64, matching CLI coverage.
  • Website redesign: Bold new landing page with full-screen hero, animated gradient text, terminal preview, scroll-reveal features grid, and tabbed install bar.
  • README restructure: Simplified to 91 lines (from 656), all technical details moved to 16 standalone guide docs under docs/guide/.

Fixes and improvements

Install and Update

  • Fixed install.sh and install.ps1 using version number in archive name — GoReleaser omits version from .tar.gz/.zip names, causing 404 downloads.
  • Fixed install.sh hanging after completion when piped via curl | bash — added explicit exit 0.
  • Fixed install scripts launching TUI by calling ggcode version on old builds that lack the subcommand — removed post-install version verification.
  • Added cross-installation detection: FindOtherInstalls(), DetectDualScopeWindows() warn when multiple installations coexist.
  • Added privilege-aware update: auto-elevate via UAC on Windows when target directory is not writable.
  • Added write permission check before downloading update binary.

winget

  • winget perUser migration: perUser MSI uses different UpgradeCode from perMachine, winget manages scope migration.
  • Added explicit scope=user override to winget publish URLs via pipe-delimited format.
  • Desktop winget publish now includes arm64 URL alongside x64.

CLI

  • Fixed FlagErrorFunc silently swallowing unknown flags — unknown flags now properly error.
  • Fixed fmt.Fprintln with redundant \n in wizard prompts.
  • Fixed --version/-v using fmt.Println instead of cmd.OutOrStdout() — now respects pipe redirection.
  • Fixed splitCommand in MCP wizard using strings.Fields() — rewrote with quote-aware parser.

Windows Packaging

  • perUser MSI (CLI + Desktop) uses different UpgradeCode from perMachine to prevent cross-scope major upgrade failure.
  • Desktop perUser WXS: removed unreliable <Icon> element, added RemoveFolder for vendor dir cleanup.
  • npm Windows wrapper: copyFileSync instead of batch-in-exe for binary copy; version check in findSystemBinary.

Code Review (Round 2)

  • Fixed npm requestedVersion === "latest" unconditionally reusing any system binary — stale binary reuse bug.

Website / Deployment

  • Fixed Railway deployment: orphan site branch now places files under docs/site/ to match Railway's Root Directory setting.
  • Fixed i18n strings with HTML tags rendered as literal text — detection changed from \n to < check.
  • Added scripts/install/** to site-release workflow trigger paths.
  • Added railway.json generation in orphan branch for DOCKERFILE builder override.

Upgrade notes

No breaking changes. All install channels now default to non-privileged (perUser) installation. Users with existing perMachine MSI on Windows will be prompted to uninstall when switching to perUser via winget.

Compare

v1.3.71...v1.3.72

v1.3.71

16 Jun 18:34

Choose a tag to compare

ggcode v1.3.71

Highlights

  • Mobile session title display: Session titles from host now correctly appear in the mobile app — connect screen, chat header, and session switcher. Previously all sessions showed fallback names (workspace + date) instead of real titles.
  • Mobile session switch rendering: Switching between active sessions now instantly loads cached messages (incrementally updated by background connections) and requests only incremental replay from host. No more blank bubbles or missing messages.
  • Mobile connection status: LIVE badge on connect screen now reflects real-time session readiness instead of stale stored flags. Stale connections older than 6 hours are auto-cleaned on startup.
  • App Store What's New fix: Release pipeline now sets What's New for all 16 supported locales and aborts submission if verification fails, instead of silently continuing with missing metadata.
  • Desktop session title in tunnel: Desktop Wails app now includes session title in tunnel SessionInfo events sent to mobile.

Fixes and improvements

  • Fixed desktop pushTunnelSessionInfo and SetSessionInfo missing the Title field — host session title now reaches mobile on every connection.
  • Fixed mobile _flushDirtyState unconditionally overwriting non-empty session titles with fallback (workspace · date).
  • Fixed mobile attachSessionToActiveWorkspace reassigning workspaceKey for sessions that already had one, causing cross-workspace title contamination.
  • Fixed mobile captureLiveProjection writing stale sessionInfoProvider title from the previous session into the new session's cache.
  • Fixed mobile connect screen using stored alive flag for LIVE badge — now uses real-time sessionReady state.
  • Fixed mobile adoptService ignoring background-cached messages when switching sessions, causing empty/incorrect rendering.
  • Added cleanupStale() to ConnectionStore.load() — auto-removes connections older than 6 hours.
  • Added cleanupOldSessions() to workspace cache init — deletes session data older than 7 days.
  • Added immediate connection removal on permanent room failure (room not found).
  • Added per-locale What's New setting with post-set verification in iOS Fastfile.
  • Added reactive connection list updates in connect screen via ref.listen.

Upgrade notes

No breaking changes. Mobile users will see improved session titles and smoother session switching after updating. Desktop users should restart the app to ensure session titles are sent to mobile.

Compare

v1.3.70...v1.3.71