Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "codeg",
"private": true,
"version": "0.22.1",
"version": "0.22.2",
"packageManager": "pnpm@11.9.0",
"scripts": {
"dev": "next dev --turbopack",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "codeg"
version = "0.22.1"
version = "0.22.2"
description = "Agent Code Generation App"
authors = ["feitao"]
edition = "2021"
Expand Down
49 changes: 45 additions & 4 deletions src-tauri/src/acp/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6571,10 +6571,12 @@ pub(crate) fn json_value_to_text(val: &Option<serde_json::Value>) -> Option<Stri
///
/// Mirror the history parser (`parsers/grok.rs::update_tool_output`): prefer the
/// already-serialized `content`, and only fall back — when `content` is empty —
/// to the object's string `output_for_prompt` (Bash/terminal) or, for an MCP
/// `rawOutput`, the text under `output` (see grok_mcp_output_text). Returning
/// `None` lets the frontend render `content`. Never emit the object blob.
/// Non-object / absent / unrecognized `rawOutput` → `None`.
/// to the object's string `output_for_prompt` (Bash/terminal), a background-task
/// `TaskOutput` envelope (see `parsers::grok::grok_task_output_envelope`, the
/// one exception to "never emit the object blob": the frontend parses it into a
/// background-task card), or, for an MCP `rawOutput`, the text under `output`
/// (see grok_mcp_output_text). Returning `None` lets the frontend render
/// `content`. Non-object / absent / unrecognized `rawOutput` → `None`.
///
/// Note: `content` here is `serialize_tool_call_content`, which for a Grok
/// terminal call is the plain text block (verified against real `~/.grok`
Expand All @@ -6599,6 +6601,13 @@ fn grok_live_tool_output(
{
return Some(text.to_string());
}
// Background-task polls (`get_command_or_subagent_output`): the command,
// exit code and shell text all live under the `TaskOutput` envelope, which
// matches none of the paths around it — without this the card streams empty.
// Shared with the history parser so both hand the frontend the same string.
if let Some(envelope) = crate::parsers::grok::grok_task_output_envelope(raw) {
return Some(envelope);
}
// MCP calls (Grok's `use_tool` envelope): the result text lives under
// `output.<*Output>` instead (see grok_mcp_output_text). Without this a
// finished MCP call — e.g. the `delegate_to_agent` ack carrying
Expand Down Expand Up @@ -9328,6 +9337,38 @@ mod tests {
);
}

/// A `get_command_or_subagent_output` poll has no `content[]` and no
/// `output_for_prompt` — its whole result sits under the `TaskOutput`
/// envelope, which used to be dropped, streaming an empty card. Live must
/// emit the SAME string the history parser stores so the background-task
/// card renders identically before and after a reload.
#[test]
fn grok_live_tool_output_emits_task_output_envelope() {
let raw = serde_json::json!({
"type": "TaskOutput",
"Result": {
"task_id": "term_b0d",
"command": "/bin/bash -lc 'pnpm dev'",
"status": "failed",
"exit_code": 1,
"output": "boom",
},
});
let live = grok_live_tool_output(&None, &Some(raw.clone())).expect("envelope emitted");
assert_eq!(
live,
crate::parsers::grok::grok_task_output_envelope(&raw).unwrap(),
"live and history must hand the frontend the same string"
);
let parsed: serde_json::Value = serde_json::from_str(&live).unwrap();
assert_eq!(parsed["Result"]["exit_code"], 1);
// A poll that DOES carry clean content keeps content's precedence.
assert_eq!(
grok_live_tool_output(&Some("已完成".to_string()), &Some(raw)),
None
);
}

#[test]
fn grok_live_tool_output_none_without_usable_string() {
// Object without `output_for_prompt` (only the byte-array `output`).
Expand Down
50 changes: 25 additions & 25 deletions src-tauri/src/acp/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
name: "Cline",
description: "Autonomous coding agent CLI",
distribution: AgentDistribution::Npx {
version: "3.0.46",
package: "cline@3.0.46",
version: "3.0.47",
package: "cline@3.0.47",
cmd: "cline",
args: &["--acp"],
env: &[],
Expand All @@ -343,39 +343,39 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
name: "OpenCode",
description: "The open source coding agent",
distribution: AgentDistribution::Binary {
version: "1.18.8",
version: "1.18.10",
cmd: "opencode",
args: &["acp"],
env: &[],
platforms: &[
PlatformBinary {
platform: "darwin-aarch64",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.8/opencode-darwin-arm64.zip",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.10/opencode-darwin-arm64.zip",
sha256: None,
},
PlatformBinary {
platform: "darwin-x86_64",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.8/opencode-darwin-x64.zip",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.10/opencode-darwin-x64.zip",
sha256: None,
},
PlatformBinary {
platform: "linux-aarch64",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.8/opencode-linux-arm64.tar.gz",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.10/opencode-linux-arm64.tar.gz",
sha256: None,
},
PlatformBinary {
platform: "linux-x86_64",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.8/opencode-linux-x64.tar.gz",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.10/opencode-linux-x64.tar.gz",
sha256: None,
},
PlatformBinary {
platform: "windows-aarch64",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.8/opencode-windows-arm64.zip",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.10/opencode-windows-arm64.zip",
sha256: None,
},
PlatformBinary {
platform: "windows-x86_64",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.8/opencode-windows-x64.zip",
url: "https://github.com/anomalyco/opencode/releases/download/v1.18.10/opencode-windows-x64.zip",
sha256: None,
},
],
Expand Down Expand Up @@ -410,8 +410,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.128.0",
package: "@tencent-ai/codebuddy-code@2.128.0",
version: "2.130.0",
package: "@tencent-ai/codebuddy-code@2.130.0",
cmd: "codebuddy",
args: &["--acp"],
env: &[],
Expand All @@ -424,8 +424,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.29.2",
package: "@moonshot-ai/kimi-code@0.29.2",
version: "0.31.0",
package: "@moonshot-ai/kimi-code@0.31.0",
cmd: "kimi",
args: &["acp"],
env: &[],
Expand Down Expand Up @@ -481,8 +481,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.112",
package: "@xai-official/grok@0.2.112",
version: "0.2.114",
package: "@xai-official/grok@0.2.114",
cmd: "grok",
// Only the ACP subcommand lives here. Grok's ROOT-level launch
// flags (`--no-auto-update` always, `--permission-mode <value>`
Expand All @@ -493,7 +493,7 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
// args rather than appending after.
args: &["agent", "stdio"],
env: &[],
// `@xai-official/grok@0.2.112` declares `engines.node: ">=20"`;
// `@xai-official/grok@0.2.114` declares `engines.node: ">=20"`;
// surface that in preflight so Node 18 isn't silently accepted.
node_required: Some("20.0.0"),
},
Expand Down Expand Up @@ -704,20 +704,20 @@ mod tests {
);
assert_npx_version(
AgentType::Cline,
"3.0.46",
"cline@3.0.46",
"3.0.47",
"cline@3.0.47",
Some("22.0.0"),
);
assert_npx_version(
AgentType::CodeBuddy,
"2.128.0",
"@tencent-ai/codebuddy-code@2.128.0",
"2.130.0",
"@tencent-ai/codebuddy-code@2.130.0",
Some("22.0.0"),
);
assert_npx_version(
AgentType::KimiCode,
"0.29.2",
"@moonshot-ai/kimi-code@0.29.2",
"0.31.0",
"@moonshot-ai/kimi-code@0.31.0",
Some("22.19.0"),
);
assert_npx_version(
Expand All @@ -729,11 +729,11 @@ mod tests {
assert_npx_version(AgentType::Pi, "0.0.32", "pi-acp@0.0.32", Some("22.0.0"));
assert_npx_version(
AgentType::Grok,
"0.2.112",
"@xai-official/grok@0.2.112",
"0.2.114",
"@xai-official/grok@0.2.114",
Some("20.0.0"),
);
assert_binary_version(AgentType::OpenCode, "1.18.8", "/releases/download/v1.18.8/");
assert_binary_version(AgentType::OpenCode, "1.18.10", "/releases/download/v1.18.10/");
assert_uvx_version(
AgentType::Hermes,
"0.19.0",
Expand Down
Loading
Loading