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
10 changes: 10 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@
This project contains the origin typescript opencode AI code assistant AND its port to golang in ./go-opencode.
Any behavior of go-opencode must match with packages/opencode server implementation.
We want to use the opencode TUI client to attach to the golang go-opencode server.


## TS Opencode

See ./packages/opencode


## Go Opencode

See ./go-opencode
2 changes: 1 addition & 1 deletion go-opencode/citest/testutil/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func StartTestServer(opts ...TestServerOption) (*TestServer, error) {
}

// Initialize tools
toolReg := tool.DefaultRegistry(workDir)
toolReg := tool.DefaultRegistry(workDir, store)

// Configure server
serverConfig := server.DefaultConfig()
Expand Down
2 changes: 1 addition & 1 deletion go-opencode/cmd/opencode/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func runInteractive(cmd *cobra.Command, args []string) error {
}

// Initialize tool registry
toolReg := tool.DefaultRegistry(workDir)
toolReg := tool.DefaultRegistry(workDir, store)

// Initialize MCP client and servers from config
var mcpClient *mcp.Client
Expand Down
2 changes: 1 addition & 1 deletion go-opencode/cmd/opencode/commands/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func runServe(cmd *cobra.Command, args []string) error {
}

// Initialize tool registry
toolReg := tool.DefaultRegistry(workDir)
toolReg := tool.DefaultRegistry(workDir, store)

// Configure server
serverConfig := server.DefaultConfig()
Expand Down
2 changes: 1 addition & 1 deletion go-opencode/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ require (

require (
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/anthropics/anthropic-sdk-go v1.4.0 // indirect
github.com/anthropics/anthropic-sdk-go v1.19.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.33.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go-opencode/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ github.com/ThreeDotsLabs/watermill v1.5.1/go.mod h1:Uop10dA3VeJWsSvis9qO3vbVY892
github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o=
github.com/anthropics/anthropic-sdk-go v1.4.0 h1:fU1jKxYbQdQDiEXCxeW5XZRIOwKevn/PMg8Ay1nnUx0=
github.com/anthropics/anthropic-sdk-go v1.4.0/go.mod h1:AapDW22irxK2PSumZiQXYUFvsdQgkwIWlpESweWZI/c=
github.com/anthropics/anthropic-sdk-go v1.19.0 h1:mO6E+ffSzLRvR/YUH9KJC0uGw0uV8GjISIuzem//3KE=
github.com/anthropics/anthropic-sdk-go v1.19.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
Expand Down
81 changes: 81 additions & 0 deletions go-opencode/internal/agent/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Package agent provides multi-agent configuration and management for opencode.
//
// This package implements a flexible agent system that supports different operation
// modes, tool access controls, and permission management. Agents can operate as
// primary agents (user-facing) or subagents (invoked by other agents).
//
// # Agent Types
//
// The package provides four built-in agents:
//
// - build: Primary agent for executing tasks, writing code, and making changes.
// Has full tool access and permissive permissions.
// - plan: Primary agent for analysis and exploration without making changes.
// Restricted to read-only operations.
// - general: Subagent for general-purpose searches and exploration.
// - explore: Fast subagent specialized for codebase exploration.
//
// # Agent Modes
//
// Agents operate in one of three modes:
//
// - ModePrimary: Can be selected as the main agent for a session
// - ModeSubagent: Can only be invoked by other agents via the Task tool
// - ModeAll: Can operate in both primary and subagent contexts
//
// # Tool Access Control
//
// Each agent has a Tools map that controls which tools are available. Tools can be
// enabled or disabled using exact names or wildcard patterns:
//
// agent.Tools = map[string]bool{
// "*": true, // Enable all tools by default
// "bash": false, // Disable bash specifically
// "mcp_*": true, // Enable all MCP tools
// }
//
// The [Agent.ToolEnabled] method checks tool availability, supporting glob patterns
// including doublestar (**) for complex matching.
//
// # Permission System
//
// Agents define permissions for sensitive operations through [AgentPermission]:
//
// - Edit: Controls file editing permissions
// - Bash: Maps command patterns to permission actions
// - WebFetch: Controls web fetching permissions
// - ExternalDir: Controls access to directories outside the project
// - DoomLoop: Controls handling of repeated failure patterns
//
// Permission actions are: allow, deny, or ask (prompt user).
//
// # Registry
//
// The [Registry] type manages agent configurations with thread-safe operations:
//
// registry := agent.NewRegistry() // Includes built-in agents
// registry.Register(customAgent) // Add custom agent
// agent, err := registry.Get("build")
// primaryAgents := registry.ListPrimary()
// subagents := registry.ListSubagents()
//
// # Custom Configuration
//
// Custom agents can be loaded from configuration using [Registry.LoadFromConfig].
// Configurations can extend or override built-in agents:
//
// config := map[string]agent.AgentConfig{
// "build": {
// Temperature: 0.7,
// Permission: &agent.AgentPermissionConfig{
// Edit: permission.ActionAsk,
// },
// },
// "custom": {
// Description: "Custom agent",
// Mode: agent.ModePrimary,
// Tools: map[string]bool{"read": true, "glob": true},
// },
// }
// registry.LoadFromConfig(config)
package agent
16 changes: 8 additions & 8 deletions go-opencode/internal/clienttool/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (r *Registry) Register(clientID string, tools []ToolDefinition) []string {
}

// Publish event
event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolRegistered,
Data: event.ClientToolRegisteredData{
ClientID: clientID,
Expand Down Expand Up @@ -154,7 +154,7 @@ func (r *Registry) Unregister(clientID string, toolIDs []string) []string {
}

if len(unregistered) > 0 {
event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolUnregistered,
Data: event.ClientToolUnregisteredData{
ClientID: clientID,
Expand Down Expand Up @@ -231,15 +231,15 @@ func (r *Registry) Execute(ctx context.Context, clientID string, req ExecutionRe
r.mu.Unlock()

// Publish event for SSE clients
event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolRequest,
Data: event.ClientToolRequestData{
ClientID: clientID,
Request: req,
},
})

event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolExecuting,
Data: event.ClientToolStatusData{
SessionID: req.SessionID,
Expand All @@ -259,7 +259,7 @@ func (r *Registry) Execute(ctx context.Context, clientID string, req ExecutionRe
r.mu.Unlock()

if resp.Status == "error" {
event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolFailed,
Data: event.ClientToolStatusData{
SessionID: req.SessionID,
Expand All @@ -273,7 +273,7 @@ func (r *Registry) Execute(ctx context.Context, clientID string, req ExecutionRe
return nil, errors.New(resp.Error)
}

event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolCompleted,
Data: event.ClientToolStatusData{
SessionID: req.SessionID,
Expand All @@ -297,7 +297,7 @@ func (r *Registry) Execute(ctx context.Context, clientID string, req ExecutionRe
delete(r.pending, req.RequestID)
r.mu.Unlock()

event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolFailed,
Data: event.ClientToolStatusData{
SessionID: req.SessionID,
Expand Down Expand Up @@ -371,7 +371,7 @@ func (r *Registry) Cleanup(clientID string) {
delete(r.tools, clientID)

if len(toolIDs) > 0 {
event.Publish(event.Event{
event.PublishSync(event.Event{
Type: event.ClientToolUnregistered,
Data: event.ClientToolUnregisteredData{
ClientID: clientID,
Expand Down
101 changes: 101 additions & 0 deletions go-opencode/internal/command/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Package command provides a flexible command execution system for OpenCode.
//
// This package implements a custom command system that allows users to define
// and execute templated commands with variable substitution. Commands can be
// defined in configuration files or as markdown files in the .opencode/command
// directory.
//
// # Command Sources
//
// Commands can be loaded from two sources:
//
// 1. Configuration files: Commands defined in the OpenCode configuration
// 2. Markdown files: Commands stored as .md files in .opencode/command/
//
// # Command Structure
//
// Each command consists of:
// - Name: Unique identifier for the command
// - Description: Human-readable description of what the command does
// - Template: The template string that will be executed with variable substitution
// - Agent: Optional agent to use for execution
// - Model: Optional model to use for execution
// - Subtask: Whether this command represents a subtask
//
// # Template System
//
// Commands use Go templates with additional support for simple variable substitution:
//
// - ${variable} syntax for variable expansion
// - $variable syntax for simple variable references
// - $1, $2, ... for positional arguments
// - $input for the full input string
// - --name=value or --name value for named arguments
//
// # Template Context
//
// Templates have access to:
// - args: Map of parsed arguments
// - input: The raw input string
// - vars: Configured prompt variables
// - env: Environment variables
// - workDir: Current working directory
// - Custom template functions (env, default, trim, upper, lower, etc.)
//
// # Markdown Command Format
//
// Markdown commands can include YAML frontmatter:
//
// ---
// description: Run tests
// agent: test-agent
// model: claude-3
// subtask: true
// ---
// Run tests for ${1} package
//
// # Built-in Commands
//
// The package provides several built-in commands:
// - help: Show available commands and help information
// - clear: Clear the current conversation
// - compact: Compact the conversation to save context
// - reset: Reset the session to its initial state
// - undo: Undo the last message
// - share: Share the current session
// - export: Export the conversation
//
// # Example Usage
//
// // Create executor
// executor := NewExecutor("/path/to/work/dir", config)
//
// // Execute a command
// result, err := executor.Execute(ctx, "greet", "World")
// if err != nil {
// log.Fatal(err)
// }
//
// // Use the generated prompt
// fmt.Println(result.Prompt) // "Hello, World!"
//
// # Dynamic Command Management
//
// Commands can be managed at runtime:
//
// // Add a new command
// executor.AddCommand(&Command{
// Name: "custom",
// Template: "Custom command with $1",
// })
//
// // Remove a command
// executor.RemoveCommand("custom")
//
// // Reload all commands
// executor.Reload()
//
// The command system is designed to be flexible and extensible, supporting
// both simple string substitution and complex Go template logic while
// maintaining ease of use for end users.
package command
Loading
Loading