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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ It aggregates your sessions from every supported agent CLI into one searchable w

## 🤖 Supported Agents

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

Codeg installs, pins, and updates most of them for you. See [Supported Agents](https://docs.codeg.app/guide/supported-agents) for the full roster, each agent's runtime requirements, and where it keeps its sessions on disk.

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.ar.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Codeg (Code Generation) هو مساحة عمل برمجية متعددة الو

## 🤖 الوكلاء المدعومون

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

يتولّى Codeg تثبيت معظمهم وتثبيت إصداراتهم وتحديثهم نيابةً عنك. راجع [الوكلاء المدعومون](https://docs.codeg.app/guide/supported-agents) للقائمة الكاملة، ومتطلبات تشغيل كل وكيل، وموضع حفظ جلساته على القرص.

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Codeg bündelt die Sitzungen aller unterstützten Agenten-CLIs in einem durchsuc

## 🤖 Unterstützte Agenten

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

Die meisten davon installiert, fixiert und aktualisiert Codeg für dich. Die vollständige Liste, die Laufzeit-Anforderungen jedes Agenten und den Ablageort seiner Sitzungen findest du unter [Unterstützte Agenten](https://docs.codeg.app/guide/supported-agents).

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Reúne las sesiones de todas las CLI de agentes compatibles en un único espacio

## 🤖 Agentes compatibles

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

Codeg instala, fija la versión y actualiza la mayoría de ellos por ti. Consulta [Agentes compatibles](https://docs.codeg.app/guide/supported-agents) para ver la lista completa, los requisitos de ejecución de cada uno y dónde guarda sus sesiones en disco.

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Il regroupe les sessions de toutes les CLI d'agents supportées dans un espace d

## 🤖 Agents supportés

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

Codeg installe, épingle et met à jour la plupart d'entre eux pour vous. Voir [Agents supportés](https://docs.codeg.app/guide/supported-agents) pour la liste complète, les prérequis d'exécution de chacun et l'emplacement de ses sessions sur le disque.

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Codeg(Code Generation)はマルチエージェント・コーディングワ

## 🤖 対応エージェント

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

その多くは Codeg がインストール・バージョン固定・更新まで面倒を見ます。全リスト、各エージェントの実行環境要件、セッションの保存場所は [対応エージェント](https://docs.codeg.app/guide/supported-agents) を参照してください。

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Codeg(Code Generation)는 멀티 에이전트 코딩 워크스페이스입니다

## 🤖 지원 에이전트

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

이 중 대부분은 Codeg가 대신 설치하고, 버전을 고정하고, 업데이트합니다. 전체 목록과 각 에이전트의 실행 환경 요구 사항, 세션이 디스크에 저장되는 위치는 [지원 에이전트](https://docs.codeg.app/guide/supported-agents)를 참고하세요.

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.pt.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Ele agrega as sessões de todas as CLIs de agentes suportadas em um único espa

## 🤖 Agentes suportados

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

O Codeg instala, fixa a versão e atualiza a maioria deles por você. Veja [Agentes suportados](https://docs.codeg.app/guide/supported-agents) para a lista completa, os requisitos de execução de cada um e onde ele guarda as sessões em disco.

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Codeg(Code Generation)是一个多智能体编码工作台:把所有 AI

## 🤖 支持的 Agent

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

其中大部分 Codeg 都能替你安装、锁定版本并更新。完整名单、各自的运行环境要求以及会话在磁盘上的存放位置,见 [支持的智能体](https://docs.codeg.app/zh/guide/supported-agents)。

Expand Down
2 changes: 1 addition & 1 deletion docs/readme/README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Codeg(Code Generation)是一個多智慧體編碼工作台:把所有 AI

## 🤖 支援的 Agent

Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness
Claude Code · Codex · Gemini · OpenClaw · OpenCode · Cline · Hermes · CodeBuddy · Kimi Code · Pi · Grok · Cursor · DeepSeek Harness · Qoder

其中大部分 Codeg 都能替你安裝、鎖定版本並更新。完整名單、各自的執行環境需求以及工作階段在磁碟上的存放位置,見 [支援的智慧體](https://docs.codeg.app/zh/guide/supported-agents)。

Expand Down
11 changes: 10 additions & 1 deletion src-tauri/src/acp/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3314,9 +3314,18 @@ fn load_mcp_servers_for_agent(agent_type: AgentType) -> Vec<McpServer> {
// DeepSeek is deliberately NOT in this set: deepseek-acp reads no MCP file
// at all, so `$DSH_HOME/mcp.json` (codeg's own store) reaches it ONLY
// through the wire — skipping it would silently drop every user server.
//
// Qoder joins the skip set: the CLI reads `mcpServers` out of its own
// `~/.qoder/settings.json` (gemini-schema settings file) at startup, which
// codeg's MCP settings UI manages directly — forwarding the same servers
// over the wire would double-mount them.
if matches!(
agent_type,
AgentType::Hermes | AgentType::KimiCode | AgentType::Grok | AgentType::Cursor
AgentType::Hermes
| AgentType::KimiCode
| AgentType::Grok
| AgentType::Cursor
| AgentType::Qoder
) {
return Vec::new();
}
Expand Down
6 changes: 3 additions & 3 deletions src-tauri/src/acp/custom_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,11 +969,11 @@ mod tests {
// A custom definition must not claim a BUILT-IN registry id: it would be
// shadowed by `from_registry_id`'s built-in arms and double-listed by
// `all_acp_agents`. This is also the hydration path that retires a
// pre-integration `deepseek-acp` custom entry (kept in the DB, never
// published) once the id became a built-in.
// pre-integration `deepseek-acp` / `qoder-cli` custom entry (kept in the
// DB, never published) once the id became a built-in.
#[test]
fn rejects_builtin_registry_id_collisions() {
for id in ["deepseek-acp", "claude-acp", "cursor"] {
for id in ["deepseek-acp", "qoder-cli", "claude-acp", "cursor"] {
assert_eq!(
validate(&npx_def(id)),
Err(CustomAgentError::CollidesWithBuiltin(id.to_string())),
Expand Down
17 changes: 9 additions & 8 deletions src-tauri/src/acp/delegation/companion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1597,14 +1597,15 @@ mod tests {
let agents = delegate["inputSchema"]["properties"]["agent_type"]["enum"]
.as_array()
.unwrap();
assert_eq!(agents.len(), 13);
assert_eq!(agents.len(), 14);
assert!(agents.iter().any(|a| a == "hermes"));
assert!(agents.iter().any(|a| a == "code_buddy"));
assert!(agents.iter().any(|a| a == "kimi_code"));
assert!(agents.iter().any(|a| a == "pi"));
assert!(agents.iter().any(|a| a == "grok"));
assert!(agents.iter().any(|a| a == "cursor"));
assert!(agents.iter().any(|a| a == "deepseek"));
assert!(agents.iter().any(|a| a == "qoder"));
// get_delegation_status takes a single id param — task_ids (required) —
// plus wait_ms. The legacy single `task_id` param is gone.
let status = tools
Expand Down Expand Up @@ -1644,11 +1645,11 @@ mod tests {
.as_array()
.unwrap()
.clone();
assert_eq!(agents.len(), 15, "13 builtins + 2 distinct customs");
assert_eq!(agents.len(), 16, "14 builtins + 2 distinct customs");
// Builtins keep the embedded order and come first.
assert_eq!(agents[0], "claude_code");
assert_eq!(agents[13], "custom:goose");
assert_eq!(agents[14], "custom:amp");
assert_eq!(agents[14], "custom:goose");
assert_eq!(agents[15], "custom:amp");
// The other delegation tools carry no agent_type and are untouched.
let status = tools
.as_array()
Expand Down Expand Up @@ -1683,13 +1684,13 @@ mod tests {
.as_array()
.unwrap()
.clone();
assert_eq!(agents.len(), 12, "13 builtins - 2 disabled + 1 custom");
assert_eq!(agents.len(), 13, "14 builtins - 2 disabled + 1 custom");
assert!(!agents.contains(&serde_json::json!("codex")));
assert!(!agents.contains(&serde_json::json!("grok")));
// Survivors keep the embedded order, customs still come last.
assert_eq!(agents[0], "claude_code");
assert_eq!(agents[1], "open_code");
assert_eq!(agents[11], "custom:goose");
assert_eq!(agents[12], "custom:goose");
}

// An empty disabled list (the parent omitted `--disabled-agents`) leaves
Expand All @@ -1711,9 +1712,9 @@ mod tests {
.as_array()
.unwrap()
.clone();
assert_eq!(agents.len(), 13);
assert_eq!(agents.len(), 14);
assert_eq!(agents[0], "claude_code");
assert_eq!(agents[12], "deepseek");
assert_eq!(agents[13], "qoder");
}

#[tokio::test]
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/src/acp/delegation/tool_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"pi",
"grok",
"cursor",
"deepseek"
"deepseek",
"qoder"
],
"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/<agent_type>`, use that exact `<agent_type>` slug (e.g. `codeg://agent/claude_code` means `claude_code`)."
},
Expand Down
8 changes: 8 additions & 0 deletions src-tauri/src/acp/file_system_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,14 @@ fn agent_root_slots(agent_type: AgentType) -> &'static [RootSlot] {
trims: false,
default_rel: &[".grok"],
}],
// Qoder relocates its whole home via `QODER_CONFIG_DIR` (the env form
// of the CLI's `--config-dir`); the sessions tree lives under
// `projects/` inside it.
AgentType::Qoder => &[RootSlot {
candidates: &[("QODER_CONFIG_DIR", "")],
trims: false,
default_rel: &[".qoder"],
}],
AgentType::ClaudeCode => &[RootSlot {
candidates: &[("CLAUDE_CONFIG_DIR", "")],
trims: false,
Expand Down
45 changes: 43 additions & 2 deletions src-tauri/src/acp/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub fn current_platform() -> &'static str {
}
}

/// The thirteen built-in agents. Excludes user-registered custom agents — use
/// The fourteen built-in agents. Excludes user-registered custom agents — use
/// [`all_acp_agents`] for the live set.
pub fn builtin_acp_agents() -> Vec<AgentType> {
vec![
Expand All @@ -155,10 +155,11 @@ pub fn builtin_acp_agents() -> Vec<AgentType> {
AgentType::Grok,
AgentType::Cursor,
AgentType::DeepSeek,
AgentType::Qoder,
]
}

/// Every agent codeg can currently drive: the thirteen built-ins followed by
/// Every agent codeg can currently drive: the fourteen built-ins followed by
/// the user's registered custom ACP agents (sorted by id).
pub fn all_acp_agents() -> Vec<AgentType> {
let mut agents = builtin_acp_agents();
Expand All @@ -181,6 +182,7 @@ pub fn registry_id_for(agent_type: AgentType) -> &'static str {
AgentType::Grok => "grok-build",
AgentType::Cursor => "cursor",
AgentType::DeepSeek => "deepseek-acp",
AgentType::Qoder => "qoder-cli",
// A custom agent's registry id IS its identity.
AgentType::Custom(id) => id,
}
Expand All @@ -201,6 +203,7 @@ pub fn from_registry_id(id: &str) -> Option<AgentType> {
"grok-build" => Some(AgentType::Grok),
"cursor" => Some(AgentType::Cursor),
"deepseek-acp" => Some(AgentType::DeepSeek),
"qoder-cli" => Some(AgentType::Qoder),
// Only ids the user has actually registered resolve. An unregistered
// id must stay `None` so the ACP-registry picker still offers it as
// "addable" rather than treating it as already supported.
Expand Down Expand Up @@ -931,6 +934,38 @@ pub fn get_agent_meta(agent_type: AgentType) -> AcpAgentMeta {
node_required: Some("22.0.0"),
},
},
AgentType::Qoder => AcpAgentMeta {
agent_type,
supports_mcp: true,
name: "Qoder",
description: "Alibaba's Qoder coding agent CLI (native ACP via --acp)",
// `qoder --acp` is the CLI's OWN first-party ACP server (not a
// community bridge): verified handshake advertises `loadSession`
// plus the full `sessionCapabilities` set (list/resume/fork/close/
// delete/additionalDirectories), image + embeddedContext prompts,
// and MCP http+sse — so the resume rung and the codeg-mcp
// companion work with no adapters in between. Auth is the qoder
// account (`qoder login`, or the IDE's qoder-browser flow); there
// is no API-key env to manage. Model, mode (default/acceptEdits/
// bypassPermissions/plan) and reasoning effort arrive through
// standard `configOptions`, so the composer selectors need no
// per-agent code. Session logs land as
// `$QODER_CONFIG_DIR/projects/<encoded-cwd>/<sessionId>.jsonl`
// (default `~/.qoder/...`) in the Claude-Code-style chunk-log
// envelope, which `parsers::qoder` reads for history. The sibling
// `<sessionId>/state.json` keeps its titles ENCRYPTED (AES-GCM
// under the machine key), so the parser derives titles from the
// plaintext transcript instead. `engines.node: ">=20"`.
distribution: AgentDistribution::Npx {
version: "1.1.23",
package: "@qoder-ai/qodercli@1.1.23",
cmd: "qoder",
args: &["--acp"],
env: &[],
// package.json declares `engines.node: ">=20.0.0"`.
node_required: Some("20.0.0"),
},
},
// Handled by the early return above; kept so the match stays
// exhaustive without a catch-all that could swallow a new built-in.
AgentType::Custom(_) => unreachable!("custom agents resolve via custom_registry"),
Expand Down Expand Up @@ -1130,6 +1165,12 @@ mod tests {
"deepseek-acp@0.3.0",
Some("22.0.0"),
);
assert_npx_version(
AgentType::Qoder,
"1.1.23",
"@qoder-ai/qodercli@1.1.23",
Some("20.0.0"),
);
assert_binary_version(AgentType::OpenCode, "1.18.18", "/releases/download/v1.18.18/");
// Hermes rides the community npm bridge (upstream retired its PyPI
// channel at 0.19.0; see the registry entry). The npm package version
Expand Down
25 changes: 25 additions & 0 deletions src-tauri/src/commands/acp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7671,6 +7671,18 @@ pub(crate) fn skill_storage_spec(agent_type: AgentType) -> Option<SkillStorageSp
],
project_rel_dirs: vec![".dsh/skills", ".agents/skills"],
}),
// Qoder's skill filesystem (verified against the 1.1.23 bundle)
// discovers directory bundles only — `<id>/SKILL.md`; it never scans
// flat `<id>.md` files, hence Claude's spec shape rather than Codex's.
// Its roots: `~/.agents/skills` (home scope) and, per workspace, both
// `<project>/skills` and `<workdir>/.agents/skills`. There is NO
// qoder-owned home skills dir — the home root is the shared
// `.agents` store other agents already use.
AgentType::Qoder => Some(SkillStorageSpec {
kind: SkillStorageKind::SkillDirectoryOnly,
global_dirs: vec![home_dir_or_default().join(".agents").join("skills")],
project_rel_dirs: vec!["skills", ".agents/skills"],
}),
// codeg cannot detect where an arbitrary ACP agent loads skills from,
// so custom agents are gated on the user's own declaration: that the
// agent reads the shared `.agents/skills` store (the cross-agent
Expand Down Expand Up @@ -8564,6 +8576,13 @@ fn agent_env_keys(agent_type: AgentType) -> (&'static str, &'static str, &'stati
"DEEPSEEK_API_KEY",
"DEEPSEEK_ACP_MODEL",
),
// Qoder authenticates as the qoder ACCOUNT (`qoder login` / the IDE's
// qoder-browser flow; credentials live in the machine key store, not
// the environment) and has no endpoint override, so none of the three
// slots is real. They stay as inert `QODER_*` placeholders so the
// generic cascade never lands on the OPENAI_* keys; model selection
// flows through the ACP `configOptions` selectors instead.
AgentType::Qoder => ("QODER_BASE_URL", "QODER_API_KEY", "QODER_MODEL"),
_ => ("OPENAI_BASE_URL", "OPENAI_API_KEY", "OPENAI_MODEL"),
}
}
Expand Down Expand Up @@ -8987,6 +9006,12 @@ fn cascade_update_agent_config(
// it has no codeg-managed config file and does not participate in
// the model-provider credential cascade.
}
AgentType::Qoder => {
// Qoder authenticates as the qoder account (`qoder login` / the
// IDE's qoder-browser flow); the credential lives in qoder's own
// machine-key store, not in any env or file codeg manages, so it
// does not participate in the model-provider credential cascade.
}
AgentType::Custom(_) => {
// Custom agents are deliberately configuration-free: codeg writes
// no config file for them and they are excluded from the
Expand Down
Loading
Loading