Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.

Commit bbfa60c

Browse files
committed
reimplement agent,provider and add file history
1 parent 76b4065 commit bbfa60c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3595
-3879
lines changed

.opencode.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
{
2-
"model": {
3-
"coder": "claude-3.7-sonnet",
4-
"coderMaxTokens": 20000
5-
},
62
"lsp": {
73
"gopls": {
84
"command": "gopls"

README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# TermAI
1+
# OpenCode
22

33
> **⚠️ Early Development Notice:** This project is in early development and is not yet ready for production use. Features may change, break, or be incomplete. Use at your own risk.
44
55
A powerful terminal-based AI assistant for developers, providing intelligent coding assistance directly in your terminal.
66

7-
[![TermAI Demo](https://asciinema.org/a/dtc4nJyGSZX79HRUmFLY3gmoy.svg)](https://asciinema.org/a/dtc4nJyGSZX79HRUmFLY3gmoy)
7+
[![OpenCode Demo](https://asciinema.org/a/dtc4nJyGSZX79HRUmFLY3gmoy.svg)](https://asciinema.org/a/dtc4nJyGSZX79HRUmFLY3gmoy)
88

99
## Overview
1010

11-
TermAI is a Go-based CLI application that brings AI assistance to your terminal. It provides a TUI (Terminal User Interface) for interacting with various AI models to help with coding tasks, debugging, and more.
11+
OpenCode is a Go-based CLI application that brings AI assistance to your terminal. It provides a TUI (Terminal User Interface) for interacting with various AI models to help with coding tasks, debugging, and more.
1212

1313
## Features
1414

@@ -23,16 +23,16 @@ TermAI is a Go-based CLI application that brings AI assistance to your terminal.
2323

2424
```bash
2525
# Coming soon
26-
go install github.com/kujtimiihoxha/termai@latest
26+
go install github.com/kujtimiihoxha/opencode@latest
2727
```
2828

2929
## Configuration
3030

31-
TermAI looks for configuration in the following locations:
31+
OpenCode looks for configuration in the following locations:
3232

33-
- `$HOME/.termai.json`
34-
- `$XDG_CONFIG_HOME/termai/.termai.json`
35-
- `./.termai.json` (local directory)
33+
- `$HOME/.opencode.json`
34+
- `$XDG_CONFIG_HOME/opencode/.opencode.json`
35+
- `./.opencode.json` (local directory)
3636

3737
You can also use environment variables:
3838

@@ -43,11 +43,11 @@ You can also use environment variables:
4343
## Usage
4444

4545
```bash
46-
# Start TermAI
47-
termai
46+
# Start OpenCode
47+
opencode
4848

4949
# Start with debug logging
50-
termai -d
50+
opencode -d
5151
```
5252

5353
### Keyboard Shortcuts
@@ -81,7 +81,7 @@ termai -d
8181

8282
## Architecture
8383

84-
TermAI is built with a modular architecture:
84+
OpenCode is built with a modular architecture:
8585

8686
- **cmd**: Command-line interface using Cobra
8787
- **internal/app**: Core application services
@@ -103,22 +103,22 @@ TermAI is built with a modular architecture:
103103

104104
```bash
105105
# Clone the repository
106-
git clone https://github.com/kujtimiihoxha/termai.git
107-
cd termai
106+
git clone https://github.com/kujtimiihoxha/opencode.git
107+
cd opencode
108108

109109
# Build the diff script first
110110
go run cmd/diff/main.go
111111

112112
# Build
113-
go build -o termai
113+
go build -o opencode
114114

115115
# Run
116-
./termai
116+
./opencode
117117
```
118118

119119
## Acknowledgments
120120

121-
TermAI builds upon the work of several open source projects and developers:
121+
OpenCode builds upon the work of several open source projects and developers:
122122

123123
- [@isaacphi](https://github.com/isaacphi) - LSP client implementation
124124

cmd/root.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
)
2121

2222
var rootCmd = &cobra.Command{
23-
Use: "termai",
23+
Use: "OpenCode",
2424
Short: "A terminal ai assistant",
2525
Long: `A terminal ai assistant`,
2626
RunE: func(cmd *cobra.Command, args []string) error {
@@ -89,12 +89,9 @@ var rootCmd = &cobra.Command{
8989
// Set up message handling for the TUI
9090
go func() {
9191
defer tuiWg.Done()
92-
defer func() {
93-
if r := recover(); r != nil {
94-
logging.Error("Panic in TUI message handling: %v", r)
95-
attemptTUIRecovery(program)
96-
}
97-
}()
92+
defer logging.RecoverPanic("TUI-message-handler", func() {
93+
attemptTUIRecovery(program)
94+
})
9895

9996
for {
10097
select {
@@ -153,11 +150,7 @@ func attemptTUIRecovery(program *tea.Program) {
153150

154151
func initMCPTools(ctx context.Context, app *app.App) {
155152
go func() {
156-
defer func() {
157-
if r := recover(); r != nil {
158-
logging.Error("Panic in MCP goroutine: %v", r)
159-
}
160-
}()
153+
defer logging.RecoverPanic("MCP-goroutine", nil)
161154

162155
// Create a context with timeout for the initial MCP tools fetch
163156
ctxWithTimeout, cancel := context.WithTimeout(ctx, 30*time.Second)
@@ -179,11 +172,7 @@ func setupSubscriber[T any](
179172
wg.Add(1)
180173
go func() {
181174
defer wg.Done()
182-
defer func() {
183-
if r := recover(); r != nil {
184-
logging.Error("Panic in %s subscription goroutine: %v", name, r)
185-
}
186-
}()
175+
defer logging.RecoverPanic(fmt.Sprintf("subscription-%s", name), nil)
187176

188177
for {
189178
select {
@@ -232,6 +221,7 @@ func setupSubscriptions(app *app.App) (chan tea.Msg, func()) {
232221
// Wait with a timeout for all goroutines to complete
233222
waitCh := make(chan struct{})
234223
go func() {
224+
defer logging.RecoverPanic("subscription-cleanup", nil)
235225
wg.Wait()
236226
close(waitCh)
237227
}()

go.mod

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ require (
2323
github.com/golang-migrate/migrate/v4 v4.18.2
2424
github.com/google/generative-ai-go v0.19.0
2525
github.com/google/uuid v1.6.0
26-
github.com/kujtimiihoxha/vimtea v0.0.3-0.20250329221256-a250e98498f9
2726
github.com/lrstanley/bubblezone v0.0.0-20250315020633-c249a3fe1231
2827
github.com/mark3labs/mcp-go v0.17.0
2928
github.com/mattn/go-runewidth v0.0.16
@@ -36,7 +35,6 @@ require (
3635
github.com/spf13/cobra v1.9.1
3736
github.com/spf13/viper v1.20.0
3837
github.com/stretchr/testify v1.10.0
39-
golang.org/x/net v0.39.0
4038
google.golang.org/api v0.215.0
4139
)
4240

@@ -106,7 +104,6 @@ require (
106104
github.com/pmezard/go-difflib v1.0.0 // indirect
107105
github.com/rivo/uniseg v0.4.7 // indirect
108106
github.com/sagikazarmark/locafero v0.7.0 // indirect
109-
github.com/sahilm/fuzzy v0.1.1 // indirect
110107
github.com/skeema/knownhosts v1.3.1 // indirect
111108
github.com/sourcegraph/conc v0.3.0 // indirect
112109
github.com/spf13/afero v1.12.0 // indirect
@@ -129,11 +126,8 @@ require (
129126
go.opentelemetry.io/otel/trace v1.29.0 // indirect
130127
go.uber.org/atomic v1.9.0 // indirect
131128
go.uber.org/multierr v1.9.0 // indirect
132-
golang.design/x/clipboard v0.7.0 // indirect
133129
golang.org/x/crypto v0.37.0 // indirect
134-
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394 // indirect
135-
golang.org/x/image v0.14.0 // indirect
136-
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect
130+
golang.org/x/net v0.39.0 // indirect
137131
golang.org/x/oauth2 v0.25.0 // indirect
138132
golang.org/x/sync v0.13.0 // indirect
139133
golang.org/x/sys v0.32.0 // indirect

go.sum

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
180180
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
181181
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
182182
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
183-
github.com/kujtimiihoxha/vimtea v0.0.3-0.20250329221256-a250e98498f9 h1:xYfCLI8KUwmXDFp1pOpNX+XsQczQw9VbEuju1pQF5/A=
184-
github.com/kujtimiihoxha/vimtea v0.0.3-0.20250329221256-a250e98498f9/go.mod h1:Ye+kIkTmPO5xuqCQ+PPHDTGIViRRoSpSIlcYgma8YlA=
185-
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
186-
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
187183
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
188184
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
189185
github.com/lrstanley/bubblezone v0.0.0-20250315020633-c249a3fe1231 h1:9rjt7AfnrXKNSZhp36A3/4QAZAwGGCGD/p8Bse26zms=
@@ -235,8 +231,6 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
235231
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
236232
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
237233
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
238-
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
239-
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
240234
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
241235
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
242236
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@@ -302,8 +296,6 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
302296
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
303297
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
304298
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
305-
golang.design/x/clipboard v0.7.0 h1:4Je8M/ys9AJumVnl8m+rZnIvstSnYj1fvzqYrU3TXvo=
306-
golang.design/x/clipboard v0.7.0/go.mod h1:PQIvqYO9GP29yINEfsEn5zSQKAz3UgXmZKzDA6dnq2E=
307299
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
308300
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
309301
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@@ -314,12 +306,6 @@ golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
314306
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
315307
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
316308
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
317-
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394 h1:bFYqOIMdeiCEdzPJkLiOoMDzW/v3tjW4AA/RmUZYsL8=
318-
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
319-
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
320-
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
321-
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg=
322-
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc=
323309
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
324310
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
325311
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

internal/app/app.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/kujtimiihoxha/termai/internal/config"
1011
"github.com/kujtimiihoxha/termai/internal/db"
1112
"github.com/kujtimiihoxha/termai/internal/history"
1213
"github.com/kujtimiihoxha/termai/internal/llm/agent"
@@ -20,7 +21,7 @@ import (
2021
type App struct {
2122
Sessions session.Service
2223
Messages message.Service
23-
Files history.Service
24+
History history.Service
2425
Permissions permission.Service
2526

2627
CoderAgent agent.Service
@@ -43,19 +44,25 @@ func New(ctx context.Context, conn *sql.DB) (*App, error) {
4344
app := &App{
4445
Sessions: sessions,
4546
Messages: messages,
46-
Files: files,
47+
History: files,
4748
Permissions: permission.NewPermissionService(),
4849
LSPClients: make(map[string]*lsp.Client),
4950
}
5051

5152
app.initLSPClients(ctx)
5253

5354
var err error
54-
app.CoderAgent, err = agent.NewCoderAgent(
55-
app.Permissions,
55+
app.CoderAgent, err = agent.NewAgent(
56+
config.AgentCoder,
5657
app.Sessions,
5758
app.Messages,
58-
app.LSPClients,
59+
agent.CoderAgentTools(
60+
app.Permissions,
61+
app.Sessions,
62+
app.Messages,
63+
app.History,
64+
app.LSPClients,
65+
),
5966
)
6067
if err != nil {
6168
logging.Error("Failed to create coder agent", err)

internal/app/lsp.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@ func (app *App) initLSPClients(ctx context.Context) {
2222
// createAndStartLSPClient creates a new LSP client, initializes it, and starts its workspace watcher
2323
func (app *App) createAndStartLSPClient(ctx context.Context, name string, command string, args ...string) {
2424
// Create a specific context for initialization with a timeout
25-
initCtx, initCancel := context.WithTimeout(context.Background(), 30*time.Second)
26-
defer initCancel()
2725

2826
// Create the LSP client
29-
lspClient, err := lsp.NewClient(initCtx, command, args...)
27+
lspClient, err := lsp.NewClient(ctx, command, args...)
3028
if err != nil {
3129
logging.Error("Failed to create LSP client for", name, err)
3230
return
31+
3332
}
3433

34+
initCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
35+
defer cancel()
3536
// Initialize with the initialization context
3637
_, err = lspClient.InitializeLSPClient(initCtx, config.WorkingDirectory())
3738
if err != nil {
@@ -64,14 +65,10 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, comman
6465
// runWorkspaceWatcher executes the workspace watcher for an LSP client
6566
func (app *App) runWorkspaceWatcher(ctx context.Context, name string, workspaceWatcher *watcher.WorkspaceWatcher) {
6667
defer app.watcherWG.Done()
67-
defer func() {
68-
if r := recover(); r != nil {
69-
logging.Error("LSP client crashed", "client", name, "panic", r)
70-
71-
// Try to restart the client
72-
app.restartLSPClient(ctx, name)
73-
}
74-
}()
68+
defer logging.RecoverPanic("LSP-"+name, func() {
69+
// Try to restart the client
70+
app.restartLSPClient(ctx, name)
71+
})
7572

7673
workspaceWatcher.WatchWorkspace(ctx, config.WorkingDirectory())
7774
logging.Info("Workspace watcher stopped", "client", name)

0 commit comments

Comments
 (0)