feat(daemon): add opencode as supported agent provider (#341)

* feat(daemon): add opencode as supported agent provider

Add opencode backend alongside claude and codex. The backend spawns
`opencode run --format json`, parses streaming JSON events (text,
tool_use, error, step_start/finish), and supports --prompt for system
prompts. Includes CLI detection, AGENTS.md runtime config, native skill
discovery via .config/opencode/skills/, and 21 tests covering handlers,
JSON parsing, and integration-level processEvents scenarios.

* chore: add .tool-versions to gitignore
This commit is contained in:
Quake Wang 2026-04-02 18:52:07 +09:00 committed by GitHub
parent 09764c5f51
commit 36db325d50
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1203 additions and 23 deletions

View file

@ -1,5 +1,5 @@
// Package agent provides a unified interface for executing prompts via
// coding agents (Claude Code, Codex). It mirrors the happy-cli AgentBackend
// coding agents (Claude Code, Codex, OpenCode). It mirrors the happy-cli AgentBackend
// pattern, translated to idiomatic Go.
package agent
@ -25,7 +25,7 @@ type ExecOptions struct {
SystemPrompt string
MaxTurns int
Timeout time.Duration
ResumeSessionID string // if non-empty, resume a previous Claude Code session
ResumeSessionID string // if non-empty, resume a previous agent session
}
// Session represents a running agent execution.
@ -73,13 +73,13 @@ type Result struct {
// Config configures a Backend instance.
type Config struct {
ExecutablePath string // path to CLI binary (claude or codex)
ExecutablePath string // path to CLI binary (claude, codex, or opencode)
Env map[string]string // extra environment variables
Logger *slog.Logger
}
// New creates a Backend for the given agent type.
// Supported types: "claude", "codex".
// Supported types: "claude", "codex", "opencode".
func New(agentType string, cfg Config) (Backend, error) {
if cfg.Logger == nil {
cfg.Logger = slog.Default()
@ -90,8 +90,10 @@ func New(agentType string, cfg Config) (Backend, error) {
return &claudeBackend{cfg: cfg}, nil
case "codex":
return &codexBackend{cfg: cfg}, nil
case "opencode":
return &opencodeBackend{cfg: cfg}, nil
default:
return nil, fmt.Errorf("unknown agent type: %q (supported: claude, codex)", agentType)
return nil, fmt.Errorf("unknown agent type: %q (supported: claude, codex, opencode)", agentType)
}
}