Skip to content

fix(tui): resolve streaming freeze from GC pressure and event flooding#1

Closed
coleleavitt wants to merge 94 commits intodevfrom
fix/tui-freeze-gc-pressure
Closed

fix(tui): resolve streaming freeze from GC pressure and event flooding#1
coleleavitt wants to merge 94 commits intodevfrom
fix/tui-freeze-gc-pressure

Conversation

@coleleavitt
Copy link
Owner

@coleleavitt coleleavitt commented Feb 27, 2026

Summary

  • Batch ALL high-frequency streaming events (delta, status, part, message, todo, diff) into a unified 100ms flush window in sync.tsx — previously only delta events were debounced while 8 other event types triggered immediate store mutations and re-renders
  • Increase SDK event batch window from 16ms to 50ms in sdk.tsx to further reduce render frequency during streaming
  • Fix stream termination bug in processor.ts where for await (stream.fullStream) never exited on finish event (caused 0% CPU hangs)
  • Add error handling for fire-and-forget effect Promises in db.ts (prevented silent crash propagation)
  • Add missing timeout to client.listTools() in mcp/index.ts (could hang indefinitely on unresponsive MCP servers)

Root Cause

During LLM streaming, each token emits 4-7 events. Only message.part.delta was debounced — the other 8 event types (session.status, message.part.updated, message.updated, todo.updated, session.diff, etc.) all called setStore() immediately, triggering full markdown re-parse per render. This generated O(n) garbage per render where n = total accumulated text length, which triggered Bun's JSC garbage collector. The GC's vmDeallocatePhysicalPages() calls madvise(MADV_DONTDUMP) which requires kernel mmap_write_lock — under memory pressure the kernel returns EAGAIN, and WebKit's bmalloc SYSCALL macro retries in a zero-delay infinite loop, causing 100% CPU and TUI freeze.

Files Changed

File Change
src/cli/cmd/tui/context/sync.tsx Unified batch flush for ALL streaming events (100ms window)
src/cli/cmd/tui/context/sdk.tsx Increase event batch window 16ms → 50ms
src/session/processor.ts Fix for-await stream termination on finish event
src/storage/db.ts Handle fire-and-forget effect Promise rejections
src/mcp/index.ts Add withTimeout() to client.listTools()

Testing

  • All 5 files pass LSP diagnostics (zero errors)
  • Full turbo typecheck passes across all 18 packages
  • Full turbo build succeeds

Summary by cubic

Fix TUI streaming freezes by batching high-frequency events and hardening stream handling. This reduces render churn and GC pressure, improving stability during long streams.

  • Bug Fixes

    • Ensure processor stream exits on finish.
    • Add a timeout to MCP client.listTools() to prevent hangs.
    • Catch rejections from fire-and-forget effect Promises.
  • Refactors

    • Batch all streaming events (delta, status, part, message, todo, diff) into a unified 100ms flush window.
    • Increase the SDK event batch window from 16ms to 50ms to lower render frequency.

Written for commit d9a81df. Summary will update on new commits.

R44VC0RP and others added 30 commits February 23, 2026 16:51
…o#14079)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
nexxeln and others added 15 commits February 26, 2026 18:35
Co-authored-by: adamelmore <2363879+adamdottv@users.noreply.github.com>
Co-authored-by: David Hill <iamdavidhill@gmail.com>
Co-authored-by: David Hill <iamdavidhill@gmail.com>
Batch ALL high-frequency streaming events (delta, status, part, message,
todo, diff) into a unified 100ms flush window to reduce store mutations
and GC pressure. Previously only delta events were debounced while 8
other event types triggered immediate renders, causing full markdown
re-parse per token and triggering Bun's JSC GC madvise spin loop.

- sync.tsx: unified batch flush for all streaming events
- sdk.tsx: increase event batch window from 16ms to 50ms
- processor.ts: fix stream termination (for-await never exited on finish)
- db.ts: handle fire-and-forget effect Promise rejections
- mcp/index.ts: add timeout to client.listTools() calls
@kusari-inspector
Copy link

⚠️ Workspace Mapping Required

Hello! We noticed that your GitHub organization is not yet mapped to a Kusari workspace. Kusari Inspector now requires installations to be associated with a Kusari workspace.

⚠️ NOTE: Only the admin who installed the Kusari GitHub App can complete these steps. If the admin is unable to complete these steps, please contact support@kusari.dev

To complete the setup:

  1. Visit https://console.us.kusari.cloud/auth/github and log in via github
  2. If you have only one workspace, it will be automatically selected for you
  3. Once the mapping is complete, return here and create a new comment with: @kusari-inspector re-run

This will trigger the analysis to run again.

For more information, or if you need help, visit https://github.com/kusaridev/community/discussions

@github-actions
Copy link

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions
Copy link

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

Important

Review skipped

Too many files!

This PR contains 274 files, which is 124 over the limit of 150.

📥 Commits

Reviewing files that changed from the base of the PR and between 8f2d8dd and d9a81df.

⛔ Files ignored due to path filters (26)
  • bun.lock is excluded by !**/*.lock
  • packages/desktop/src-tauri/Cargo.lock is excluded by !**/*.lock
  • packages/sdk/js/src/v2/gen/sdk.gen.ts is excluded by !**/gen/**
  • packages/sdk/js/src/v2/gen/types.gen.ts is excluded by !**/gen/**
  • packages/storybook/debug-storybook.log is excluded by !**/*.log
  • packages/ui/src/assets/icons/provider/302ai.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/berget.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/cloudferro-sherlock.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/firmware.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/gitlab.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/jiekou.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/kilo.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/kuae-cloud-coding-plan.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/meganova.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/minimax-cn-coding-plan.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/minimax-coding-plan.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/moark.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/nova.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/novita-ai.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/privatemode-ai.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/qihang-ai.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/qiniu-ai.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/stackit.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/stepfun.svg is excluded by !**/*.svg
  • packages/ui/src/assets/icons/provider/vivgrid.svg is excluded by !**/*.svg
  • packages/ui/src/components/provider-icons/sprite.svg is excluded by !**/*.svg
📒 Files selected for processing (274)
  • .github/actions/setup-bun/action.yml
  • .github/workflows/beta.yml
  • .github/workflows/compliance-close.yml
  • .github/workflows/docs-locale-sync.yml
  • .github/workflows/pr-standards.yml
  • .github/workflows/test.yml
  • .github/workflows/vouch-check-issue.yml
  • .github/workflows/vouch-check-pr.yml
  • .github/workflows/vouch-manage-by-issue.yml
  • .opencode/agent/translator.md
  • .opencode/glossary/README.md
  • .opencode/glossary/ar.md
  • .opencode/glossary/br.md
  • .opencode/glossary/bs.md
  • .opencode/glossary/da.md
  • .opencode/glossary/de.md
  • .opencode/glossary/es.md
  • .opencode/glossary/fr.md
  • .opencode/glossary/ja.md
  • .opencode/glossary/ko.md
  • .opencode/glossary/no.md
  • .opencode/glossary/pl.md
  • .opencode/glossary/ru.md
  • .opencode/glossary/th.md
  • .opencode/glossary/zh-cn.md
  • .opencode/glossary/zh-tw.md
  • infra/console.ts
  • nix/hashes.json
  • package.json
  • packages/app/e2e/projects/projects-switch.spec.ts
  • packages/app/e2e/session/session-composer-dock.spec.ts
  • packages/app/e2e/utils.ts
  • packages/app/package.json
  • packages/app/playwright.config.ts
  • packages/app/src/components/dialog-select-model-unpaid.tsx
  • packages/app/src/components/dialog-select-provider.tsx
  • packages/app/src/components/file-tree.tsx
  • packages/app/src/components/prompt-input.tsx
  • packages/app/src/components/session/session-header.tsx
  • packages/app/src/components/session/session-sortable-tab.tsx
  • packages/app/src/components/settings-providers.tsx
  • packages/app/src/context/file/path.test.ts
  • packages/app/src/context/file/path.ts
  • packages/app/src/context/global-sdk.tsx
  • packages/app/src/context/global-sync.tsx
  • packages/app/src/context/global-sync/bootstrap.ts
  • packages/app/src/context/permission.tsx
  • packages/app/src/hooks/use-providers.ts
  • packages/app/src/i18n/ar.ts
  • packages/app/src/i18n/br.ts
  • packages/app/src/i18n/bs.ts
  • packages/app/src/i18n/da.ts
  • packages/app/src/i18n/de.ts
  • packages/app/src/i18n/en.ts
  • packages/app/src/i18n/es.ts
  • packages/app/src/i18n/fr.ts
  • packages/app/src/i18n/ja.ts
  • packages/app/src/i18n/ko.ts
  • packages/app/src/i18n/no.ts
  • packages/app/src/i18n/pl.ts
  • packages/app/src/i18n/ru.ts
  • packages/app/src/i18n/th.ts
  • packages/app/src/i18n/zh.ts
  • packages/app/src/i18n/zht.ts
  • packages/app/src/pages/directory-layout.tsx
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/helpers.test.ts
  • packages/app/src/pages/layout/helpers.ts
  • packages/app/src/pages/layout/sidebar-project.tsx
  • packages/app/src/pages/session.tsx
  • packages/app/src/pages/session/composer/session-composer-state.test.ts
  • packages/app/src/pages/session/composer/session-composer-state.ts
  • packages/app/src/pages/session/composer/session-request-tree.ts
  • packages/app/src/pages/session/file-tabs.tsx
  • packages/app/src/pages/session/helpers.test.ts
  • packages/app/src/pages/session/helpers.ts
  • packages/app/src/pages/session/message-timeline.tsx
  • packages/app/src/pages/session/review-tab.tsx
  • packages/app/src/pages/session/session-side-panel.tsx
  • packages/app/src/pages/session/use-session-hash-scroll.ts
  • packages/app/src/utils/server-errors.test.ts
  • packages/app/src/utils/server-errors.ts
  • packages/console/app/package.json
  • packages/console/app/src/i18n/ar.ts
  • packages/console/app/src/i18n/br.ts
  • packages/console/app/src/i18n/da.ts
  • packages/console/app/src/i18n/de.ts
  • packages/console/app/src/i18n/en.ts
  • packages/console/app/src/i18n/es.ts
  • packages/console/app/src/i18n/fr.ts
  • packages/console/app/src/i18n/it.ts
  • packages/console/app/src/i18n/ja.ts
  • packages/console/app/src/i18n/ko.ts
  • packages/console/app/src/i18n/no.ts
  • packages/console/app/src/i18n/pl.ts
  • packages/console/app/src/i18n/ru.ts
  • packages/console/app/src/i18n/th.ts
  • packages/console/app/src/i18n/tr.ts
  • packages/console/app/src/i18n/zh.ts
  • packages/console/app/src/i18n/zht.ts
  • packages/console/app/src/routes/black.css
  • packages/console/app/src/routes/black/index.tsx
  • packages/console/app/src/routes/black/subscribe/[plan].tsx
  • packages/console/app/src/routes/stripe/webhook.ts
  • packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx
  • packages/console/app/src/routes/workspace/[id]/billing/index.tsx
  • packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css
  • packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx
  • packages/console/app/src/routes/workspace/[id]/graph-section.tsx
  • packages/console/app/src/routes/workspace/[id]/usage-section.tsx
  • packages/console/app/src/routes/workspace/common.tsx
  • packages/console/app/src/routes/zen/go/v1/chat/completions.ts
  • packages/console/app/src/routes/zen/go/v1/messages.ts
  • packages/console/app/src/routes/zen/util/handler.ts
  • packages/console/app/src/routes/zen/v1/models.ts
  • packages/console/core/migrations/20260224043338_nifty_starjammers/migration.sql
  • packages/console/core/migrations/20260224043338_nifty_starjammers/snapshot.json
  • packages/console/core/package.json
  • packages/console/core/script/black-select-workspaces.ts
  • packages/console/core/script/lookup-user.ts
  • packages/console/core/src/billing.ts
  • packages/console/core/src/black.ts
  • packages/console/core/src/identifier.ts
  • packages/console/core/src/lite.ts
  • packages/console/core/src/schema/billing.sql.ts
  • packages/console/core/src/subscription.ts
  • packages/console/core/src/util/date.test.ts
  • packages/console/core/src/util/date.ts
  • packages/console/core/test/date.test.ts
  • packages/console/core/test/subscription.test.ts
  • packages/console/function/package.json
  • packages/console/function/src/log-processor.ts
  • packages/console/mail/package.json
  • packages/desktop/README.md
  • packages/desktop/package.json
  • packages/desktop/src-tauri/Cargo.toml
  • packages/desktop/src-tauri/src/cli.rs
  • packages/desktop/src-tauri/src/lib.rs
  • packages/desktop/src-tauri/src/os/mod.rs
  • packages/desktop/src-tauri/src/os/windows.rs
  • packages/desktop/src/bindings.ts
  • packages/desktop/src/index.tsx
  • packages/enterprise/package.json
  • packages/extensions/zed/extension.toml
  • packages/function/package.json
  • packages/opencode/BUN_SHELL_MIGRATION_PLAN.md
  • packages/opencode/package.json
  • packages/opencode/script/schema.ts
  • packages/opencode/src/acp/agent.ts
  • packages/opencode/src/bun/index.ts
  • packages/opencode/src/bun/registry.ts
  • packages/opencode/src/cli/cmd/auth.ts
  • packages/opencode/src/cli/cmd/session.ts
  • packages/opencode/src/cli/cmd/tui/app.tsx
  • packages/opencode/src/cli/cmd/tui/attach.ts
  • packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx
  • packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
  • packages/opencode/src/cli/cmd/tui/component/tips.tsx
  • packages/opencode/src/cli/cmd/tui/context/keybind.tsx
  • packages/opencode/src/cli/cmd/tui/context/sdk.tsx
  • packages/opencode/src/cli/cmd/tui/context/sync.tsx
  • packages/opencode/src/cli/cmd/tui/context/theme.tsx
  • packages/opencode/src/cli/cmd/tui/context/tui-config.tsx
  • packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
  • packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
  • packages/opencode/src/cli/cmd/tui/thread.ts
  • packages/opencode/src/cli/cmd/tui/util/clipboard.ts
  • packages/opencode/src/cli/cmd/tui/util/editor.ts
  • packages/opencode/src/cli/cmd/workspace-serve.ts
  • packages/opencode/src/config/config.ts
  • packages/opencode/src/config/markdown.ts
  • packages/opencode/src/config/migrate-tui-config.ts
  • packages/opencode/src/config/paths.ts
  • packages/opencode/src/config/tui-schema.ts
  • packages/opencode/src/config/tui.ts
  • packages/opencode/src/file/ignore.ts
  • packages/opencode/src/file/ripgrep.ts
  • packages/opencode/src/file/time.ts
  • packages/opencode/src/flag/flag.ts
  • packages/opencode/src/format/formatter.ts
  • packages/opencode/src/format/index.ts
  • packages/opencode/src/index.ts
  • packages/opencode/src/lsp/server.ts
  • packages/opencode/src/mcp/index.ts
  • packages/opencode/src/project/project.ts
  • packages/opencode/src/pty/index.ts
  • packages/opencode/src/server/routes/session.ts
  • packages/opencode/src/session/index.ts
  • packages/opencode/src/session/processor.ts
  • packages/opencode/src/snapshot/index.ts
  • packages/opencode/src/storage/db.ts
  • packages/opencode/src/tool/grep.ts
  • packages/opencode/src/tool/plan.ts
  • packages/opencode/src/tool/registry.ts
  • packages/opencode/src/util/git.ts
  • packages/opencode/src/util/process.ts
  • packages/opencode/test/acp/event-subscription.test.ts
  • packages/opencode/test/config/config.test.ts
  • packages/opencode/test/config/markdown.test.ts
  • packages/opencode/test/config/tui.test.ts
  • packages/opencode/test/ide/ide.test.ts
  • packages/opencode/test/preload.ts
  • packages/opencode/test/skill/discovery.test.ts
  • packages/opencode/test/snapshot/snapshot.test.ts
  • packages/opencode/test/tool/bash.test.ts
  • packages/opencode/test/tool/external-directory.test.ts
  • packages/opencode/test/tool/write.test.ts
  • packages/opencode/test/util/glob.test.ts
  • packages/opencode/test/util/process.test.ts
  • packages/plugin/package.json
  • packages/plugin/script/publish.ts
  • packages/sdk/js/package.json
  • packages/sdk/js/script/build.ts
  • packages/sdk/js/script/publish.ts
  • packages/sdk/openapi.json
  • packages/slack/package.json
  • packages/storybook/.gitignore
  • packages/storybook/.storybook/main.ts
  • packages/storybook/.storybook/manager.ts
  • packages/storybook/.storybook/preview.tsx
  • packages/storybook/.storybook/theme-tool.ts
  • packages/storybook/package.json
  • packages/storybook/tsconfig.json
  • packages/ui/package.json
  • packages/ui/src/components/accordion.stories.tsx
  • packages/ui/src/components/app-icon.stories.tsx
  • packages/ui/src/components/avatar.stories.tsx
  • packages/ui/src/components/basic-tool.stories.tsx
  • packages/ui/src/components/button.stories.tsx
  • packages/ui/src/components/card.stories.tsx
  • packages/ui/src/components/checkbox.stories.tsx
  • packages/ui/src/components/code.stories.tsx
  • packages/ui/src/components/collapsible.stories.tsx
  • packages/ui/src/components/context-menu.stories.tsx
  • packages/ui/src/components/dialog.stories.tsx
  • packages/ui/src/components/diff-changes.stories.tsx
  • packages/ui/src/components/diff-ssr.stories.tsx
  • packages/ui/src/components/diff.stories.tsx
  • packages/ui/src/components/dock-prompt.stories.tsx
  • packages/ui/src/components/dropdown-menu.stories.tsx
  • packages/ui/src/components/favicon.stories.tsx
  • packages/ui/src/components/file-icon.stories.tsx
  • packages/ui/src/components/font.stories.tsx
  • packages/ui/src/components/hover-card.stories.tsx
  • packages/ui/src/components/icon-button.stories.tsx
  • packages/ui/src/components/icon.stories.tsx
  • packages/ui/src/components/image-preview.stories.tsx
  • packages/ui/src/components/inline-input.stories.tsx
  • packages/ui/src/components/keybind.stories.tsx
  • packages/ui/src/components/line-comment.stories.tsx
  • packages/ui/src/components/list.stories.tsx
  • packages/ui/src/components/logo.stories.tsx
  • packages/ui/src/components/markdown.stories.tsx
  • packages/ui/src/components/message-nav.stories.tsx
  • packages/ui/src/components/message-part.css
  • packages/ui/src/components/message-part.stories.tsx
  • packages/ui/src/components/message-part.tsx
  • packages/ui/src/components/popover.stories.tsx
  • packages/ui/src/components/progress-circle.stories.tsx
  • packages/ui/src/components/progress.stories.tsx
  • packages/ui/src/components/provider-icon.stories.tsx
  • packages/ui/src/components/provider-icons/types.ts
  • packages/ui/src/components/radio-group.stories.tsx
  • packages/ui/src/components/resize-handle.stories.tsx
  • packages/ui/src/components/select.stories.tsx
  • packages/ui/src/components/session-review.css
  • packages/ui/src/components/session-review.stories.tsx
  • packages/ui/src/components/session-turn.stories.tsx
  • packages/ui/src/components/spinner.stories.tsx
  • packages/ui/src/components/sticky-accordion-header.stories.tsx
  • packages/ui/src/components/switch.stories.tsx
  • packages/ui/src/components/tabs.css
  • packages/ui/src/components/tabs.stories.tsx
  • packages/ui/src/components/tabs.tsx

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/tui-freeze-gc-pressure

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-free-for-open-source-projects

Review Summary by Qodo

Refactor TUI config, add Go subscription support, implement cross-platform process utility, and fix stream termination

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation

Grey Divider

Walkthroughs

Description
  **Major refactoring and feature additions across multiple packages:**
• **TUI Configuration Separation**: Extracted TUI-specific settings (theme, keybinds, tui)
  from main config schema into dedicated tui.json files with automatic migration from legacy
  opencode.json format
• **Cross-Platform Process Utility**: Introduced new Process utility for consistent process
  spawning across Bun and Node.js, replacing scattered Bun.spawn() calls throughout codebase (LSP
  server, ripgrep, git, clipboard, bun registry)
• **Go Subscription Plan Support**: Added comprehensive "lite" subscription tier alongside existing
  "black" plans with usage tracking, billing validation, and Stripe webhook integration
• **Stream Termination Fix**: Fixed session processor stream hang where for await loop never
  exited on finish event, preventing proper cleanup
• **Bash Output Deduplication**: Implemented snapshot deduplication and synthetic pending state
  handling in ACP agent to prevent duplicate tool updates
• **Windows Path Compatibility**: Fixed cross-platform path handling for Windows backslashes, UNC
  paths, and symlink support with git config flags
• **Comprehensive Test Coverage**: Added 510+ lines of TUI config tests, subscription analysis
  tests, date utility tests, permission tests, and process utility tests
• **i18n Updates**: Added 30+ new translation keys across 15+ languages for Black plan pause
  messages and Go subscription UI
• **Billing Schema Extension**: Extended database schema with LiteTable for Go plan usage tracking
  and subscription management
• **Permission Terminology Fixes**: Corrected permission-related terminology across 20+ i18n files
  from "edits" to "permissions"
Diagram
flowchart LR
  A["Config System"] -->|"Extract TUI keys"| B["TUI Config<br/>tui.json"]
  A -->|"Migrate legacy"| C["Migration Utility"]
  C -->|"Create"| B
  
  D["Process Spawning"] -->|"Unify"| E["Process Utility<br/>Node.js child_process"]
  E -->|"Replace"| F["Bun.spawn<br/>calls"]
  
  G["Subscription"] -->|"Add tier"| H["Go Plan<br/>lite"]
  H -->|"Track usage"| I["LiteTable<br/>DB Schema"]
  H -->|"Webhook"| J["Stripe Events"]
  
  K["Session Processor"] -->|"Fix loop"| L["Stream Termination<br/>finish event"]
  
  M["ACP Agent"] -->|"Deduplicate"| N["Bash Output<br/>Snapshots"]
  
  O["Path Helper"] -->|"Support"| P["Windows Paths<br/>UNC + Symlinks"]
Loading

Grey Divider

File Changes

1. packages/opencode/test/config/tui.test.ts 🧪 Tests +510/-0

Add extensive TUI configuration test coverage

• Added comprehensive test suite for TUI configuration loading with 510 lines of tests
• Tests cover configuration precedence (global, project, local, managed, environment variables)
• Tests validate configuration migration from legacy opencode.json to new tui.json format
• Tests verify keybind merging, file/env substitutions, and graceful fallback behavior

packages/opencode/test/config/tui.test.ts


2. packages/console/app/src/routes/stripe/webhook.ts ✨ Enhancement +73/-289

Refactor Stripe webhook to support lite subscriptions

• Refactored webhook handler to support new "lite" subscription tier alongside existing "black"
 subscriptions
• Replaced checkout.session.completed handler with customer.subscription.created event for lite
 subscriptions
• Updated subscription cancellation logic to route to tier-specific unsubscribe methods
 (unsubscribeLite, unsubscribeBlack)
• Simplified payment enrichment to include product type identification

packages/console/app/src/routes/stripe/webhook.ts


3. packages/opencode/src/config/config.ts Refactoring +56/-148

Separate TUI configuration from main config schema

• Extracted configuration path resolution logic to new ConfigPaths module for reusability
• Removed TUI-specific config fields (theme, keybinds, tui) from main Config.Info schema
• Added deprecation warning when TUI keys are found in opencode.json files
• Improved plugin resolution with fallback to createRequire when import.meta.resolve fails
• Fixed Windows path normalization in config file discovery

packages/opencode/src/config/config.ts


View more (168)
4. packages/console/app/src/routes/zen/util/handler.ts ✨ Enhancement +203/-59

Add lite subscription billing validation and usage tracking

• Added support for "lite" subscription tier validation alongside "black" subscriptions
• Implemented weekly, monthly, and rolling usage limit checks for lite subscriptions
• Refactored billing source validation to handle lite tier with separate usage tracking
• Updated database queries to include LiteTable joins and usage update logic
• Renamed FREE_WORKSPACES to ADMIN_WORKSPACES for clarity

packages/console/app/src/routes/zen/util/handler.ts


5. packages/app/e2e/session/session-composer-dock.spec.ts 🧪 Tests +246/-52

Refactor permission tests to use HTTP mocking

• Refactored permission testing to use mock HTTP routes instead of SDK seed functions
• Added withMockPermission helper to intercept and mock permission API endpoints
• Added clearPermissionDock helper to handle multiple permission dock interactions
• Added new tests for child session permission and question request blocking behavior
• Improved session cleanup with try/finally blocks to ensure child sessions are deleted

packages/app/e2e/session/session-composer-dock.spec.ts


6. packages/opencode/test/snapshot/snapshot.test.ts 🐞 Bug fix +47/-41

Fix snapshot tests for Windows path compatibility

• Added cross-platform path normalization helper fwd() to handle Windows backslash conversion
• Replaced shell-based symlink creation (ln -s) with fs.symlink() for Windows compatibility
• Updated all file path assertions to use normalized paths for consistent cross-platform testing
• Fixed git config path handling to use forward slashes

packages/opencode/test/snapshot/snapshot.test.ts


7. packages/sdk/js/src/v2/gen/types.gen.ts ✨ Enhancement +40/-409

Remove TUI config types and add message deletion types

• Removed KeybindsConfig type definition (388 lines) from SDK types
• Removed theme, keybinds, and tui fields from Config type
• Removed TUI-specific configuration object with scroll_speed, scroll_acceleration, and
 diff_style properties
• Added new SessionDeleteMessageData and related types for message deletion API endpoint

packages/sdk/js/src/v2/gen/types.gen.ts


8. packages/opencode/test/acp/event-subscription.test.ts 🧪 Tests +247/-2

Add ACP tool event snapshot and pending state tests

• Added helper functions for tool event creation and state checking (toolEvent,
 isToolCallUpdate, inProgressText)
• Added three new tests for bash output snapshot deduplication and synthetic pending state handling
• Added test for clearing bash snapshot marker on pending state transitions
• Extended createFakeAgent to track sessionUpdates for assertion validation

packages/opencode/test/acp/event-subscription.test.ts


9. packages/opencode/src/acp/agent.ts ✨ Enhancement +94/-51

Add bash output snapshot deduplication and synthetic pending

• Added bashSnapshots map and toolStarts set to track tool execution state and prevent duplicate
 updates
• Implemented bashOutput() helper to extract output metadata from bash tool states
• Implemented toolStart() helper to emit synthetic pending state before first running update
• Added deduplication logic to skip identical bash output snapshots using hash comparison
• Updated tool state handlers to clear snapshot markers on pending/completed/error transitions

packages/opencode/src/acp/agent.ts


10. packages/app/src/context/file/path.test.ts 🐞 Bug fix +2/-2

Fix Windows path normalization test expectations

• Updated Windows path normalization test expectations to preserve backslashes instead of converting
 to forward slashes
• Changed two test assertions to expect src\app.ts format instead of src/app.ts for Windows
 paths

packages/app/src/context/file/path.test.ts


11. packages/opencode/src/lsp/server.ts ✨ Enhancement +24/-24

Migrate LSP server from Bun spawn to Process utility

• Replaced Bun.spawn() calls with Process.spawn() for cross-platform compatibility
• Changed readableStreamToText() import to text() from node:stream/consumers
• Added null check for proc.stdout before consuming stream output
• Refactored spawn command syntax from object form to array form

packages/opencode/src/lsp/server.ts


12. packages/opencode/src/snapshot/index.ts ✨ Enhancement +20/-13

Add git config flags for long paths and symlinks

• Added three git config settings: core.longpaths=true, core.symlinks=true,
 core.fsmonitor=false
• Applied these configs consistently across all git operations (diff, checkout, read-tree, show,
 add)
• Improves handling of long file paths and symbolic links on Windows

packages/opencode/src/snapshot/index.ts


13. packages/opencode/test/config/config.test.ts 🧪 Tests +38/-18

Update config tests for TUI migration and legacy key removal

• Added test for ignoring legacy theme and tui keys in opencode config
• Updated environment variable substitution tests to use username instead of theme
• Changed test data from theme_* to test-user and secret_* values
• Removed theme assertions from managed settings override test
• Fixed Bun.write() call to use Filesystem.write() for consistency

packages/opencode/test/config/config.test.ts


14. packages/opencode/src/config/paths.ts ✨ Enhancement +174/-0

Add ConfigPaths utility for config file operations

• New utility namespace for config file discovery and parsing
• Implements {env:VAR} and {file:path} token substitution in config text
• Provides JSONC parsing with detailed error reporting
• Handles file inclusion with path resolution and comment detection

packages/opencode/src/config/paths.ts


15. packages/opencode/src/config/migrate-tui-config.ts ✨ Enhancement +155/-0

Add TUI config migration from opencode.json to tui.json

• New migration utility to extract TUI-specific keys from opencode.json files
• Migrates theme, keybinds, and tui keys to dedicated tui.json files
• Creates backups before stripping legacy keys from source files
• Skips migration if tui.json already exists in target directory

packages/opencode/src/config/migrate-tui-config.ts


16. packages/opencode/src/pty/index.ts ✨ Enhancement +19/-85

Simplify PTY subscriber connection tracking

• Removed complex socket tagging and token extraction logic (60+ lines)
• Simplified subscriber tracking to use ws.data as connection key
• Changed subscribers map type from Map<Socket, Subscriber> to Map<unknown, Socket>
• Removed WeakMap-based socket and owner tracking

packages/opencode/src/pty/index.ts


17. packages/console/core/test/subscription.test.ts 🧪 Tests +106/-0

Add subscription monthly usage analysis tests

• New test suite for Subscription.analyzeMonthlyUsage() method
• Tests monthly usage calculation, reset boundaries, and edge cases
• Covers subscription day handling in short months (February)
• Validates usage percent capping and period boundary crossing

packages/console/core/test/subscription.test.ts


18. packages/console/app/src/i18n/th.ts 📝 Documentation +35/-1

Add Thai translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI (loading, time units, subscription info, promo)

packages/console/app/src/i18n/th.ts


19. packages/console/app/src/i18n/ja.ts 📝 Documentation +35/-1

Add Japanese translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/ja.ts


20. packages/console/app/src/i18n/pl.ts 📝 Documentation +35/-1

Add Polish translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/pl.ts


21. packages/opencode/src/config/tui.ts ✨ Enhancement +118/-0

Add TuiConfig namespace for TUI settings management

• New TUI config namespace for loading and merging TUI settings
• Implements config file discovery across project, user, and managed directories
• Triggers TUI config migration before loading
• Normalizes nested tui keys and validates against TuiInfo schema

packages/opencode/src/config/tui.ts


22. packages/console/core/test/date.test.ts 🧪 Tests +76/-0

Add date utility function tests

• New test suite for date utility functions getWeekBounds() and getMonthlyBounds()
• Tests Monday-based week calculation and seven-day window validation
• Tests monthly reset on subscription day with mid-month and short month edge cases
• Validates boundary conditions and day clamping for February

packages/console/core/test/date.test.ts


23. packages/console/app/src/i18n/tr.ts 📝 Documentation +35/-1

Add Turkish translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/tr.ts


24. packages/console/app/src/i18n/zht.ts 📝 Documentation +34/-1

Add Traditional Chinese translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/zht.ts


25. packages/console/app/src/i18n/ar.ts 📝 Documentation +35/-1

Add Arabic translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/ar.ts


26. packages/console/app/src/i18n/ru.ts 📝 Documentation +35/-1

Add Russian translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/ru.ts


27. packages/console/app/src/i18n/it.ts 📝 Documentation +35/-1

Add Italian translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/it.ts


28. packages/console/app/src/i18n/ko.ts 📝 Documentation +35/-1

Add Korean translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/ko.ts


29. packages/console/app/src/i18n/da.ts 📝 Documentation +35/-1

Add Danish translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/da.ts


30. packages/opencode/src/util/process.ts ✨ Enhancement +126/-0

Add Process utility for cross-platform process spawning

• New cross-platform process spawning utility using Node.js child_process
• Implements spawn() for process creation with stdio control and timeout support
• Implements run() for capturing stdout/stderr with error handling
• Provides RunFailedError with detailed command and output information

packages/opencode/src/util/process.ts


31. packages/console/app/src/i18n/no.ts 📝 Documentation +35/-1

Add Norwegian translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/no.ts


32. packages/console/app/src/i18n/fr.ts 📝 Documentation +36/-1

Add French translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/fr.ts


33. packages/console/app/src/i18n/de.ts 📝 Documentation +35/-1

Add German translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/de.ts


34. packages/console/app/src/i18n/es.ts 📝 Documentation +35/-1

Add Spanish translations for Black pause and Go subscription

• Added black.paused translation for Black plan pause message
• Updated workspace.usage.subscription label from generic to Black
• Added new subscription type labels: workspace.usage.lite (Go) and workspace.usage.byok (BYOK)
• Added workspace.cost.liteShort abbreviation
• Added 30+ new translations for Go subscription UI

packages/console/app/src/i18n/es.ts


35. packages/app/e2e/projects/projects-switch.spec.ts 🧪 Tests +11/-11

Refactor project switch test to use SDK session creation

• Imported sessionPath utility function for session URL construction
• Replaced manual prompt interaction with SDK-based session creation
• Added null check for decoded workspace directory
• Changed session navigation to use sessionPath() helper instead of URL regex matching

packages/app/e2e/projects/projects-switch.spec.ts


36. packages/opencode/src/session/processor.ts 🐞 Bug fix +4/-1

Fix stream termination in session processor

• Added finished flag to track stream termination
• Set finished = true when finish event is received
• Added break condition if (needsCompaction || finished) to exit loop on stream completion
• Added logging for stream finish event

packages/opencode/src/session/processor.ts


37. packages/console/app/src/i18n/br.ts 📝 Documentation +35/-1

Brazilian Portuguese i18n updates for Black and Go plans

• Added new i18n key black.paused for Black plan enrollment pause message
• Updated subscription-related labels from generic "subscription" to specific plan names (Black,
 Go, BYOK)
• Added 30+ new i18n keys for OpenCode Go (Lite) subscription feature including time units,
 subscription management, and promotional content

packages/console/app/src/i18n/br.ts


38. packages/console/app/src/i18n/zh.ts 📝 Documentation +34/-1

Simplified Chinese i18n updates for subscription plans

• Added black.paused message for Black plan enrollment pause
• Updated subscription labels to distinguish between Black, Go, and BYOK plans
• Added 30+ new i18n keys for OpenCode Go subscription feature with time units and management UI
 strings

packages/console/app/src/i18n/zh.ts


39. packages/app/src/i18n/ar.ts 📝 Documentation +8/-6

Arabic i18n fixes for permissions and provider descriptions

• Fixed permission-related terminology from "edits" to "permissions" in command and toast messages
• Added new provider taglines for opencode and opencodeGo subscriptions
• Improved translation accuracy for permission request handling

packages/app/src/i18n/ar.ts


40. packages/opencode/script/schema.ts ✨ Enhancement +53/-37

Schema generation script refactored for multiple configs

• Refactored schema generation into reusable generate() function to support multiple schemas
• Added support for generating TuiConfig.Info schema in addition to Config.Info
• Updated script to accept two file arguments for config and TUI schema output

packages/opencode/script/schema.ts


41. packages/console/core/src/billing.ts ✨ Enhancement +79/-3

Billing module extended with Go plan support

• Added LiteTable import for Lite subscription support
• Added generateLiteCheckoutUrl() function to create Stripe checkout sessions for Go plan
• Renamed subscribe() to subscribeBlack() and unsubscribe() to unsubscribeBlack() for
 clarity
• Added unsubscribeLite() function to handle Go plan cancellation

packages/console/core/src/billing.ts


42. packages/console/app/src/i18n/en.ts 📝 Documentation +35/-1

English i18n updates for Black and Go subscription plans

• Added black.paused message for Black plan enrollment pause notification
• Updated subscription cost labels to distinguish between Black, Go, and BYOK plans
• Added 30+ new i18n keys for OpenCode Go subscription including time units, usage tracking, and
 promotional messaging

packages/console/app/src/i18n/en.ts


43. packages/opencode/src/file/ripgrep.ts ✨ Enhancement +27/-30

Ripgrep process handling refactored to use Process utility

• Replaced Bun.spawn() with Process.spawn() for consistent process handling
• Updated stream reading from getReader() pattern to async iteration using for await
• Changed stderr handling from Bun.readableStreamToText() to text() from node:stream/consumers
• Improved error handling with proper exit code checks and stderr capture

packages/opencode/src/file/ripgrep.ts


44. packages/app/src/i18n/th.ts 📝 Documentation +9/-7

Thai i18n fixes for permissions and provider descriptions

• Fixed permission terminology from "edits" to "permissions" throughout command and toast messages
• Added new provider taglines for opencode and opencodeGo
• Updated Copilot provider description to clarify GitHub Copilot integration

packages/app/src/i18n/th.ts


45. packages/app/src/i18n/pl.ts 📝 Documentation +9/-7

Polish i18n fixes for permissions and provider descriptions

• Corrected permission-related terminology from "edycji" (edits) to "uprawnień" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot description to reference GitHub Copilot integration

packages/app/src/i18n/pl.ts


46. packages/app/src/pages/session/composer/session-composer-state.test.ts 🧪 Tests +83/-0

Session request tree helper test suite added

• Added comprehensive test suite for sessionPermissionRequest() and sessionQuestionRequest()
 functions
• Tests cover preference for current session requests, nested child session traversal, and undefined
 handling
• Validates session tree traversal logic for permission and question request resolution

packages/app/src/pages/session/composer/session-composer-state.test.ts


47. packages/opencode/src/util/git.ts ✨ Enhancement +24/-53

Git utility refactored to use Process helper

• Simplified git command execution to use unified Process.run() helper instead of conditional
 Bun.spawn() vs $ logic
• Removed platform-specific ACP client handling, now delegated to Process utility
• Updated return type to use Buffer instead of ReadableStream for stdout/stderr

packages/opencode/src/util/git.ts


48. packages/app/src/i18n/bs.ts 📝 Documentation +9/-7

Bosnian i18n fixes for permissions and provider descriptions

• Fixed permission terminology from "izmjene" (edits) to "dozvole" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot provider description to clarify GitHub Copilot integration

packages/app/src/i18n/bs.ts


49. packages/app/src/pages/layout/helpers.test.ts 🧪 Tests +75/-1

Layout helpers test suite extended with session selection tests

• Added test helper function to create mock Session objects with default values
• Added latestRootSession() test suite validating selection of most recent root session across
 workspaces
• Tests verify filtering of archived and child sessions when finding latest root session

packages/app/src/pages/layout/helpers.test.ts


50. script/beta.ts ✨ Enhancement +62/-13

Beta script enhanced with AI-assisted merge conflict resolution

• Added conflicts() function to detect unmerged files during git merge
• Added cleanup() function to abort merge and reset working tree
• Added fix() function to auto-resolve merge conflicts using opencode AI
• Enhanced merge failure handling with conflict detection and AI-assisted resolution

script/beta.ts


51. packages/app/src/i18n/ja.ts 📝 Documentation +8/-6

Japanese i18n fixes for permissions and provider descriptions

• Updated permission terminology from "編集" (edits) to "権限" (permissions) in commands and toasts
• Added new provider taglines for opencode and opencodeGo subscriptions
• Improved toast message clarity for permission request handling

packages/app/src/i18n/ja.ts


52. packages/app/src/i18n/no.ts 📝 Documentation +9/-7

Norwegian i18n fixes for permissions and provider descriptions

• Fixed permission terminology from "endringer" (edits) to "tillatelser" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot provider description to reference GitHub Copilot

packages/app/src/i18n/no.ts


53. packages/app/src/i18n/da.ts 📝 Documentation +9/-7

Danish i18n fixes for permissions and provider descriptions

• Corrected permission terminology from "ændringer" (edits) to "tilladelser" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot provider description to clarify GitHub Copilot integration

packages/app/src/i18n/da.ts


54. packages/app/src/i18n/ru.ts 📝 Documentation +9/-7

Russian i18n fixes for permissions and provider descriptions

• Updated permission terminology from "изменений" (edits) to "разрешений" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot provider description to reference GitHub Copilot

packages/app/src/i18n/ru.ts


55. packages/app/src/i18n/de.ts 📝 Documentation +8/-6

German i18n fixes for permissions and provider descriptions

• Fixed permission terminology from "Änderungen" (edits) to "Berechtigungen" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Improved toast message clarity for permission request handling

packages/app/src/i18n/de.ts


56. packages/app/src/i18n/fr.ts 📝 Documentation +8/-8

French i18n fixes for permissions and provider descriptions

• Updated permission terminology from "modifications" (edits) to "permissions" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Simplified toast message structure for permission request handling

packages/app/src/i18n/fr.ts


57. packages/console/core/src/subscription.ts ✨ Enhancement +37/-3

Subscription analysis extended with monthly usage tracking

• Changed usagePercent calculation from Math.ceil() to Math.floor() for rolling and weekly
 usage
• Added getMonthlyBounds() import from date utilities
• Added new analyzeMonthlyUsage() function to track monthly subscription usage with reset timing

packages/console/core/src/subscription.ts


58. packages/app/src/i18n/es.ts 📝 Documentation +9/-7

Spanish i18n fixes for permissions and provider descriptions

• Fixed permission terminology from "ediciones" (edits) to "permisos" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot provider description to reference GitHub Copilot

packages/app/src/i18n/es.ts


59. packages/app/src/i18n/ko.ts 📝 Documentation +8/-6

Korean i18n fixes for permissions and provider descriptions

• Updated permission terminology from "편집" (edits) to "권한" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Improved toast message clarity for permission request handling

packages/app/src/i18n/ko.ts


60. packages/app/src/i18n/br.ts 📝 Documentation +8/-6

Brazilian Portuguese i18n fixes for permissions and provider descriptions

• Fixed permission terminology from "edições" (edits) to "permissões" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Improved toast message clarity for permission request handling

packages/app/src/i18n/br.ts


61. packages/opencode/src/cli/cmd/tui/util/clipboard.ts ✨ Enhancement +9/-4

Clipboard utility refactored to use Process helper

• Replaced Bun.spawn() with Process.spawn() for consistent process handling across clipboard
 tools
• Added null checks for proc.stdin before writing to prevent errors
• Updated all clipboard implementations (wl-copy, xclip, xsel, powershell) to use Process utility

packages/opencode/src/cli/cmd/tui/util/clipboard.ts


62. packages/app/src/utils/server-errors.test.ts 🧪 Tests +69/-0

Server error formatting test suite added

• Added test suite for parseReabaleConfigInvalidError() validating config error formatting with
 file paths and issues
• Added test suite for formatServerError() covering config errors, Error objects, strings, and
 fallback cases
• Tests validate proper error message formatting and unknown error handling

packages/app/src/utils/server-errors.test.ts


63. packages/app/src/i18n/zht.ts 📝 Documentation +8/-6

Traditional Chinese i18n fixes for permissions and provider descriptions

• Updated permission terminology from "編輯" (edits) to "權限" (permissions)
• Added new provider taglines for opencode and opencodeGo subscriptions
• Improved toast message clarity for permission request handling

packages/app/src/i18n/zht.ts


64. packages/opencode/test/util/process.test.ts 🧪 Tests +59/-0

Process utility test suite added

• Added comprehensive test suite for Process.run() utility covering stdout/stderr capture, exit
 codes, and error handling
• Tests validate abort signal handling, timeout behavior, and RunFailedError exception throwing
• Includes platform-specific tests for signal handling on non-Windows systems

packages/opencode/test/util/process.test.ts


65. packages/app/src/i18n/en.ts 📝 Documentation +9/-7

English i18n fixes for permissions and provider descriptions

• Updated permission terminology from "edits" to "permissions" in command and toast messages
• Added new provider taglines for opencode and opencodeGo subscriptions
• Updated Copilot provider description to reference GitHub Copilot

packages/app/src/i18n/en.ts


66. packages/app/src/context/file/path.ts 🐞 Bug fix +11/-13

Path helper refactored for cross-platform separator handling

• Refactored path normalization to handle both Unix and Windows separators consistently
• Added support for UNC paths (Windows network paths starting with \\)
• Improved case-insensitive matching for Windows paths while preserving native separators
• Fixed prefix stripping logic to use character comparison instead of string concatenation

packages/app/src/context/file/path.ts


67. packages/ui/src/components/provider-icons/types.ts ✨ Enhancement +20/-0

Provider icons expanded with new AI service providers

• Added 20+ new provider icon names to the iconNames array including vivgrid, stepfun,
 stackit, qiniu-ai, novita-ai, moark, minimax-coding-plan, kuae-cloud-coding-plan,
 kilo, jiekou, gitlab, firmware, cloudferro-sherlock, berget, 302ai
• Maintains alphabetical ordering of provider names

packages/ui/src/components/provider-icons/types.ts


68. packages/opencode/src/bun/index.ts ✨ Enhancement +8/-15

Bun process execution refactored to use Process utility

• Replaced Bun.spawn() with Process.spawn() for consistent process handling
• Updated stream reading from readableStreamToText() to text() from node:stream/consumers
• Fixed exit code reference from result.exitCode to code variable
• Added CI environment check to disable cache in proxied or CI environments

packages/opencode/src/bun/index.ts


69. packages/console/core/src/schema/billing.sql.ts ✨ Enhancement +23/-3

Billing schema extended with Go plan support

• Renamed SubscriptionPlan to BlackPlans for clarity
• Added liteSubscriptionID and lite fields to BillingTable for Go plan support
• Added new LiteTable with usage tracking fields (rollingUsage, weeklyUsage, monthlyUsage)
 and timestamps

packages/console/core/src/schema/billing.sql.ts


70. packages/app/src/i18n/zh.ts 📦 Other +8/-6
• Updated

packages/app/src/i18n/zh.ts


71. .github/actions/setup-bun/action.yml Additional files +16/-1

...

.github/actions/setup-bun/action.yml


72. .github/workflows/beta.yml Additional files +4/-0

...

.github/workflows/beta.yml


73. .github/workflows/compliance-close.yml Additional files +9/-0

...

.github/workflows/compliance-close.yml


74. .github/workflows/docs-locale-sync.yml Additional files +4/-4

...

.github/workflows/docs-locale-sync.yml


75. .github/workflows/pr-standards.yml Additional files +6/-6

...

.github/workflows/pr-standards.yml


76. .github/workflows/test.yml Additional files +10/-2

...

.github/workflows/test.yml


77. .github/workflows/vouch-check-issue.yml Additional files +39/-19

...

.github/workflows/vouch-check-issue.yml


78. .github/workflows/vouch-check-pr.yml Additional files +38/-17

...

.github/workflows/vouch-check-pr.yml


79. .github/workflows/vouch-manage-by-issue.yml Additional files +1/-0

...

.github/workflows/vouch-manage-by-issue.yml


80. .opencode/agent/translator.md Additional files +1/-1

...

.opencode/agent/translator.md


81. .opencode/glossary/README.md Additional files +0/-0

...

.opencode/glossary/README.md


82. .opencode/glossary/ar.md Additional files +0/-0

...

.opencode/glossary/ar.md


83. .opencode/glossary/br.md Additional files +0/-0

...

.opencode/glossary/br.md


84. .opencode/glossary/bs.md Additional files +0/-0

...

.opencode/glossary/bs.md


85. .opencode/glossary/da.md Additional files +0/-0

...

.opencode/glossary/da.md


86. .opencode/glossary/de.md Additional files +0/-0

...

.opencode/glossary/de.md


87. .opencode/glossary/es.md Additional files +0/-0

...

.opencode/glossary/es.md


88. .opencode/glossary/fr.md Additional files +0/-0

...

.opencode/glossary/fr.md


89. .opencode/glossary/ja.md Additional files +0/-0

...

.opencode/glossary/ja.md


90. .opencode/glossary/ko.md Additional files +0/-0

...

.opencode/glossary/ko.md


91. .opencode/glossary/no.md Additional files +0/-0

...

.opencode/glossary/no.md


92. .opencode/glossary/pl.md Additional files +0/-0

...

.opencode/glossary/pl.md


93. .opencode/glossary/ru.md Additional files +0/-0

...

.opencode/glossary/ru.md


94. .opencode/glossary/th.md Additional files +0/-0

...

.opencode/glossary/th.md


95. .opencode/glossary/zh-cn.md Additional files +0/-0

...

.opencode/glossary/zh-cn.md


96. .opencode/glossary/zh-tw.md Additional files +0/-0

...

.opencode/glossary/zh-tw.md


97. infra/console.ts A...

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Feb 27, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (7) 📎 Requirement gaps (0)

Grey Divider


Action required

1. scheduleBatchFlush uses any 📘 Rule violation ✓ Correctness
Description
The new streaming batcher introduces multiple explicit any types (e.g., setStore: any, `store:
any, and draft: any[]`), weakening type safety and enabling incorrect store mutations to compile.
This violates the requirement to avoid any in new/modified TypeScript code.
Code

packages/opencode/src/cli/cmd/tui/context/sync.tsx[44]

+function scheduleBatchFlush(setStore: any, store: any) {
Evidence
PR Compliance ID 8 forbids introducing any; the added batcher function signature and callbacks
explicitly annotate parameters as any in the modified file.

AGENTS.md
packages/opencode/src/cli/cmd/tui/context/sync.tsx[44-45]
packages/opencode/src/cli/cmd/tui/context/sync.tsx[93-95]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New code in the streaming batcher uses explicit `any` types (including in `scheduleBatchFlush` and `produce()` drafts), violating the project rule to avoid `any` and reducing compile-time safety.

## Issue Context
The batcher can be typed without `any` by:
- moving `scheduleBatchFlush` inside `init()` so it can capture typed `store`/`setStore` via inference, and/or
- defining a local `type` for the store shape and using it for `createStore&lt;...&gt;()` and `SetStoreFunction&lt;...&gt;`.
Also remove unnecessary `(m: any)` / `(p: any)` annotations and let inference work.

## Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/context/sync.tsx[44-155]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. loadFile returns any 📘 Rule violation ✓ Correctness
Description
createOpenReviewFile changes loadFile to return any | Promise<void>, introducing any and
erasing the expected contract of the callback. This can mask incorrect return types and breaks the
no-any rule.
Code

packages/app/src/pages/session/helpers.ts[R24-28]

  showAllFiles: () => void
  tabForPath: (path: string) => string
  openTab: (tab: string) => void
-  loadFile: (path: string) => void
+  loadFile: (path: string) => any | Promise<void>
}) => {
Evidence
PR Compliance ID 8 forbids introducing any; the updated loadFile callback signature explicitly
returns any.

AGENTS.md
packages/app/src/pages/session/helpers.ts[23-28]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`loadFile` was broadened to `any | Promise&lt;void&gt;`, which introduces `any` and removes type safety.

## Issue Context
The implementation only needs to know whether the result is async; the correct type is `void | Promise&lt;void&gt;` (or `unknown | Promise&lt;void&gt;` with narrowing), not `any`.

## Fix Focus Areas
- packages/app/src/pages/session/helpers.ts[23-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Diagnostics props use any 📘 Rule violation ✓ Correctness
Description
The newly added Diagnostics component types diagnostics as `Record<string, Record<string,
any>[]>, introducing any` into the TUI route. This prevents compile-time checking of diagnostic
shape used in rendering (e.g., severity, range, message).
Code

packages/opencode/src/cli/cmd/tui/routes/session/index.tsx[2141]

+function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]>; filePath: string }) {
Evidence
PR Compliance ID 8 forbids introducing any; the new Diagnostics function signature explicitly
includes any in the diagnostics type.

AGENTS.md
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx[2141-2146]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Diagnostics` introduces `any` in its `diagnostics` prop type, which weakens type safety in new UI code.

## Issue Context
The component reads `severity`, `range.start.line`, `range.start.character`, and `message`. Define/import a type that includes these fields, or accept `unknown` and narrow before rendering.

## Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx[2141-2157]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (3)
4. parseModel uses body: any 📘 Rule violation ⛨ Security
Description
The new POST handler uses body: any for request parsing, introducing any on external input
handling. This removes type safety where validation/narrowing is expected for untrusted request
bodies.
Code

packages/console/app/src/routes/zen/go/v1/messages.ts[R9-10]

+    parseModel: (url: string, body: any) => body.model,
+    parseIsStream: (url: string, body: any) => !!body.stream,
Evidence
PR Compliance ID 8 forbids introducing any; the new route explicitly types the request body as
any in parsing callbacks.

AGENTS.md
packages/console/app/src/routes/zen/go/v1/messages.ts[8-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new console endpoint parses request bodies using `any`, which violates the no-`any` rule and weakens safety for untrusted inputs.

## Issue Context
Request bodies are external inputs; prefer `unknown` and explicit narrowing (e.g., check for object shape and string/boolean fields) before reading `model`/`stream`.

## Fix Focus Areas
- packages/console/app/src/routes/zen/go/v1/messages.ts[4-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. E2E mocks use any 📘 Rule violation ✓ Correctness
Description
The updated e2e test introduces multiple any-typed Playwright objects (page: any, route: any,
and opts: { child?: any }), reducing test correctness and violating the no-any rule. This can
hide incorrect API usage and make refactors harder.
Code

packages/app/e2e/session/session-composer-dock.spec.ts[R43-75]

+async function clearPermissionDock(page: any, label: RegExp) {
+  const dock = page.locator(permissionDockSelector)
+  for (let i = 0; i < 3; i++) {
+    const count = await dock.count()
+    if (count === 0) return
+    await dock.getByRole("button", { name: label }).click()
+    await page.waitForTimeout(150)
+  }
+}
+
+async function withMockPermission<T>(
+  page: any,
+  request: {
+    id: string
+    sessionID: string
+    permission: string
+    patterns: string[]
+    metadata?: Record<string, unknown>
+    always?: string[]
+  },
+  opts: { child?: any } | undefined,
+  fn: () => Promise<T>,
+) {
+  let pending = [
+    {
+      ...request,
+      always: request.always ?? ["*"],
+      metadata: request.metadata ?? {},
+    },
+  ]
+
+  const list = async (route: any) => {
+    await route.fulfill({
Evidence
PR Compliance ID 8 forbids introducing any; the new helper functions in the test file explicitly
annotate multiple parameters as any.

AGENTS.md
packages/app/e2e/session/session-composer-dock.spec.ts[43-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New e2e helpers type Playwright objects as `any`, violating the no-`any` rule and reducing test type safety.

## Issue Context
Playwright provides types like `Page` and `Route` that can be imported from `@playwright/test` (or the project’s fixture types). Replace `opts.child?: any` with a concrete type matching the mocked session object.

## Fix Focus Areas
- packages/app/e2e/session/session-composer-dock.spec.ts[43-109]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. ACP test casts as any 📘 Rule violation ✓ Correctness
Description
The updated ACP event subscription tests use as any casts when calling agent.newSession(...),
introducing any and bypassing type checks on session creation inputs. This violates the no-any
rule and can let incorrect test setup compile.
Code

packages/opencode/test/acp/event-subscription.test.ts[R501-504]

+        const { agent, controller, sessionUpdates, stop } = createFakeAgent()
+        const cwd = "/tmp/opencode-acp-test"
+        const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId)
+        const input = { command: "echo hello", description: "run command" }
Evidence
PR Compliance ID 8 forbids introducing any; the new tests explicitly cast the new session input
object to any.

AGENTS.md
packages/opencode/test/acp/event-subscription.test.ts[501-504]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The ACP event subscription test suite introduces `as any` casts for session creation, bypassing TypeScript safety.

## Issue Context
Prefer importing the expected input type for `agent.newSession` (or deriving it via `Parameters&lt;typeof agent.newSession&gt;[0]`) and building a valid object without casting.

## Fix Focus Areas
- packages/opencode/test/acp/event-subscription.test.ts[496-541]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

7. let byMessage reassigned 📘 Rule violation ✓ Correctness
Description
The new delta-batching logic uses let variables (byMessage, byPart) that are reassigned during
initialization, which is discouraged by the immutability/control-flow rule. This can be rewritten
with const plus conditional insertion for clearer intent.
Code

packages/opencode/src/cli/cmd/tui/context/sync.tsx[R388-397]

+          let byMessage = pendingDeltas.get(messageID)
+          if (!byMessage) {
+            byMessage = new Map()
+            pendingDeltas.set(messageID, byMessage)
+          }
+          let byPart = byMessage.get(partID)
+          if (!byPart) {
+            byPart = new Map()
+            byMessage.set(partID, byPart)
+          }
Evidence
PR Compliance ID 15 requires preferring const and avoiding reassignment; the new
message.part.delta handler reassigns let bindings while building nested Maps.

AGENTS.md
packages/opencode/src/cli/cmd/tui/context/sync.tsx[386-398]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new delta batching code uses `let` with reassignment for Map initialization, which can be rewritten more immutably and clearly.

## Issue Context
You can keep `const` bindings by computing defaults and only inserting into the maps when missing (e.g., `const byMessage = pendingDeltas.get(messageID) ?? new Map(); if (!pendingDeltas.has(messageID)) pendingDeltas.set(messageID, byMessage);`). Repeat for `byPart`.

## Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/context/sync.tsx[386-400]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Sync batcher is module-scoped 🐞 Bug ⛯ Reliability
Description
The new streaming batcher buffers and timer live at module scope, so they are shared across any
SyncProvider mounts/instances and are not cleaned up on unmount. This is brittle and can lead to
flushing buffered events into the wrong store/setter (or flushing after unmount) if the provider is
ever remounted or duplicated (tests, future refactors, error-boundary resets).
Code

packages/opencode/src/cli/cmd/tui/context/sync.tsx[R32-47]

+// Streaming event batcher: batch ALL high-frequency events during streaming
+// to reduce store mutations and avoid GC pressure from markdown re-parsing.
+// Events are buffered and flushed every BATCH_FLUSH_MS in a single batch() call.
+const BATCH_FLUSH_MS = 100
+const pendingDeltas = new Map<string, Map<string, Map<string, string>>>()
+const pendingStatus = new Map<string, SessionStatus>()
+const pendingMessages = new Map<string, Message>()
+const pendingParts = new Map<string, Part>()
+const pendingTodos = new Map<string, Todo[]>()
+const pendingDiffs = new Map<string, import("@/snapshot").Snapshot.FileDiff[]>()
+let batchTimer: Timer | undefined
+
+function scheduleBatchFlush(setStore: any, store: any) {
+  if (batchTimer) return
+  batchTimer = setTimeout(() => {
+    batchTimer = undefined
Evidence
sync.tsx declares all pending buffers and the timer at module scope, and scheduleBatchFlush relies
on these shared globals. createSimpleContext() calls init() when the provider is mounted, meaning
module-scoped mutable state is not tied to provider lifecycle and would be shared if mounted more
than once.

packages/opencode/src/cli/cmd/tui/context/sync.tsx[32-47]
packages/opencode/src/cli/cmd/tui/context/helper.tsx[3-17]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The streaming batching buffers/timer in `sync.tsx` are currently declared at module scope, making them shared across any `SyncProvider` mounts/instances and not tied to Solid lifecycle. This can cause stale flushes after unmount and cross-instance contamination if the provider is ever remounted or duplicated.

### Issue Context
`createSimpleContext()` runs `init()` on provider mount; module-level mutable state is therefore not reset per mount.

### Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/context/sync.tsx[32-159]
- packages/opencode/src/cli/cmd/tui/context/helper.tsx[3-17]

### Implementation notes
- Move `pending*` maps and `batchTimer` into the `init: () =&gt; { ... }` scope.
- Convert `scheduleBatchFlush` into a closure that captures `store`/`setStore`.
- Add `onCleanup(() =&gt; { if (batchTimer) clearTimeout(batchTimer); pending*.clear(); })`.
- Optionally flush any remaining pending events before cleanup if desired.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. SDK batching delay miscomputed 🐞 Bug ➹ Performance
Description
The SDK event batcher schedules a fixed 50ms timeout when the last flush was <50ms ago, which can
delay the next flush to nearly 100ms after the previous flush. This increases UI latency beyond the
intended 50ms batch window and can enlarge batches unnecessarily.
Code

packages/opencode/src/cli/cmd/tui/context/sdk.tsx[R52-61]

      const elapsed = Date.now() - last

      if (timer) return
-      // If we just flushed recently (within 16ms), batch this with future events
+      // If we just flushed recently (within 50ms), batch this with future events
      // Otherwise, process immediately to avoid latency
-      if (elapsed < 16) {
-        timer = setTimeout(flush, 16)
+      if (elapsed < 50) {
+        timer = setTimeout(flush, 50)
        return
      }
      flush()
Evidence
The code computes elapsed = Date.now() - last but uses setTimeout(flush, 50) rather than the
remaining time (50 - elapsed). If elapsed is close to 50ms, the flush fires ~50ms later,
totaling ~100ms since last.

packages/opencode/src/cli/cmd/tui/context/sdk.tsx[50-62]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The SDK event batcher intends to cap batching at 50ms, but it currently schedules `setTimeout(flush, 50)` regardless of how much time has already elapsed since the last flush. This can cause the effective interval to approach ~100ms.

### Issue Context
`elapsed` is computed but not used to compute the remaining delay.

### Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/context/sdk.tsx[50-62]

### Implementation notes
- Replace `setTimeout(flush, 50)` with something like:
 - `const delay = Math.max(0, 50 - elapsed)`
 - `timer = setTimeout(flush, delay)`
- Consider naming the window constant (e.g., `BATCH_MS = 50`) for clarity.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Copy link

@devloai devloai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary:

  • Batches all high-frequency streaming events (delta, status, part, message, todo, diff) into a 100ms flush window to reduce GC pressure
  • Increases SDK event batch window from 16ms → 50ms
  • Fixes stream termination bug in processor.ts where for await never exited on finish event
  • Adds error handling for fire-and-forget effect Promises in db.ts
  • Adds withTimeout() to client.listTools() in mcp/index.ts

Review Summary:

The core batching approach in sync.tsx is sound and addresses a real GC pressure problem. The processor.ts stream termination fix is correct — finish signals the provider is done and break safely calls return() on the AsyncGenerator. The db.ts effect error handling and MCP timeout additions are clean improvements.

One architectural issue stands out: all pending event Maps and the batchTimer are declared as module-level globals, meaning they are shared across all SyncProvider instances and persist beyond component lifetime. If the provider unmounts while a flush is pending, the timer fires with a stale setStore/store closure. This is a real, reproducible bug in environments with hot-reload or component remounting. This state should live inside init() with an onCleanup guard.

Follow-up suggestions:

  • @devloai fix the module-level global state issue in sync.tsx by moving pending Maps and batchTimer inside init() with proper onCleanup teardown

const pendingDiffs = new Map<string, import("@/snapshot").Snapshot.FileDiff[]>()
let batchTimer: Timer | undefined

function scheduleBatchFlush(setStore: any, store: any) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scheduleBatchFlush function captures setStore and store from the first call only (subsequent calls early-return when batchTimer is already set). This means if a second SyncProvider instance were mounted (e.g. hot-reload, navigate away and back), the timer would keep flushing stale closures.

More critically: all the pending Maps are module-level globals shared across all SyncProvider instances. If the component unmounts while a timer is pending, the flush fires after unmount with a stale setStore/store reference, potentially writing to a dead reactive scope.

Consider moving all the pending state and the timer inside the init function and returning a cleanup that cancels the timer:

// Inside init():
let batchTimer: Timer | undefined
const pendingDeltas = new Map(...)
// ... etc

onCleanup(() => {
  if (batchTimer) clearTimeout(batchTimer)
  batchTimer = undefined
  pendingDeltas.clear()
  // etc.
})

Apply quick fix

actions

Quick Fix: Apply a small focused fix for this specific issue (takes < 1min).

Feedback: Rate this comment to help me improve future code reviews:

  • 👍 Good - Helpful and accurate
  • 👎 Poor - Wrong, unclear, or unhelpful
  • Skip if you don't have any strong opinions either way.

try {
let currentText: MessageV2.TextPart | undefined
let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
let finished = false
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The let finished = false declaration is indented at 4 spaces while the surrounding declarations use 12 spaces (3 levels of nesting: try, while, function body). This appears to be a copy-paste indentation error.

            let currentText: MessageV2.TextPart | undefined
            let reasoningMap: Record<string, MessageV2.ReasoningPart> = {}
            let finished = false
            const stream = await LLM.stream(streamInput)

Apply quick fix

actions

Quick Fix: Apply a small focused fix for this specific issue (takes < 1min).

Feedback: Rate this comment to help me improve future code reviews:

  • 👍 Good - Helpful and accurate
  • 👎 Poor - Wrong, unclear, or unhelpful
  • Skip if you don't have any strong opinions either way.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 issues found across 348 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/app/src/pages/session/helpers.ts">

<violation number="1" location="packages/app/src/pages/session/helpers.ts:34">
P2: Missing `.catch()` on the promise chain — if `loadFile` rejects, this will produce an unhandled promise rejection. Add error handling to be consistent with the PR's stated goal of handling fire-and-forget promise rejections.</violation>
</file>

<file name="packages/app/src/pages/session/file-tabs.tsx">

<violation number="1" location="packages/app/src/pages/session/file-tabs.tsx:377">
P2: `cancelCommenting` bypasses `setCommenting(null)`, skipping the `scheduleComments()` side-effect that clears `draftTop`. Use the existing wrapper to keep behavior consistent.</violation>
</file>

<file name="packages/app/src/pages/layout.tsx">

<violation number="1" location="packages/app/src/pages/layout.tsx:1097">
P2: `navigateToProject` is now `async` but callers (e.g., `openProject`, `closeProject`, the reactive `on()` block, and `chooseProject`) still call it without `await` — creating fire-and-forget promises. Any unexpected throw becomes a silent unhandled rejection, and concurrent calls (e.g., from the deep-link loop via `openProject`) now race non-deterministically. Consider either awaiting/`.catch()`-ing at call sites, or wrapping the entire body in a try/catch to guarantee no rejections escape.</violation>
</file>

<file name="packages/app/src/pages/session/session-side-panel.tsx">

<violation number="1" location="packages/app/src/pages/session/session-side-panel.tsx:226">
P2: Review count badge lost all styling classes — the pill indicator (`rounded-full bg-surface-base`, text/padding/flex classes) was removed, leaving a bare unstyled `<div>`. This looks like an accidental regression from the refactor.</violation>
</file>

<file name="packages/app/src/components/dialog-select-model-unpaid.tsx">

<violation number="1" location="packages/app/src/components/dialog-select-model-unpaid.tsx:100">
P2: Two adjacent `<Show>` blocks share the identical condition `i.id === "opencode"`. Merge them into a single `<Show>` with a fragment, consistent with how the `opencode-go` block is structured just below.</violation>
</file>

<file name="packages/app/src/components/dialog-select-provider.tsx">

<violation number="1" location="packages/app/src/components/dialog-select-provider.tsx:74">
P3: Duplicate `<Show when={i.id === "opencode"}>` — this new block checks the same condition as the existing one a few lines below. Merge them into a single `<Show>` block to avoid redundant condition evaluation and improve readability.</violation>
</file>

<file name="packages/app/src/utils/server-errors.ts">

<violation number="1" location="packages/app/src/utils/server-errors.ts:23">
P2: Typo in exported function name: `parseReabaleConfigInvalidError` should be `parseReadableConfigInvalidError`. Since this is a newly added exported symbol, fixing the name now avoids a breaking rename later.</violation>

<violation number="2" location="packages/app/src/utils/server-errors.ts:30">
P2: Bug: The empty string `""` intended as a blank-line separator is removed by `.filter(Boolean)` (empty string is falsy). The issues will appear directly after the header with no visual break. Consider filtering before inserting the separator.</violation>
</file>

<file name=".github/workflows/compliance-close.yml">

<violation number="1" location=".github/workflows/compliance-close.yml:75">
P3: Empty `catch (e) {}` silently swallows all errors, not just the expected 404. Consider logging the error at debug level so unexpected failures (auth issues, rate limits, network errors) aren't invisible.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

input.loadFile(path)
const maybePromise = input.loadFile(path)
const openTab = () => input.openTab(input.tabForPath(path))
if (maybePromise instanceof Promise) maybePromise.then(openTab)
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Missing .catch() on the promise chain — if loadFile rejects, this will produce an unhandled promise rejection. Add error handling to be consistent with the PR's stated goal of handling fire-and-forget promise rejections.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/pages/session/helpers.ts, line 34:

<comment>Missing `.catch()` on the promise chain — if `loadFile` rejects, this will produce an unhandled promise rejection. Add error handling to be consistent with the PR's stated goal of handling fire-and-forget promise rejections.</comment>

<file context>
@@ -24,13 +24,15 @@ export const createOpenReviewFile = (input: {
-      input.loadFile(path)
+      const maybePromise = input.loadFile(path)
+      const openTab = () => input.openTab(input.tabForPath(path))
+      if (maybePromise instanceof Promise) maybePromise.then(openTab)
+      else openTab()
     })
</file context>
Fix with Cubic

const cancelCommenting = () => {
const p = path()
if (p) file.setSelectedLines(p, null)
setNote("commenting", null)
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: cancelCommenting bypasses setCommenting(null), skipping the scheduleComments() side-effect that clears draftTop. Use the existing wrapper to keep behavior consistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/pages/session/file-tabs.tsx, line 377:

<comment>`cancelCommenting` bypasses `setCommenting(null)`, skipping the `scheduleComments()` side-effect that clears `draftTop`. Use the existing wrapper to keep behavior consistent.</comment>

<file context>
@@ -371,6 +371,12 @@ export function FileTabContent(props: { tab: string }) {
+  const cancelCommenting = () => {
+    const p = path()
+    if (p) file.setSelectedLines(p, null)
+    setNote("commenting", null)
+  }
+
</file context>
Suggested change
setNote("commenting", null)
setCommenting(null)
Fix with Cubic

}

function navigateToProject(directory: string | undefined) {
async function navigateToProject(directory: string | undefined) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: navigateToProject is now async but callers (e.g., openProject, closeProject, the reactive on() block, and chooseProject) still call it without await — creating fire-and-forget promises. Any unexpected throw becomes a silent unhandled rejection, and concurrent calls (e.g., from the deep-link loop via openProject) now race non-deterministically. Consider either awaiting/.catch()-ing at call sites, or wrapping the entire body in a try/catch to guarantee no rejections escape.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/pages/layout.tsx, line 1097:

<comment>`navigateToProject` is now `async` but callers (e.g., `openProject`, `closeProject`, the reactive `on()` block, and `chooseProject`) still call it without `await` — creating fire-and-forget promises. Any unexpected throw becomes a silent unhandled rejection, and concurrent calls (e.g., from the deep-link loop via `openProject`) now race non-deterministically. Consider either awaiting/`.catch()`-ing at call sites, or wrapping the entire body in a try/catch to guarantee no rejections escape.</comment>

<file context>
@@ -1093,14 +1094,51 @@ export default function Layout(props: ParentProps) {
   }
 
-  function navigateToProject(directory: string | undefined) {
+  async function navigateToProject(directory: string | undefined) {
     if (!directory) return
     const root = projectRoot(directory)
</file context>
Fix with Cubic

<div class="flex items-center gap-1.5">
<div>{language.t("session.tab.review")}</div>
<Show when={hasReview()}>
<div>{reviewCount()}</div>
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Review count badge lost all styling classes — the pill indicator (rounded-full bg-surface-base, text/padding/flex classes) was removed, leaving a bare unstyled <div>. This looks like an accidental regression from the refactor.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/pages/session/session-side-panel.tsx, line 226:

<comment>Review count badge lost all styling classes — the pill indicator (`rounded-full bg-surface-base`, text/padding/flex classes) was removed, leaving a bare unstyled `<div>`. This looks like an accidental regression from the refactor.</comment>

<file context>
@@ -202,133 +202,123 @@ export function SessionSidePanel(props: {
+                        <div class="flex items-center gap-1.5">
+                          <div>{language.t("session.tab.review")}</div>
+                          <Show when={hasReview()}>
+                            <div>{reviewCount()}</div>
+                          </Show>
+                        </div>
</file context>
Suggested change
<div>{reviewCount()}</div>
<div class="text-12-medium text-text-strong h-4 px-2 flex flex-col items-center justify-center rounded-full bg-surface-base">
{reviewCount()}
</div>
Fix with Cubic

<div class="w-full flex items-center gap-x-3">
<ProviderIcon data-slot="list-item-extra-icon" id={i.id as IconName} />
<span>{i.name}</span>
<Show when={i.id === "opencode"}>
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Two adjacent <Show> blocks share the identical condition i.id === "opencode". Merge them into a single <Show> with a fragment, consistent with how the opencode-go block is structured just below.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/components/dialog-select-model-unpaid.tsx, line 100:

<comment>Two adjacent `<Show>` blocks share the identical condition `i.id === "opencode"`. Merge them into a single `<Show>` with a fragment, consistent with how the `opencode-go` block is structured just below.</comment>

<file context>
@@ -97,9 +97,20 @@ export const DialogSelectModelUnpaid: Component = () => {
                   <div class="w-full flex items-center gap-x-3">
                     <ProviderIcon data-slot="list-item-extra-icon" id={i.id as IconName} />
                     <span>{i.name}</span>
+                    <Show when={i.id === "opencode"}>
+                      <div class="text-14-regular text-text-weak">{language.t("dialog.provider.opencode.tagline")}</div>
+                    </Show>
</file context>
Fix with Cubic

return o.name === "ConfigInvalidError" && typeof o.data === "object" && o.data !== null
}

export function parseReabaleConfigInvalidError(errorInput: ConfigInvalidError) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Typo in exported function name: parseReabaleConfigInvalidError should be parseReadableConfigInvalidError. Since this is a newly added exported symbol, fixing the name now avoids a breaking rename later.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/utils/server-errors.ts, line 23:

<comment>Typo in exported function name: `parseReabaleConfigInvalidError` should be `parseReadableConfigInvalidError`. Since this is a newly added exported symbol, fixing the name now avoids a breaking rename later.</comment>

<file context>
@@ -0,0 +1,32 @@
+  return o.name === "ConfigInvalidError" && typeof o.data === "object" && o.data !== null
+}
+
+export function parseReabaleConfigInvalidError(errorInput: ConfigInvalidError) {
+  const head = "Invalid configuration"
+  const file = errorInput.data.path && errorInput.data.path !== "config" ? errorInput.data.path : ""
</file context>
Fix with Cubic

const issues = (errorInput.data.issues ?? []).map((issue) => {
return `${issue.path.join(".")}: ${issue.message}`
})
if (issues.length) return [head, file, "", ...issues].filter(Boolean).join("\n")
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Bug: The empty string "" intended as a blank-line separator is removed by .filter(Boolean) (empty string is falsy). The issues will appear directly after the header with no visual break. Consider filtering before inserting the separator.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/utils/server-errors.ts, line 30:

<comment>Bug: The empty string `""` intended as a blank-line separator is removed by `.filter(Boolean)` (empty string is falsy). The issues will appear directly after the header with no visual break. Consider filtering before inserting the separator.</comment>

<file context>
@@ -0,0 +1,32 @@
+  const issues = (errorInput.data.issues ?? []).map((issue) => {
+    return `${issue.path.join(".")}: ${issue.message}`
+  })
+  if (issues.length) return [head, file, "", ...issues].filter(Boolean).join("\n")
+  return [head, file, detail].filter(Boolean).join("\n")
+}
</file context>
Fix with Cubic

<div class="px-1.25 w-full flex items-center gap-x-3">
<ProviderIcon data-slot="list-item-extra-icon" id={icon(i.id)} />
<span>{i.name}</span>
<Show when={i.id === "opencode"}>
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Duplicate <Show when={i.id === "opencode"}> — this new block checks the same condition as the existing one a few lines below. Merge them into a single <Show> block to avoid redundant condition evaluation and improve readability.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/components/dialog-select-provider.tsx, line 74:

<comment>Duplicate `<Show when={i.id === "opencode"}>` — this new block checks the same condition as the existing one a few lines below. Merge them into a single `<Show>` block to avoid redundant condition evaluation and improve readability.</comment>

<file context>
@@ -70,13 +71,19 @@ export const DialogSelectProvider: Component = () => {
           <div class="px-1.25 w-full flex items-center gap-x-3">
             <ProviderIcon data-slot="list-item-extra-icon" id={icon(i.id)} />
             <span>{i.name}</span>
+            <Show when={i.id === "opencode"}>
+              <div class="text-14-regular text-text-weak">{language.t("dialog.provider.opencode.tagline")}</div>
+            </Show>
</file context>
Fix with Cubic

issue_number: item.number,
name: 'needs:compliance',
});
} catch (e) {}
Copy link

@cubic-dev-ai cubic-dev-ai bot Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Empty catch (e) {} silently swallows all errors, not just the expected 404. Consider logging the error at debug level so unexpected failures (auth issues, rate limits, network errors) aren't invisible.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/compliance-close.yml, line 75:

<comment>Empty `catch (e) {}` silently swallows all errors, not just the expected 404. Consider logging the error at debug level so unexpected failures (auth issues, rate limits, network errors) aren't invisible.</comment>

<file context>
@@ -65,6 +65,15 @@ jobs:
+                  issue_number: item.number,
+                  name: 'needs:compliance',
+                });
+              } catch (e) {}
+
               if (isPR) {
</file context>
Suggested change
} catch (e) {}
} catch (e) {
core.info(`Failed to remove label from #${item.number}: ${e.message}`);
}
Fix with Cubic

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the performance and stability of the TUI by optimizing event handling during LLM streaming, which was previously causing high garbage collection pressure and UI freezes. It also addresses several critical bugs related to stream termination, error propagation in database effects, and unresponsive MCP client calls. Furthermore, it introduces a clearer separation of configuration concerns by migrating TUI-specific settings to a dedicated file and enhances the desktop app's ability to correctly load shell environments on Windows.

Highlights

  • Performance Optimization: Batched all high-frequency streaming events (delta, status, part, message, todo, diff) into a unified 100ms flush window in sync.tsx to reduce store mutations and re-renders, addressing GC pressure.
  • SDK Event Batch Window Increase: Increased the SDK event batch window from 16ms to 50ms in sdk.tsx to further reduce render frequency during streaming.
  • Stream Termination Bug Fix: Resolved a bug in processor.ts where for await (stream.fullStream) never exited on a finish event, which caused 0% CPU hangs.
  • Error Handling for Effect Promises: Added error handling for fire-and-forget effect Promises in db.ts to prevent silent crash propagation.
  • MCP Client Timeout: Added a missing timeout to client.listTools() in mcp/index.ts to prevent indefinite hangs on unresponsive MCP servers.
  • TUI Config Migration: Introduced a migration plan for TUI-specific configuration keys (theme, keybinds, tui) from opencode.json to a new dedicated tui.json file, ensuring better separation of concerns and improved config management.
  • Windows Shell Environment Loading: Implemented robust shell environment loading for Windows in the desktop app, including timeout handling and detection of various shell types (e.g., PowerShell, Nushell), to improve command execution reliability.
Changelog
  • .github/actions/setup-bun/action.yml
    • Updated Bun setup action to use baseline download URL for improved reliability.
  • .opencode/agent/glossary/README.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/agent/translator.md
    • Updated glossary path in translator instructions to reflect new directory structure.
  • .opencode/glossary/ar.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/br.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/bs.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/da.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/de.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/es.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/fr.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/ja.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/ko.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/no.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/pl.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/ru.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/th.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/zh-cn.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • .opencode/glossary/zh-tw.md
    • Renamed glossary directory from .opencode/agent/glossary to .opencode/glossary.
  • bun.lock
    • Updated package versions across multiple internal packages to 1.2.15.
    • Added new Storybook-related dependencies including @storybook/addon-a11y, @storybook/addon-docs, @storybook/addon-links, @storybook/addon-onboarding, @storybook/addon-vitest, storybook, and storybook-solidjs-vite.
  • infra/console.ts
    • Renamed the 'OpenCode Lite' product to 'OpenCode Go' for consistency.
  • nix/hashes.json
    • Updated Nix hashes for node modules to reflect new dependencies and versions.
  • package.json
    • Updated the packageManager version to bun@1.3.10.
    • Updated the project version to 1.2.15.
  • packages/app/e2e/projects/projects-switch.spec.ts
    • Refactored project switch E2E test to use sessionPath for navigation.
    • Created sessions via SDK instead of relying on prompt input for session creation.
    • Removed the stamp variable as it's no longer needed.
  • packages/app/e2e/session/session-composer-dock.spec.ts
    • Refactored E2E tests for composer dock permissions, introducing withMockPermission and clearPermissionDock helpers.
    • Added new tests for child session permission and question requests to ensure proper blocking and unblocking behavior.
  • packages/app/e2e/utils.ts
    • Changed the default PLAYWRIGHT_SERVER_HOST from localhost to 127.0.0.1 for broader compatibility.
  • packages/app/package.json
    • Updated the package version to 1.2.15.
  • packages/app/playwright.config.ts
    • Changed the default PLAYWRIGHT_BASE_URL and PLAYWRIGHT_SERVER_HOST from localhost to 127.0.0.1.
  • packages/app/src/components/dialog-select-model-unpaid.tsx
    • Added a tagline and recommended tag for the 'OpenCode Go' provider in the model selection dialog.
  • packages/app/src/components/dialog-select-provider.tsx
    • Added a tagline and recommended tag for the 'OpenCode Go' provider in the provider selection dialog.
  • packages/app/src/components/file-tree.tsx
    • Removed the FileTreeNodeTooltip component and the tooltip prop from FileTree for simplification.
  • packages/app/src/components/prompt-input.tsx
    • Refactored auto-accept permissions logic to use a memoized accepting state for better performance and readability.
    • Updated UI text for auto-accept permission toggle.
  • packages/app/src/components/session/session-header.tsx
    • Refactored app opening logic to display a spinner while an application is launching.
    • Disabled open buttons during the app opening process.
    • Updated openIconSize usage for consistency.
  • packages/app/src/components/session/session-sortable-tab.tsx
    • Added a gutter prop to TooltipKeybind for improved tooltip positioning.
  • packages/app/src/components/settings-providers.tsx
    • Added a tagline and recommended tag for the 'OpenCode Go' provider in the settings.
  • packages/app/src/context/file/path.test.ts
    • Corrected Windows path normalization behavior in tests to ensure accurate path handling.
  • packages/app/src/context/file/path.ts
    • Adjusted Windows path normalization to preserve native separators and correctly handle . prefixes.
  • packages/app/src/context/global-sdk.tsx
    • Implemented batching for high-frequency streaming events (delta, status, part, message, todo, diff) into a unified 100ms flush window.
    • Reduced store mutations and alleviated garbage collection pressure during streaming.
  • packages/app/src/context/global-sync.tsx
    • Updated error handling to use formatServerError for toast messages, providing more user-friendly error descriptions.
  • packages/app/src/context/global-sync/bootstrap.ts
    • Updated error handling to use formatServerError for toast messages, improving error presentation.
  • packages/app/src/context/permission.tsx
    • Refactored auto-accept logic to be more generic for all permission types, not just edits.
    • Migrated autoAcceptEdits to a more general autoAccept store key.
    • Removed the shouldAutoAccept function as its logic is now integrated.
  • packages/app/src/hooks/use-providers.ts
    • Added 'opencode-go' to the list of popular providers.
  • packages/app/src/i18n/ar.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/br.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/bs.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/da.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/de.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/en.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/es.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/fr.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/ja.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/ko.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/no.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/pl.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/ru.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/th.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/zh.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/i18n/zht.ts
    • Updated translations for auto-accept permissions and added 'OpenCode Go' tagline.
  • packages/app/src/pages/directory-layout.tsx
    • Removed onPermissionRespond, onQuestionReply, and onQuestionReject from DataProvider as these are now handled internally.
  • packages/app/src/pages/layout.tsx
    • Refactored navigateToProject to find the latest root session across workspaces.
    • Implemented fetching sessions if not already loaded to ensure the most recent session is opened.
  • packages/app/src/pages/layout/helpers.test.ts
    • Added new tests for the latestRootSession helper function.
  • packages/app/src/pages/layout/helpers.ts
    • Added a new latestRootSession helper function to find the most recently updated root session across multiple workspaces.
  • packages/app/src/pages/layout/sidebar-project.tsx
    • Added suppressHover state to ProjectTile to prevent the hover card from opening when clicking on a selected project.
  • packages/app/src/pages/session.tsx
    • Adjusted message navigation logic to correctly handle the last message in the timeline.
    • Removed a redundant createEffect related to tab switching for improved efficiency.
  • packages/app/src/pages/session/composer/session-composer-state.test.ts
    • Added a new test file to validate the session request tree logic for permissions and questions.
  • packages/app/src/pages/session/composer/session-composer-state.ts
    • Refactored session composer state to utilize sessionPermissionRequest and sessionQuestionRequest for determining the blocked state, improving accuracy for nested sessions.
  • packages/app/src/pages/session/composer/session-request-tree.ts
    • Added a new file containing helper functions for traversing the session request tree to find relevant permissions and questions.
  • packages/app/src/pages/session/file-tabs.tsx
    • Introduced a cancelCommenting helper function to streamline comment cancellation logic.
    • Updated onCancel and setTimeout callbacks to use the new cancelCommenting helper.
  • packages/app/src/pages/session/helpers.test.ts
    • Updated test expectation for createOpenReviewFile to reflect the new order of operations.
  • packages/app/src/pages/session/helpers.ts
    • Modified loadFile to handle promises, ensuring that openTab is called only after the file content has been successfully loaded.
  • packages/app/src/pages/session/message-timeline.tsx
    • Added a data-session-title attribute to the session header for improved scroll positioning and UI consistency.
  • packages/app/src/pages/session/review-tab.tsx
    • Removed StickyAddButton logic, simplifying its rendering and reducing complexity.
  • packages/app/src/pages/session/session-side-panel.tsx
    • Removed conditional rendering for reviewPanel and simplified StickyAddButton usage for a cleaner implementation.
  • packages/app/src/pages/session/use-session-hash-scroll.ts
    • Added an offset based on the data-session-title element's height to the scroll calculation, ensuring correct positioning when sticky headers are present.
  • packages/app/src/utils/server-errors.test.ts
    • Added a new test file to validate the server error formatting utility functions.
  • packages/app/src/utils/server-errors.ts
    • Added a new file containing helper functions for formatting server errors, including specific handling for ConfigInvalidError.
  • packages/console/app/package.json
    • Updated the package version to 1.2.15.
    • Modified the build script to explicitly use bun and generate the tui.json schema.
  • packages/console/app/src/i18n/ar.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/br.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/da.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/de.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/en.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/es.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/fr.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/it.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/ja.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/ko.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/no.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/pl.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/ru.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/th.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/tr.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/zh.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/i18n/zht.ts
    • Added translations for 'black.paused', 'workspace.usage.lite', 'workspace.usage.byok', 'workspace.cost.liteShort', and the new 'workspace.lite' section.
  • packages/console/app/src/routes/black.css
    • Added new CSS styles for the [data-slot="paused"] element, used to display a message when the Black plan enrollment is paused.
  • packages/console/app/src/routes/black/index.tsx
    • Integrated a getPaused query and a Show component to conditionally display a paused message for the Black plan, improving user communication.
  • packages/console/app/src/routes/black/subscribe/[plan].tsx
    • Integrated a getEnabled query and a Show component to conditionally render the subscribe form, allowing for dynamic control over subscription availability.
  • packages/console/app/src/routes/stripe/webhook.ts
    • Refactored webhook handling to correctly differentiate between Black and Lite subscriptions.
    • Added LiteTable and BlackData imports for managing new subscription types.
    • Updated unsubscribe calls to use unsubscribeBlack or unsubscribeLite based on the product ID.
  • packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx
    • Updated Billing.subscribe to Billing.subscribeBlack to reflect the new subscription naming.
  • packages/console/app/src/routes/workspace/[id]/billing/index.tsx
    • Introduced a new LiteSection component for managing Lite subscription billing.
    • Implemented conditional rendering to display either BlackSection or LiteSection based on the user's subscription status.
  • packages/console/app/src/routes/workspace/[id]/billing/lite-section.module.css
    • Added a new CSS module to style the Lite subscription billing section, ensuring a consistent look and feel.
  • packages/console/app/src/routes/workspace/[id]/billing/lite-section.tsx
    • Added a new file for the Lite subscription billing section, including queries for subscription status, checkout URL generation, and balance usage settings.
  • packages/console/app/src/routes/workspace/[id]/graph-section.tsx
    • Updated getCosts to include plan in the enrichment data, allowing for more granular cost analysis.
    • Adjusted graph data processing to differentiate between 'lite' and 'sub' plans.
    • Added liteSuffix for graph labels to clearly distinguish Lite plan usage.
  • packages/console/app/src/routes/workspace/[id]/usage-section.tsx
    • Updated UsageSection to display plan-specific labels for usage costs, providing clearer billing information to users.
  • packages/console/app/src/routes/workspace/common.tsx
    • Added lite and liteSubscriptionID fields to queryBillingInfo, expanding the billing information available.
  • packages/console/app/src/routes/zen/go/v1/chat/completions.ts
    • Renamed the file from zen/lite to zen/go to reflect the new product branding.
  • packages/console/app/src/routes/zen/go/v1/messages.ts
    • Added a new file for handling Anthropic messages specifically for the zen/go endpoint.
  • packages/console/app/src/routes/zen/util/handler.ts
    • Added LiteTable import and ADMIN_WORKSPACES constant for internal management.
    • Included lite in AuthInfo and updated validateBilling to correctly handle Lite subscriptions.
    • Improved metric logging to capture more detailed subscription source information.
  • packages/console/app/src/routes/zen/v1/models.ts
    • Added a filter to exclude 'alpha-' models in production environments, ensuring only stable models are exposed.
  • packages/console/core/migrations/20260224043338_nifty_starjammers/migration.sql
    • Added a new migration to introduce the lite table and new lite_subscription_id and lite columns to the billing table, supporting the new Lite subscription plan.
  • packages/console/core/migrations/20260224043338_nifty_starjammers/snapshot.json
    • Added a new snapshot for the updated database schema, reflecting the changes introduced by the Lite subscription migration.
  • packages/console/core/package.json
    • Updated the package version to 1.2.15.
  • packages/console/core/script/black-select-workspaces.ts
    • Updated SubscriptionPlan to BlackPlans for consistency with new naming conventions.
  • packages/console/core/script/lookup-user.ts
    • Updated SubscriptionPlan to BlackPlans for consistency with new naming conventions.
  • packages/console/core/src/billing.ts
    • Added generateLiteCheckoutUrl for creating checkout sessions for the Lite plan.
    • Renamed subscribe to subscribeBlack and unsubscribe to unsubscribeBlack for clarity.
    • Introduced unsubscribeLite to handle cancellations for the Lite subscription plan.
  • packages/console/core/src/black.ts
    • Updated SubscriptionPlan to BlackPlans for consistency.
    • Added a productID function to retrieve the product ID for the Black plan.
  • packages/console/core/src/identifier.ts
    • Added lite to ID_PREFIXES, enabling unique ID generation for Lite-related entities.
  • packages/console/core/src/lite.ts
    • Updated LiteData schema to include weeklyLimit and monthlyLimit, and removed fixedLimit.
    • Added productID, priceID, and planName functions for managing Lite plan details.
  • packages/console/core/src/schema/billing.sql.ts
    • Renamed SubscriptionPlan to BlackPlans for better clarity.
    • Added liteSubscriptionID and lite columns to BillingTable to support the new Lite subscription.
    • Introduced the LiteTable schema for storing Lite subscription-specific data.
  • packages/console/core/src/subscription.ts
    • Added getMonthlyBounds import and a new analyzeMonthlyUsage function for monthly usage tracking.
    • Adjusted usagePercent calculation to use Math.floor for more accurate representation.
  • packages/console/core/src/util/date.test.ts
    • Removed the old date test file, as its functionality has been replaced or moved.
  • packages/console/core/src/util/date.ts
    • Added a new getMonthlyBounds function to calculate monthly date boundaries based on subscription start dates.
  • packages/console/core/test/date.test.ts
    • Added a new test file to validate the getMonthlyBounds function in util/date.ts.
  • packages/console/core/test/subscription.test.ts
    • Added a new test file to validate the analyzeMonthlyUsage function in Subscription namespace.
  • packages/console/function/package.json
    • Updated the package version to 1.2.15.
  • packages/console/function/src/log-processor.ts
    • Added new zen/go paths to the log processor, ensuring proper logging for the rebranded endpoints.
  • packages/console/mail/package.json
    • Updated the package version to 1.2.15.
  • packages/desktop/README.md
    • Added prerequisites and troubleshooting sections for Rust, guiding users on setting up the development environment for the desktop app.
  • packages/desktop/package.json
    • Updated the package version to 1.2.15.
  • packages/desktop/src-tauri/Cargo.lock
    • Updated windows-core to 0.61.2 and windows-sys to 0.61.2.
  • packages/desktop/src-tauri/Cargo.toml
    • Updated windows-sys and windows-core dependencies to newer versions for improved compatibility and features.
  • packages/desktop/src-tauri/src/cli.rs
    • Implemented robust shell environment probing logic, including command_output_with_timeout, parse_shell_env, merge_shell_env, is_nushell, and load_shell_env functions.
    • Updated spawn_command to utilize the loaded shell environment, enhancing command execution reliability.
    • Changed command.creation_flags to use direct CREATE_NO_WINDOW | CREATE_SUSPENDED instead of .0.
  • packages/desktop/src-tauri/src/lib.rs
    • Added a new os module to encapsulate OS-specific utilities.
    • Introduced an open_in_powershell command for Windows-specific functionality.
    • Updated check_app_exists and resolve_app_path to leverage the new os::windows functions.
  • packages/desktop/src-tauri/src/os/mod.rs
    • Added a new module for OS-specific utilities, currently containing Windows-specific implementations.
  • packages/desktop/src-tauri/src/os/windows.rs
    • Added a new file containing Windows-specific app path resolution logic, including registry lookups and environment variable expansion.
    • Implemented open_in_powershell function to launch PowerShell in a specified directory.
  • packages/desktop/src/bindings.ts
    • Added openInPowershell command to the bindings, exposing the new Windows-specific functionality to the frontend.
  • packages/desktop/src/index.tsx
    • Implemented PowerShell opening logic for Windows, allowing users to open directories directly in PowerShell.
  • packages/enterprise/package.json
    • Updated the package version to 1.2.15.
  • packages/extensions/zed/extension.toml
    • Updated the extension version to 1.2.15.
    • Updated archive URLs to point to the new release version.
  • packages/function/package.json
    • Updated the package version to 1.2.15.
  • packages/opencode/BUN_SHELL_MIGRATION_PLAN.md
    • Added a new markdown file outlining a phased migration plan to replace Bun shell template-tag usage with a unified Process API.
  • packages/opencode/package.json
    • Updated the package version to 1.2.15.
  • packages/opencode/script/schema.ts
    • Refactored schema generation into a reusable generate function.
    • Added TuiConfig schema generation, providing schema for TUI-specific settings.
    • Removed theme, keybinds, and tui from Config.Info schema, as these are now handled by TuiConfig.
  • packages/opencode/src/acp/agent.ts
    • Implemented bashSnapshots and toolStarts to track tool execution and prevent duplicate tool_call events.
    • Added bashOutput and toolStart helper functions for better tool state management.
    • Included metadata in error raw output for more detailed error reporting.
  • packages/opencode/src/bun/index.ts
    • Updated the run function to utilize Process.spawn and text consumer for more robust command execution.
    • Adjusted the --no-cache condition for bun install to include CI environments.
  • packages/opencode/src/bun/registry.ts
    • Updated the info function to use Process.spawn and text consumer for consistent process handling.
  • packages/opencode/src/cli/cmd/auth.ts
    • Updated AuthLoginCommand to use Process.spawn and text consumer for command execution, aligning with the new process API.
  • packages/opencode/src/cli/cmd/session.ts
    • Updated SessionListCommand to use Process.spawn and correctly handle stdin pipe for pager commands.
  • packages/opencode/src/cli/cmd/tui/app.tsx
    • Integrated TuiConfigProvider and TuiConfig into the TUI app initialization, allowing TUI settings to be loaded and managed separately.
  • packages/opencode/src/cli/cmd/tui/attach.ts
    • Added TuiConfig loading to AttachCommand, ensuring TUI-specific settings are applied when attaching to a session.
  • packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx
    • Updated KeybindKey type to reference the new TuiConfig for keybind definitions.
  • packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
    • Updated PROVIDER_PRIORITY to include 'opencode-go' and adjusted the order.
    • Added 'opencode-go' tagline for better user context.
  • packages/opencode/src/cli/cmd/tui/component/tips.tsx
    • Updated tips related to tui.json and scroll_acceleration to reflect the new configuration structure.
  • packages/opencode/src/cli/cmd/tui/context/keybind.tsx
    • Refactored KeybindProvider to use useTuiConfig for retrieving keybind configurations.
    • Introduced KeybindKey type for improved type safety.
  • packages/opencode/src/cli/cmd/tui/context/sdk.tsx
    • Increased the SDK event batch window from 16ms to 50ms to further reduce render frequency during streaming.
  • packages/opencode/src/cli/cmd/tui/context/sync.tsx
    • Implemented batching for all high-frequency streaming events (delta, status, part, message, todo, diff) into a 100ms flush window.
    • This significantly reduces store mutations and alleviates garbage collection pressure during streaming.
  • packages/opencode/src/cli/cmd/tui/context/theme.tsx
    • Refactored ThemeProvider to use useTuiConfig for theme settings, centralizing TUI theme management.
  • packages/opencode/src/cli/cmd/tui/context/tui-config.tsx
    • Added a new file for the TUI config context, providing a dedicated store for TUI-specific settings.
  • packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
    • Updated the session component to use useTuiConfig for TUI-specific settings.
    • Removed diagnostics from Write and Edit tools, as diagnostics are now handled by a dedicated Diagnostics component.
  • packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
    • Updated EditBody to use useTuiConfig for diff style settings, ensuring consistency with the new TUI config structure.
  • packages/opencode/src/cli/cmd/tui/thread.ts
    • Added TuiConfig loading to TuiThreadCommand, ensuring TUI-specific settings are available in the TUI thread.
  • packages/opencode/src/cli/cmd/tui/util/clipboard.ts
    • Updated clipboard functions to use Process.spawn and correctly handle stdin pipe, improving cross-platform compatibility and reliability.
  • packages/opencode/src/cli/cmd/tui/util/editor.ts
    • Updated Editor.open to use Process.spawn for consistent and robust external editor launching.
  • packages/opencode/src/cli/cmd/workspace-serve.ts
    • Added a new file for the workspace-serve command, enabling a remote workspace websocket server.
  • packages/opencode/src/config/config.ts
    • Refactored config loading to use ConfigPaths for centralized file handling.
    • Removed theme, keybinds, and tui from Config.Info schema, as these are now managed by TuiConfig.
    • Updated the merge function to mergeConfigConcatArrays for consistent array merging behavior.
  • packages/opencode/src/config/markdown.ts
    • Updated frontmatter splitting to handle both Unix ( ) and Windows ( ) line endings, improving cross-platform compatibility.
  • packages/opencode/src/config/migrate-tui-config.ts
    • Added a new file containing logic for migrating TUI-specific configuration keys from opencode.json to tui.json.
  • packages/opencode/src/config/paths.ts
    • Added a new file with utility functions for handling config file paths, including project file discovery, directory traversal, and JSONC parsing with environment and file substitutions.
  • packages/opencode/src/config/tui-schema.ts
    • Added a new file defining the schema for TUI-specific configuration, including scroll speed, acceleration, diff style, theme, and keybinds.
  • packages/opencode/src/config/tui.ts
    • Added a new file for TUI config loading and management, implementing a precedence order for merging TUI settings from various sources.
  • packages/opencode/src/file/ignore.ts
    • Updated filepath splitting to handle both Unix (/) and Windows (\]) path separators, improving cross-platform ignore pattern matching.
  • packages/opencode/src/file/ripgrep.ts
    • Updated Ripgrep functions to use Process.spawn and text consumer for consistent process handling.
    • Added a guard against invalid cwd to provide more informative error messages.
  • packages/opencode/src/file/time.ts
    • Added a 50ms tolerance for Windows NTFS timestamp fuzziness in FileTime.assertNotModified, preventing false positives for file modifications.
  • packages/opencode/src/flag/flag.ts
    • Added a new OPENCODE_TUI_CONFIG flag for specifying a custom TUI configuration file path.
  • packages/opencode/src/format/formatter.ts
    • Updated rlang and uvformat enabled checks to use Process.spawn and text consumer for consistent process execution.
  • packages/opencode/src/format/index.ts
    • Updated Format.file to use Process.spawn for external formatter execution, aligning with the new process API.
  • packages/opencode/src/index.ts
    • Added WorkspaceServeCommand to CLI commands, conditionally enabled if Installation.isLocal().
  • packages/opencode/src/lsp/server.ts
    • Updated LSP server functions to use Process.spawn and text consumer for command execution, improving consistency and reliability.
  • packages/opencode/src/mcp/index.ts
    • Added withTimeout to client.listTools() call, preventing indefinite hangs when connecting to unresponsive MCP servers.
  • packages/opencode/src/project/project.ts
    • Changed void Filesystem.write to await Filesystem.write for explicit asynchronous file writing.
  • packages/opencode/src/pty/index.ts
    • Refactored Pty to use a connectionKey for subscribers, simplifying socket management and improving robustness.
    • Simplified socket tagging logic.
  • packages/opencode/src/server/routes/session.ts
    • Added a new DELETE route for /session/:sessionID/message/:messageID, allowing permanent deletion of messages.
  • packages/opencode/src/session/index.ts
    • Updated Session.removeMessage and Session.removePart to include session_id in the where clause, ensuring correct deletion scope.
  • packages/opencode/src/session/processor.ts
    • Fixed a stream termination bug where for await (stream.fullStream) never exited on a finish event, resolving 0% CPU hangs.
  • packages/opencode/src/snapshot/index.ts
    • Added core.longpaths, core.symlinks, and core.fsmonitor git configurations for improved compatibility and performance.
    • Updated git commands to explicitly include these flags.
  • packages/opencode/src/storage/db.ts
    • Added a close function to the Database namespace for proper database shutdown.
    • Implemented error handling for effect promises to catch and log failures in fire-and-forget operations.
  • packages/opencode/src/tool/grep.ts
    • Updated GrepTool to use Process.spawn and text consumer for consistent and robust command execution.
  • packages/opencode/src/tool/plan.ts
    • Removed PlanEnterTool and its associated import, streamlining the planning tools.
  • packages/opencode/src/tool/registry.ts
    • Removed PlanEnterTool from getTools and updated plugin import to use pathToFileURL for better module resolution.
  • packages/opencode/src/util/git.ts
    • Refactored the git function to use Process.run instead of $ or Bun.spawn, providing a more consistent and robust interface for git commands.
  • packages/opencode/src/util/process.ts
    • Added a new file defining the Process namespace, offering a robust API for executing child processes with features like stdout/stderr capture, error handling, and abort signals.
  • packages/opencode/test/acp/event-subscription.test.ts
    • Added new tests for bash output snapshots, ensuring correct tracking and de-duplication of identical output.
    • Included tests for synthetic pending events and clearing snapshots to validate tool state management.
  • packages/opencode/test/config/config.test.ts
    • Added a test for ignoring legacy TUI keys in opencode.json during config loading.
    • Updated environment variable substitution test to use username instead of theme.
    • Fixed import.meta.resolve for scoped npm plugins to correctly resolve paths.
  • packages/opencode/test/config/markdown.test.ts
    • Updated test for frontmatter parsing to handle both Unix and Windows line endings, improving cross-platform compatibility.
  • packages/opencode/test/config/tui.test.ts
    • Added a new test file to thoroughly validate TUI config loading, precedence, migration from opencode.json, and handling of various edge cases like invalid JSON and read-only files.
  • packages/opencode/test/ide/ide.test.ts
    • Updated original environment variable cloning to ensure proper test isolation.
  • packages/opencode/test/preload.ts
    • Added Database.close() and retry logic for fs.rm in the afterAll hook to handle Windows SQLite EBUSY errors, improving test suite stability.
  • packages/opencode/test/skill/discovery.test.ts
    • Updated test to use path.sep for platform-agnostic path checking, ensuring tests pass on different operating systems.
  • packages/opencode/test/snapshot/snapshot.test.ts
    • Added a fwd helper for platform-agnostic path assertions in tests.
    • Updated git commands to explicitly include core.longpaths, core.symlinks, and core.fsmonitor flags for improved compatibility and behavior.
  • packages/opencode/test/tool/bash.test.ts
    • Updated bash tool tests to use os.tmpdir() for temporary directory paths and handle Windows EOL for consistent output assertions.
  • packages/opencode/test/tool/external-directory.test.ts
    • Updated external directory tests to normalize paths for cross-platform consistency.
  • packages/opencode/test/tool/write.test.ts
    • Added a new test case for OS write access denial in WriteTool, ensuring proper error handling when files are read-only.
  • packages/opencode/test/util/glob.test.ts
    • Updated glob tests to use path.join for platform-agnostic path assertions, ensuring tests pass on different operating systems.
  • packages/opencode/test/util/process.test.ts
    • Added a new test file to validate the Process utility, covering stdout/stderr capture, error handling, and process abortion.
  • packages/ui/package.json
    • Updated the package version to 1.2.15.
    • Added package.json export for better module resolution.
  • packages/ui/src/assets/icons/provider/302ai.svg
    • Added a new SVG icon for the '302ai' provider.
  • packages/ui/src/assets/icons/provider/berget.svg
    • Added a new SVG icon for the 'Berget' provider.
  • packages/ui/src/assets/icons/provider/cloudferro-sherlock.svg
    • Added a new SVG icon for the 'CloudFerro Sherlock' provider.
  • packages/ui/src/assets/icons/provider/firmware.svg
    • Added a new SVG icon for the 'Firmware' provider.
  • packages/ui/src/assets/icons/provider/gitlab.svg
    • Added a new SVG icon for the 'GitLab' provider.
  • packages/ui/src/assets/icons/provider/jiekou.svg
    • Added a new SVG icon for the 'Jiekou' provider.
  • packages/ui/src/assets/icons/provider/kilo.svg
    • Added a new SVG icon for the 'Kilo' provider.
  • packages/ui/src/assets/icons/provider/kuae-cloud-coding-plan.svg
    • Added a new SVG icon for the 'Kuae Cloud Coding Plan' provider.
  • packages/ui/src/assets/icons/provider/meganova.svg
    • Added a new SVG icon for the 'Meganova' provider.
  • packages/ui/src/assets/icons/provider/minimax-cn-coding-plan.svg
    • Added a new SVG icon for the 'Minimax CN Coding Plan' provider.
  • packages/ui/src/assets/icons/provider/minimax-coding-plan.svg
    • Added a new SVG icon for the 'Minimax Coding Plan' provider.
  • packages/ui/src/assets/icons/provider/moark.svg
    • Added a new SVG icon for the 'Moark' provider.
  • packages/ui/src/assets/icons/provider/nova.svg
    • Added a new SVG icon for the 'Nova' provider.
  • packages/ui/src/assets/icons/provider/novita-ai.svg
    • Added a new SVG icon for the 'Novita AI' provider.
  • packages/ui/src/assets/icons/provider/privatemode-ai.svg
    • Added a new SVG icon for the 'Privatemode AI' provider.
  • packages/ui/src/assets/icons/provider/qihang-ai.svg
    • Added a new SVG icon for the 'Qihang AI' provider.
  • packages/ui/src/assets/icons/provider/qiniu-ai.svg
    • Added a new SVG icon for the 'Qiniu AI' provider.
  • packages/ui/src/assets/icons/provider/stackit.svg
    • Added a new SVG icon for the 'Stackit' provider.
  • packages/ui/src/assets/icons/provider/stepfun.svg
    • Added a new SVG icon for the 'Stepfun' provider.
  • packages/ui/src/assets/icons/provider/vivgrid.svg
    • Added a new SVG icon for the 'Vivgrid' provider.
  • packages/ui/src/components/accordion.stories.tsx
    • Added a new Storybook file for the Accordion component, showcasing its basic usage, multiple open items, and non-collapsible states.
  • packages/ui/src/components/app-icon.stories.tsx
    • Added a new Storybook file for the AppIcon component, demonstrating its basic usage and displaying all available icons.
  • packages/ui/src/components/avatar.stories.tsx
    • Added a new Storybook file for the Avatar component, illustrating its basic usage, image support, different sizes, and custom color options.
  • packages/ui/src/components/basic-tool.stories.tsx
    • Added a new Storybook file for the BasicTool component, showcasing its various states including pending, locked, deferred, force open, hidden details, and subtitle actions.
  • packages/ui/src/components/button.stories.tsx
    • Added a new Storybook file for the Button component, demonstrating its primary, secondary, ghost variants, icon support, disabled state, and different sizes.
  • packages/ui/src/components/card.stories.tsx
    • Added a new Storybook file for the Card component, illustrating its normal, error, warning, success, and info variants.
  • packages/ui/src/components/checkbox.stories.tsx
    • Added a new Storybook file for the Checkbox component, showcasing its basic usage, various states (checked, unchecked, disabled), custom icon support, and hidden label option.
  • packages/ui/src/components/code.stories.tsx
    • Added a new Storybook file for the Code component, demonstrating basic usage, selected lines, and commented lines.
  • packages/ui/src/components/collapsible.stories.tsx
    • Added a new Storybook file for the Collapsible component, illustrating its basic usage with normal and ghost variants.
  • packages/ui/src/components/context-menu.stories.tsx
    • Added a new Storybook file for the ContextMenu component, showcasing its basic usage with grouped actions, submenus, checkbox items, and radio groups.
  • packages/ui/src/components/dialog.stories.tsx
    • Added a new Storybook file for the Dialog component, demonstrating its basic usage, different sizes, transition effects, custom actions, and fit-to-content behavior.
  • packages/ui/src/components/diff-changes.stories.tsx
    • Added a new Storybook file for the DiffChanges component, illustrating its default and bars variants, handling of multiple files, and zero changes.
  • packages/ui/src/components/diff-ssr.stories.tsx
    • Added a new Storybook file for the DiffSSR component, showcasing its basic usage with unified and split diff styles for server-rendered diffs.
  • packages/ui/src/components/diff.stories.tsx
    • Added a new Storybook file for the Diff component, demonstrating its unified and split styles, selectable lines, selected lines, and commented lines.
  • packages/ui/src/components/dock-prompt.stories.tsx
    • Added a new Storybook file for the DockPrompt component, illustrating its basic usage for questions and permission requests.
  • packages/ui/src/components/dropdown-menu.stories.tsx
    • Added a new Storybook file for the DropdownMenu component, showcasing its basic usage with grouped actions, submenus, checkbox items, and radio groups.
  • packages/ui/src/components/favicon.stories.tsx
    • Added a new Storybook file for the Favicon component, demonstrating its basic functionality of injecting favicon and app icon meta tags.
  • packages/ui/src/components/file-icon.stories.tsx
    • Added a new Storybook file for the FileIcon component, illustrating its basic usage for files and folders, and providing various icon samples.
  • packages/ui/src/components/font.stories.tsx
    • Added a new Storybook file for the Font component, demonstrating its basic functionality of loading OpenCode typography assets.
  • packages/ui/src/components/hover-card.stories.tsx
    • Added a new Storybook file for the HoverCard component, showcasing its basic usage and inline mounting capabilities.
  • packages/ui/src/components/icon-button.stories.tsx
    • Added a new Storybook file for the IconButton component, illustrating its basic usage, different sizes, variants, and icon size overrides.
Ignored Files
  • Ignored by pattern: .github/workflows/** (8)
    • .github/workflows/beta.yml
    • .github/workflows/compliance-close.yml
    • .github/workflows/docs-locale-sync.yml
    • .github/workflows/pr-standards.yml
    • .github/workflows/test.yml
    • .github/workflows/vouch-check-issue.yml
    • .github/workflows/vouch-check-pr.yml
    • .github/workflows/vouch-manage-by-issue.yml
Activity
  • The pull request was created by coleleavitt.
  • No human activity (comments, reviews) has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

const pendingDiffs = new Map<string, import("@/snapshot").Snapshot.FileDiff[]>()
let batchTimer: Timer | undefined

function scheduleBatchFlush(setStore: any, store: any) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. schedulebatchflush uses any 📘 Rule violation ✓ Correctness

The new streaming batcher introduces multiple explicit any types (e.g., setStore: any, `store:
any, and draft: any[]`), weakening type safety and enabling incorrect store mutations to compile.
This violates the requirement to avoid any in new/modified TypeScript code.
Agent Prompt
## Issue description
New code in the streaming batcher uses explicit `any` types (including in `scheduleBatchFlush` and `produce()` drafts), violating the project rule to avoid `any` and reducing compile-time safety.

## Issue Context
The batcher can be typed without `any` by:
- moving `scheduleBatchFlush` inside `init()` so it can capture typed `store`/`setStore` via inference, and/or
- defining a local `type` for the store shape and using it for `createStore<...>()` and `SetStoreFunction<...>`.
Also remove unnecessary `(m: any)` / `(p: any)` annotations and let inference work.

## Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/context/sync.tsx[44-155]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 24 to 28
showAllFiles: () => void
tabForPath: (path: string) => string
openTab: (tab: string) => void
loadFile: (path: string) => void
loadFile: (path: string) => any | Promise<void>
}) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. loadfile returns any 📘 Rule violation ✓ Correctness

createOpenReviewFile changes loadFile to return any | Promise<void>, introducing any and
erasing the expected contract of the callback. This can mask incorrect return types and breaks the
no-any rule.
Agent Prompt
## Issue description
`loadFile` was broadened to `any | Promise<void>`, which introduces `any` and removes type safety.

## Issue Context
The implementation only needs to know whether the result is async; the correct type is `void | Promise<void>` (or `unknown | Promise<void>` with narrowing), not `any`.

## Fix Focus Areas
- packages/app/src/pages/session/helpers.ts[23-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

)
}

function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]>; filePath: string }) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. diagnostics props use any 📘 Rule violation ✓ Correctness

The newly added Diagnostics component types diagnostics as `Record<string, Record<string,
any>[]>, introducing any` into the TUI route. This prevents compile-time checking of diagnostic
shape used in rendering (e.g., severity, range, message).
Agent Prompt
## Issue description
`Diagnostics` introduces `any` in its `diagnostics` prop type, which weakens type safety in new UI code.

## Issue Context
The component reads `severity`, `range.start.line`, `range.start.character`, and `message`. Define/import a type that includes these fields, or accept `unknown` and narrow before rendering.

## Fix Focus Areas
- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx[2141-2157]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +9 to +10
parseModel: (url: string, body: any) => body.model,
parseIsStream: (url: string, body: any) => !!body.stream,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. parsemodel uses body: any 📘 Rule violation ⛨ Security

The new POST handler uses body: any for request parsing, introducing any on external input
handling. This removes type safety where validation/narrowing is expected for untrusted request
bodies.
Agent Prompt
## Issue description
The new console endpoint parses request bodies using `any`, which violates the no-`any` rule and weakens safety for untrusted inputs.

## Issue Context
Request bodies are external inputs; prefer `unknown` and explicit narrowing (e.g., check for object shape and string/boolean fields) before reading `model`/`stream`.

## Fix Focus Areas
- packages/console/app/src/routes/zen/go/v1/messages.ts[4-11]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +43 to +75
async function clearPermissionDock(page: any, label: RegExp) {
const dock = page.locator(permissionDockSelector)
for (let i = 0; i < 3; i++) {
const count = await dock.count()
if (count === 0) return
await dock.getByRole("button", { name: label }).click()
await page.waitForTimeout(150)
}
}

async function withMockPermission<T>(
page: any,
request: {
id: string
sessionID: string
permission: string
patterns: string[]
metadata?: Record<string, unknown>
always?: string[]
},
opts: { child?: any } | undefined,
fn: () => Promise<T>,
) {
let pending = [
{
...request,
always: request.always ?? ["*"],
metadata: request.metadata ?? {},
},
]

const list = async (route: any) => {
await route.fulfill({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. E2e mocks use any 📘 Rule violation ✓ Correctness

The updated e2e test introduces multiple any-typed Playwright objects (page: any, route: any,
and opts: { child?: any }), reducing test correctness and violating the no-any rule. This can
hide incorrect API usage and make refactors harder.
Agent Prompt
## Issue description
New e2e helpers type Playwright objects as `any`, violating the no-`any` rule and reducing test type safety.

## Issue Context
Playwright provides types like `Page` and `Route` that can be imported from `@playwright/test` (or the project’s fixture types). Replace `opts.child?: any` with a concrete type matching the mocked session object.

## Fix Focus Areas
- packages/app/e2e/session/session-composer-dock.spec.ts[43-109]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +501 to +504
const { agent, controller, sessionUpdates, stop } = createFakeAgent()
const cwd = "/tmp/opencode-acp-test"
const sessionId = await agent.newSession({ cwd, mcpServers: [] } as any).then((x) => x.sessionId)
const input = { command: "echo hello", description: "run command" }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

6. Acp test casts as any 📘 Rule violation ✓ Correctness

The updated ACP event subscription tests use as any casts when calling agent.newSession(...),
introducing any and bypassing type checks on session creation inputs. This violates the no-any
rule and can let incorrect test setup compile.
Agent Prompt
## Issue description
The ACP event subscription test suite introduces `as any` casts for session creation, bypassing TypeScript safety.

## Issue Context
Prefer importing the expected input type for `agent.newSession` (or deriving it via `Parameters<typeof agent.newSession>[0]`) and building a valid object without casting.

## Fix Focus Areas
- packages/opencode/test/acp/event-subscription.test.ts[496-541]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is an excellent pull request that addresses critical performance and stability issues in the TUI while also making significant architectural improvements. The batching of streaming events, fixing the stream termination bug, and adding timeouts are all crucial fixes. The refactoring of configuration into separate server and TUI files, along with the robust migration path, is very well-executed. Similarly, replacing direct Bun.spawn calls with a more robust Process utility is a great move for maintainability and stability. The introduction of the "Go" plan is a major feature, and the implementation across the backend and frontend seems thorough. Overall, these are high-quality changes that significantly improve the product.

Comment on lines +18 to +21
expect(path.normalize("C:\\repo\\src\\app.ts")).toBe("src\\app.ts")
expect(path.normalize("C:/repo/src/app.ts")).toBe("src/app.ts")
expect(path.normalize("file://C:/repo/src/app.ts")).toBe("src/app.ts")
expect(path.normalize("c:\\repo\\src\\app.ts")).toBe("src/app.ts")
expect(path.normalize("c:\\repo\\src\\app.ts")).toBe("src\\app.ts")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test has become platform-dependent. It will pass on Windows but fail on POSIX systems because the expected path contains backslashes. To ensure the test is portable, consider normalizing the path separators to forward slashes before the assertion.

Suggested change
expect(path.normalize("C:\\repo\\src\\app.ts")).toBe("src\\app.ts")
expect(path.normalize("C:/repo/src/app.ts")).toBe("src/app.ts")
expect(path.normalize("file://C:/repo/src/app.ts")).toBe("src/app.ts")
expect(path.normalize("c:\\repo\\src\\app.ts")).toBe("src/app.ts")
expect(path.normalize("c:\\repo\\src\\app.ts")).toBe("src\\app.ts")
expect(path.normalize("C:\\repo\\src\\app.ts").replace(/\\/g, "/")).toBe("src/app.ts")
expect(path.normalize("C:/repo/src/app.ts")).toBe("src/app.ts")
expect(path.normalize("file://C:/repo/src/app.ts")).toBe("src/app.ts")
expect(path.normalize("c:\\repo\\src\\app.ts").replace(/\\/g, "/")).toBe("src/app.ts")

@coleleavitt
Copy link
Owner Author

Closing to rebase onto current dev. Will reopen with clean diff (sync.tsx changes moved to PR #3).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.