From 2ebc912d3e3465bc35c12fe3cfd056f763ea466f Mon Sep 17 00:00:00 2001
From: youxikexue <5642921+youxikexue@users.noreply.github.com>
Date: Tue, 14 Jul 2026 16:58:30 +0800
Subject: [PATCH 1/5] fix(messages): hide pointer focus ring on thread
---
.../virtualized-message-thread.test.tsx | 106 ++++++++++++++++++
.../message/virtualized-message-thread.tsx | 13 ++-
2 files changed, 117 insertions(+), 2 deletions(-)
create mode 100644 src/components/message/virtualized-message-thread.test.tsx
diff --git a/src/components/message/virtualized-message-thread.test.tsx b/src/components/message/virtualized-message-thread.test.tsx
new file mode 100644
index 000000000..7ac6a53fe
--- /dev/null
+++ b/src/components/message/virtualized-message-thread.test.tsx
@@ -0,0 +1,106 @@
+import type { ReactNode } from "react"
+import { fireEvent, render, screen } from "@testing-library/react"
+import { beforeEach, describe, expect, it, vi } from "vitest"
+
+const testState = vi.hoisted(() => ({
+ scrollRef: { current: null as HTMLDivElement | null },
+}))
+
+vi.mock("use-stick-to-bottom", () => ({
+ useStickToBottomContext: () => ({ scrollRef: testState.scrollRef }),
+}))
+
+vi.mock("virtua", () => ({
+ Virtualizer: ({ children }: { children: ReactNode }) => <>{children}>,
+}))
+
+vi.mock("@/components/ai-elements/message-thread", () => ({
+ MessageThreadContent: ({
+ children,
+ scrollClassName,
+ }: {
+ children: ReactNode
+ scrollClassName?: string
+ }) => (
+
{
+ testState.scrollRef.current = element
+ }}
+ className={scrollClassName}
+ data-testid="viewport"
+ >
+ {children}
+
+ ),
+}))
+
+import { VirtualizedMessageThread } from "@/components/message/virtualized-message-thread"
+
+function renderThread(
+ content: ReactNode = text
+) {
+ return render(
+ item.id}
+ renderItem={() => content}
+ />
+ )
+}
+
+function pointerDown(element: HTMLElement, button: number) {
+ fireEvent(element, new MouseEvent("pointerdown", { bubbles: true, button }))
+}
+
+beforeEach(() => {
+ testState.scrollRef.current = null
+})
+
+describe("VirtualizedMessageThread focus origin", () => {
+ it("marks pointer-origin focus and clears it on blur", () => {
+ renderThread()
+ const viewport = screen.getByTestId("viewport")
+
+ pointerDown(screen.getByTestId("content"), 0)
+
+ expect(document.activeElement).toBe(viewport)
+ expect(viewport).toHaveAttribute("data-focus-origin", "pointer")
+ expect(viewport.className).toContain(
+ "data-[focus-origin=pointer]:focus-visible:ring-0"
+ )
+
+ fireEvent.blur(viewport)
+ expect(viewport).not.toHaveAttribute("data-focus-origin")
+ })
+
+ it("keeps keyboard-origin focus distinguishable", () => {
+ renderThread()
+ const viewport = screen.getByTestId("viewport")
+
+ viewport.focus()
+
+ expect(document.activeElement).toBe(viewport)
+ expect(viewport).not.toHaveAttribute("data-focus-origin")
+ expect(viewport.className).toContain("focus-visible:ring-2")
+ })
+
+ it("does not mark focus when an interactive control is clicked", () => {
+ renderThread()
+ const viewport = screen.getByTestId("viewport")
+
+ pointerDown(screen.getByTestId("action"), 0)
+
+ expect(viewport).not.toHaveAttribute("data-focus-origin")
+ expect(document.activeElement).not.toBe(viewport)
+ })
+
+ it("does not mark focus for a right click", () => {
+ renderThread()
+ const viewport = screen.getByTestId("viewport")
+
+ pointerDown(screen.getByTestId("content"), 2)
+
+ expect(viewport).not.toHaveAttribute("data-focus-origin")
+ expect(document.activeElement).not.toBe(viewport)
+ })
+})
diff --git a/src/components/message/virtualized-message-thread.tsx b/src/components/message/virtualized-message-thread.tsx
index e1987203f..ced6583ab 100644
--- a/src/components/message/virtualized-message-thread.tsx
+++ b/src/components/message/virtualized-message-thread.tsx
@@ -103,6 +103,9 @@ function VirtualizedMessageThreadImpl({
const el = scrollRef.current
if (!el) return
el.tabIndex = 0
+ const clearPointerFocus = () => {
+ el.removeAttribute("data-focus-origin")
+ }
const onPointerDown = (e: PointerEvent) => {
// Ignore right-click and macOS ctrl-click (both open the context menu).
if (e.button !== 0 || e.ctrlKey) return
@@ -117,10 +120,16 @@ function VirtualizedMessageThreadImpl({
)
)
return
+ el.setAttribute("data-focus-origin", "pointer")
el.focus({ preventScroll: true })
}
el.addEventListener("pointerdown", onPointerDown)
- return () => el.removeEventListener("pointerdown", onPointerDown)
+ el.addEventListener("blur", clearPointerFocus)
+ return () => {
+ el.removeEventListener("pointerdown", onPointerDown)
+ el.removeEventListener("blur", clearPointerFocus)
+ clearPointerFocus()
+ }
}, [scrollRef])
// Pre-compute the three possible padding styles so every render reuses
@@ -146,7 +155,7 @@ function VirtualizedMessageThreadImpl({
{items.length === 0 ? (
From a87e3ab9cd5e2749caf18fe5808e00ac164de6dc Mon Sep 17 00:00:00 2001
From: xintaofei
Date: Thu, 23 Jul 2026 22:31:25 +0800
Subject: [PATCH 2/5] fix(messages): restore focus ring on keyboard input after
pointer focus
---
.../virtualized-message-thread.test.tsx | 19 +++++++++++++++++++
.../message/virtualized-message-thread.tsx | 7 +++++++
2 files changed, 26 insertions(+)
diff --git a/src/components/message/virtualized-message-thread.test.tsx b/src/components/message/virtualized-message-thread.test.tsx
index 7ac6a53fe..82a53c623 100644
--- a/src/components/message/virtualized-message-thread.test.tsx
+++ b/src/components/message/virtualized-message-thread.test.tsx
@@ -52,6 +52,10 @@ function pointerDown(element: HTMLElement, button: number) {
fireEvent(element, new MouseEvent("pointerdown", { bubbles: true, button }))
}
+function keyDown(element: HTMLElement, key: string) {
+ fireEvent.keyDown(element, { key })
+}
+
beforeEach(() => {
testState.scrollRef.current = null
})
@@ -73,6 +77,21 @@ describe("VirtualizedMessageThread focus origin", () => {
expect(viewport).not.toHaveAttribute("data-focus-origin")
})
+ it("clears the pointer marker on keyboard input so the ring returns", () => {
+ renderThread()
+ const viewport = screen.getByTestId("viewport")
+
+ pointerDown(screen.getByTestId("content"), 0)
+ expect(viewport).toHaveAttribute("data-focus-origin", "pointer")
+
+ // Switching to keyboard scrolling drops the marker, so the suppressing
+ // `data-[focus-origin=pointer]` selector no longer matches and the
+ // keyboard focus ring becomes visible again.
+ keyDown(viewport, "ArrowDown")
+ expect(viewport).not.toHaveAttribute("data-focus-origin")
+ expect(document.activeElement).toBe(viewport)
+ })
+
it("keeps keyboard-origin focus distinguishable", () => {
renderThread()
const viewport = screen.getByTestId("viewport")
diff --git a/src/components/message/virtualized-message-thread.tsx b/src/components/message/virtualized-message-thread.tsx
index ced6583ab..93c2a5aed 100644
--- a/src/components/message/virtualized-message-thread.tsx
+++ b/src/components/message/virtualized-message-thread.tsx
@@ -125,9 +125,16 @@ function VirtualizedMessageThreadImpl({
}
el.addEventListener("pointerdown", onPointerDown)
el.addEventListener("blur", clearPointerFocus)
+ // Once the user drives the viewport with the keyboard (Arrow/Page/Home/End
+ // to scroll), drop the pointer-origin marker so the focus ring reappears —
+ // keeping the keyboard focus indicator visible per WCAG 2.4.7. The ring is
+ // only suppressed for the mouse click that focused the viewport, not for
+ // subsequent keyboard use.
+ el.addEventListener("keydown", clearPointerFocus)
return () => {
el.removeEventListener("pointerdown", onPointerDown)
el.removeEventListener("blur", clearPointerFocus)
+ el.removeEventListener("keydown", clearPointerFocus)
clearPointerFocus()
}
}, [scrollRef])
From b87b0f99e204bddae3eb84bd84eb194bf2f0d010 Mon Sep 17 00:00:00 2001
From: xintaofei
Date: Thu, 23 Jul 2026 23:34:17 +0800
Subject: [PATCH 3/5] feat(delegation): recognize @agent mentions as explicit
delegate_to_agent requests
---
src-tauri/src/acp/delegation/tool_schema.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src-tauri/src/acp/delegation/tool_schema.json b/src-tauri/src/acp/delegation/tool_schema.json
index d40a41731..1bfe5485c 100644
--- a/src-tauri/src/acp/delegation/tool_schema.json
+++ b/src-tauri/src/acp/delegation/tool_schema.json
@@ -1,7 +1,7 @@
[
{
"name": "delegate_to_agent",
- "description": "Hand off a self-contained sub-task to a separate local AI agent that runs in its own session. ASYNCHRONOUS: returns a task_id right away and the sub-agent keeps working in the background — this call never blocks. So you can fan out several delegations at once and keep working, then collect the results with get_delegation_status by passing the task_ids array (one id to poll a single task, or many at once to poll the whole fan-out in one call) — or stop one early with cancel_delegation(task_id). The sub-agent CANNOT see this conversation, your open files, or earlier turns — it starts cold, so `task` must carry everything it needs. Best for independent, parallelizable work you can describe up front; not for steps that need your ongoing back-and-forth.",
+ "description": "Hand off a self-contained sub-task to a separate local AI agent that runs in its own session. ASYNCHRONOUS: returns a task_id right away and the sub-agent keeps working in the background — this call never blocks. So you can fan out several delegations at once and keep working, then collect the results with get_delegation_status by passing the task_ids array (one id to poll a single task, or many at once to poll the whole fan-out in one call) — or stop one early with cancel_delegation(task_id). The sub-agent CANNOT see this conversation, your open files, or earlier turns — it starts cold, so `task` must carry everything it needs. Best for independent, parallelizable work you can describe up front; not for steps that need your ongoing back-and-forth. RECOGNIZING AN EXPLICIT DELEGATION REQUEST: the user can name a sub-agent directly in their message — it appears as `@AgentName` or as a Markdown link `[@AgentName](codeg://agent/)`. Such a mention IS an explicit instruction to delegate the associated work to that agent, even when the user never names this tool. If the message names several agents, make one call per agent, each carrying that agent's slice of the work.",
"inputSchema": {
"type": "object",
"required": ["agent_type", "task"],
@@ -22,7 +22,7 @@
"grok",
"cursor"
],
- "description": "Which local agent runs the sub-task. Pick the one best suited to the work."
+ "description": "Which local agent runs the sub-task. Pick the one best suited to the work — or, when the user's message names an agent via `@AgentName` / `codeg://agent/`, use that exact `` slug (e.g. `codeg://agent/claude_code` means `claude_code`)."
},
"task": {
"type": "string",
From 2609ed560960dbba61e92cac49688ae0bd71dab9 Mon Sep 17 00:00:00 2001
From: xintaofei
Date: Fri, 24 Jul 2026 00:17:02 +0800
Subject: [PATCH 4/5] chore(acp): bump pinned agent versions
Claude Code 0.60.0 -> 0.61.0, Gemini 0.51.0 -> 0.52.0, CodeBuddy
2.125.0 -> 2.126.0, Kimi Code 0.28.1 -> 0.29.0, Grok 0.2.103 -> 0.2.111,
and Cursor 2026.07.16-899851b -> 2026.07.20-8cc9c0b.
---
src-tauri/src/acp/registry.rs | 60 +++++++++++++++++------------------
src-tauri/src/commands/acp.rs | 2 +-
2 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/src-tauri/src/acp/registry.rs b/src-tauri/src/acp/registry.rs
index f2a5c9df0..324d28cbb 100644
--- a/src-tauri/src/acp/registry.rs
+++ b/src-tauri/src/acp/registry.rs
@@ -194,8 +194,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
name: "Claude Code",
description: "ACP wrapper for Anthropic's Claude",
distribution: AgentDistribution::Npx {
- version: "0.60.0",
- package: "@agentclientprotocol/claude-agent-acp@0.60.0",
+ version: "0.61.0",
+ package: "@agentclientprotocol/claude-agent-acp@0.61.0",
cmd: "claude-agent-acp",
args: &[],
env: &[],
@@ -231,8 +231,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
name: "Gemini CLI",
description: "Google's official CLI for Gemini",
distribution: AgentDistribution::Npx {
- version: "0.51.0",
- package: "@google/gemini-cli@0.51.0",
+ version: "0.52.0",
+ package: "@google/gemini-cli@0.52.0",
cmd: "gemini",
args: &["--acp", "--skip-trust"],
env: &[],
@@ -336,8 +336,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
name: "CodeBuddy",
description: "Tencent Cloud's official AI coding assistant (ACP)",
distribution: AgentDistribution::Npx {
- version: "2.125.0",
- package: "@tencent-ai/codebuddy-code@2.125.0",
+ version: "2.126.0",
+ package: "@tencent-ai/codebuddy-code@2.126.0",
cmd: "codebuddy",
args: &["--acp"],
env: &[],
@@ -350,8 +350,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
name: "Kimi Code",
description: "Moonshot AI's official CLI coding assistant (ACP)",
distribution: AgentDistribution::Npx {
- version: "0.28.1",
- package: "@moonshot-ai/kimi-code@0.28.1",
+ version: "0.29.0",
+ package: "@moonshot-ai/kimi-code@0.29.0",
cmd: "kimi",
args: &["acp"],
env: &[],
@@ -407,8 +407,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
// leading `KEY=value` argv and sacp's `parse_env_var` only accepts
// `[A-Za-z0-9_]` env names, which npm's `@scope:registry` key is not.)
distribution: AgentDistribution::Npx {
- version: "0.2.103",
- package: "@xai-official/grok@0.2.103",
+ version: "0.2.111",
+ package: "@xai-official/grok@0.2.111",
cmd: "grok",
// Only the ACP subcommand lives here. Grok's ROOT-level launch
// flags (`--no-auto-update` always, `--permission-mode `
@@ -419,7 +419,7 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
// args rather than appending after.
args: &["agent", "stdio"],
env: &[],
- // `@xai-official/grok@0.2.103` declares `engines.node: ">=20"`;
+ // `@xai-official/grok@0.2.111` declares `engines.node: ">=20"`;
// surface that in preflight so Node 18 isn't silently accepted.
node_required: Some("20.0.0"),
},
@@ -441,34 +441,34 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
// (downloads.cursor.com/lab////...); custom
// versions substitute into the same pattern.
distribution: AgentDistribution::Binary {
- version: "2026.07.16-899851b",
+ version: "2026.07.20-8cc9c0b",
cmd: "cursor-agent",
args: &["acp"],
env: &[],
platforms: &[
PlatformBinary {
platform: "darwin-aarch64",
- url: "https://downloads.cursor.com/lab/2026.07.16-899851b/darwin/arm64/agent-cli-package.tar.gz",
+ url: "https://downloads.cursor.com/lab/2026.07.20-8cc9c0b/darwin/arm64/agent-cli-package.tar.gz",
},
PlatformBinary {
platform: "darwin-x86_64",
- url: "https://downloads.cursor.com/lab/2026.07.16-899851b/darwin/x64/agent-cli-package.tar.gz",
+ url: "https://downloads.cursor.com/lab/2026.07.20-8cc9c0b/darwin/x64/agent-cli-package.tar.gz",
},
PlatformBinary {
platform: "linux-aarch64",
- url: "https://downloads.cursor.com/lab/2026.07.16-899851b/linux/arm64/agent-cli-package.tar.gz",
+ url: "https://downloads.cursor.com/lab/2026.07.20-8cc9c0b/linux/arm64/agent-cli-package.tar.gz",
},
PlatformBinary {
platform: "linux-x86_64",
- url: "https://downloads.cursor.com/lab/2026.07.16-899851b/linux/x64/agent-cli-package.tar.gz",
+ url: "https://downloads.cursor.com/lab/2026.07.20-8cc9c0b/linux/x64/agent-cli-package.tar.gz",
},
PlatformBinary {
platform: "windows-aarch64",
- url: "https://downloads.cursor.com/lab/2026.07.16-899851b/windows/arm64/agent-cli-package.zip",
+ url: "https://downloads.cursor.com/lab/2026.07.20-8cc9c0b/windows/arm64/agent-cli-package.zip",
},
PlatformBinary {
platform: "windows-x86_64",
- url: "https://downloads.cursor.com/lab/2026.07.16-899851b/windows/x64/agent-cli-package.zip",
+ url: "https://downloads.cursor.com/lab/2026.07.20-8cc9c0b/windows/x64/agent-cli-package.zip",
},
],
dir_entry: Some(BinaryDirEntry {
@@ -572,8 +572,8 @@ mod tests {
let meta = get_agent_meta(AgentType::Cursor);
assert_binary_version(
AgentType::Cursor,
- "2026.07.16-899851b",
- "/lab/2026.07.16-899851b/",
+ "2026.07.20-8cc9c0b",
+ "/lab/2026.07.20-8cc9c0b/",
);
match meta.distribution {
AgentDistribution::Binary {
@@ -603,14 +603,14 @@ mod tests {
fn registry_pins_current_acp_agent_versions() {
assert_npx_version(
AgentType::ClaudeCode,
- "0.60.0",
- "@agentclientprotocol/claude-agent-acp@0.60.0",
+ "0.61.0",
+ "@agentclientprotocol/claude-agent-acp@0.61.0",
Some("22.0.0"),
);
assert_npx_version(
AgentType::Gemini,
- "0.51.0",
- "@google/gemini-cli@0.51.0",
+ "0.52.0",
+ "@google/gemini-cli@0.52.0",
Some("20.0.0"),
);
assert_npx_version(
@@ -627,14 +627,14 @@ mod tests {
);
assert_npx_version(
AgentType::CodeBuddy,
- "2.125.0",
- "@tencent-ai/codebuddy-code@2.125.0",
+ "2.126.0",
+ "@tencent-ai/codebuddy-code@2.126.0",
Some("22.0.0"),
);
assert_npx_version(
AgentType::KimiCode,
- "0.28.1",
- "@moonshot-ai/kimi-code@0.28.1",
+ "0.29.0",
+ "@moonshot-ai/kimi-code@0.29.0",
Some("22.19.0"),
);
assert_npx_version(
@@ -646,8 +646,8 @@ mod tests {
assert_npx_version(AgentType::Pi, "0.0.31", "pi-acp@0.0.31", Some("22.0.0"));
assert_npx_version(
AgentType::Grok,
- "0.2.103",
- "@xai-official/grok@0.2.103",
+ "0.2.111",
+ "@xai-official/grok@0.2.111",
Some("20.0.0"),
);
assert_binary_version(AgentType::OpenCode, "1.18.4", "/releases/download/v1.18.4/");
diff --git a/src-tauri/src/commands/acp.rs b/src-tauri/src/commands/acp.rs
index 166c62373..ca58260d0 100644
--- a/src-tauri/src/commands/acp.rs
+++ b/src-tauri/src/commands/acp.rs
@@ -604,7 +604,7 @@ async fn detect_local_version(agent_type: AgentType) -> Option {
}
// Dir-tree agents: a user-installed CLI (no codeg cache) still
// reports a version via ` --version` (e.g. cursor-agent →
- // "2026.07.16-899851b").
+ // "2026.07.20-8cc9c0b").
if dir_entry.is_some() {
return system_dir_agent_version(cmd).await;
}
From 692d6ebe6ecbedbb6ee4a3f8779f64b1b7a02f2c Mon Sep 17 00:00:00 2001
From: xintaofei
Date: Fri, 24 Jul 2026 00:31:50 +0800
Subject: [PATCH 5/5] # Release version 0.21.6
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- feat(git-log): **A rebuilt Commit history tab.** Virtualized and paged for long histories, with branch and author filters, a pushed/not-pushed marker on every commit, and your filter choices remembered per folder.
- feat(sidebar): **Group sessions by git worktree.** Turn on "Show worktree folders" to nest each worktree under its repo as a collapsible, branch-labelled sub-group. On by default now, alongside "Show completed."
- feat(delegation): **Mention an agent with `@` to hand it the work.** Naming a sub-agent in your message now delegates that work straight to it — one delegation per agent named.
- feat(chat): **View a diff from a reply's changed files.** Each modified file now has a View Diff button that opens its diff in an editor tab, on web and desktop.
- feat(layout): **Session stats on mobile.** The mobile status bar now shows your session stats on the left.
- fix(chat): **No more phantom tool cards after a turn ends.** Empty tool calls left by interrupted or retried turns no longer resurface and inflate the tool-group and poll cards.
- fix(messages): **The focus ring follows your keyboard, not your mouse.** Clicking a message no longer leaves a focus outline; keyboard navigation still shows one. Thanks to @youxikexue (#338).
- fix(chat): **A tidier connection indicator.** It now aligns with the send button and uses a muted colour when connected instead of a green heart.
- fix(layout): **No stray scrollbar on the branch selector.** The popup now sizes to its rows, so filtered lists have no leftover scrollbar or empty space.
- chore(acp): **Refreshed the bundled agent versions.** Claude Code 0.61.0, Gemini 0.52.0, CodeBuddy 2.126.0, Kimi Code 0.29.0, Grok 0.2.111, and Cursor 2026.07.20.
-----------------------------
# 发布版本 0.21.6
- 功能(提交历史):**重建的「提交」标签。** 虚拟化分页加载,长历史也流畅,支持按分支与作者筛选,每条提交显示是否已推送,筛选选择按文件夹分别记住。
- 功能(侧边栏):**按 git 工作树分组会话。** 打开「显示工作树文件夹」,即可把每个工作树作为可折叠、以分支命名的子分组归到所属仓库下。现与「显示已完成」一并默认开启。
- 功能(委派):**用 `@` 提及某个智能体,即可把工作交给它。** 在消息中点名子智能体,现在会直接把这部分工作委派给它——点名几个就生成几个委派。
- 功能(聊天):**在回复的变更文件上查看 diff。** 每个被修改的文件现在都带「查看 Diff」按钮,点击即在编辑器标签中打开其 diff,网页端与桌面端均可用。
- 功能(布局):**移动端显示会话统计。** 移动端状态栏现在在左侧显示你的会话统计。
- 修复(聊天):**回合结束后不再残留幽灵工具卡片。** 中断或重试回合留下的空工具调用,不再重新出现并撑大工具分组与轮询卡片。
- 修复(消息):**焦点框跟随键盘,而非鼠标。** 点击消息不再留下焦点轮廓,键盘导航时仍会显示。感谢 @youxikexue 的贡献(#338)。
- 修复(聊天):**更整洁的连接指示。** 现在与发送按钮对齐,「已连接」时改用柔和色而非绿色心形。
- 修复(布局):**分支选择器不再出现多余滚动条。** 弹层现在按其行高自适应,筛选后的列表既无残留滚动条也没有空白。
- 维护(智能体):**刷新内置的智能体版本。** Claude Code 0.61.0、Gemini 0.52.0、CodeBuddy 2.126.0、Kimi Code 0.29.0、Grok 0.2.111,以及 Cursor 2026.07.20。
---
package.json | 2 +-
src-tauri/Cargo.lock | 2 +-
src-tauri/Cargo.toml | 2 +-
src-tauri/tauri.conf.json | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/package.json b/package.json
index 4acaf3de3..00c56a2d8 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "codeg",
"private": true,
- "version": "0.21.5",
+ "version": "0.21.6",
"packageManager": "pnpm@11.9.0",
"scripts": {
"dev": "next dev --turbopack",
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index 850c7c97d..1bda9cdc9 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -1014,7 +1014,7 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "codeg"
-version = "0.21.5"
+version = "0.21.6"
dependencies = [
"aes-gcm",
"agent-client-protocol-schema",
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index fd514a82b..45304bc0f 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "codeg"
-version = "0.21.5"
+version = "0.21.6"
description = "Agent Code Generation App"
authors = ["feitao"]
edition = "2021"
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index c8fd92048..dc52db76d 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "codeg",
- "version": "0.21.5",
+ "version": "0.21.6",
"identifier": "app.codeg",
"build": {
"beforeDevCommand": "pnpm tauri:before-dev",