This commit is contained in:
Dax Raad 2025-08-31 02:16:43 -04:00
commit 647671dbe6
89 changed files with 15329 additions and 44 deletions

View file

@ -37,9 +37,8 @@ func main() {
url := os.Getenv("OPENCODE_SERVER")
appInfoStr := os.Getenv("OPENCODE_APP_INFO")
var appInfo opencode.App
err := json.Unmarshal([]byte(appInfoStr), &appInfo)
var project opencode.Project
err := json.Unmarshal([]byte(os.Getenv("OPENCODE_PROJECT")), &project)
if err != nil {
slog.Error("Failed to unmarshal app info", "error", err)
os.Exit(1)
@ -74,7 +73,7 @@ func main() {
)
// Fetch agents from the /agent endpoint
agentsPtr, err := httpClient.App.Agents(context.Background())
agentsPtr, err := httpClient.Agent.List(context.Background())
if err != nil {
slog.Error("Failed to fetch agents", "error", err)
os.Exit(1)
@ -85,13 +84,18 @@ func main() {
}
agents := *agentsPtr
path, err := httpClient.Path.Get(context.Background())
if err != nil {
os.Exit(1)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
apiHandler := util.NewAPILogHandler(ctx, httpClient, "tui", slog.LevelDebug)
logger := slog.New(apiHandler)
slog.SetDefault(logger)
slog.Debug("TUI launched", "app", appInfoStr, "agents_count", len(agents), "url", url)
slog.Debug("TUI launched")
go func() {
err = clipboard.Init()
@ -101,7 +105,7 @@ func main() {
}()
// Create main context for the application
app_, err := app.New(ctx, version, appInfo, agents, httpClient, model, prompt, agent, sessionID)
app_, err := app.New(ctx, version, project, path, agents, httpClient, model, prompt, agent, sessionID)
if err != nil {
panic(err)
}
@ -121,9 +125,6 @@ func main() {
stream := httpClient.Event.ListStreaming(ctx)
for stream.Next() {
evt := stream.Current().AsUnion()
if _, ok := evt.(opencode.EventListResponseEventStorageWrite); ok {
continue
}
program.Send(evt)
}
if err := stream.Err(); err != nil {

View file

@ -27,7 +27,7 @@ type Message struct {
}
type App struct {
Info opencode.App
Project opencode.Project
Agents []opencode.Agent
Providers []opencode.Provider
Version string
@ -101,7 +101,8 @@ type PermissionRespondedToMsg struct {
func New(
ctx context.Context,
version string,
appInfo opencode.App,
project opencode.Project,
path *opencode.Path,
agents []opencode.Agent,
httpClient *opencode.Client,
initialModel *string,
@ -109,8 +110,8 @@ func New(
initialAgent *string,
initialSession *string,
) (*App, error) {
util.RootPath = appInfo.Path.Root
util.CwdPath = appInfo.Path.Cwd
util.RootPath = project.Worktree
util.CwdPath, _ = os.Getwd()
configInfo, err := httpClient.Config.Get(ctx)
if err != nil {
@ -121,7 +122,7 @@ func New(
configInfo.Keybinds.Leader = "ctrl+x"
}
appStatePath := filepath.Join(appInfo.Path.State, "tui")
appStatePath := filepath.Join(path.State, "tui")
appState, err := LoadState(appStatePath)
if err != nil {
appState = NewState()
@ -168,9 +169,9 @@ func New(
}
if err := theme.LoadThemesFromDirectories(
appInfo.Path.Config,
appInfo.Path.Root,
appInfo.Path.Cwd,
path.Config,
util.RootPath,
util.CwdPath,
); err != nil {
slog.Warn("Failed to load themes from directories", "error", err)
}
@ -193,7 +194,7 @@ func New(
}
app := &App{
Info: appInfo,
Project: project,
Agents: agents,
Version: version,
StatePath: appStatePath,
@ -749,12 +750,15 @@ func (a *App) CompactSession(ctx context.Context) tea.Cmd {
}
func (a *App) MarkProjectInitialized(ctx context.Context) error {
_, err := a.Client.App.Init(ctx)
if err != nil {
slog.Error("Failed to mark project as initialized", "error", err)
return err
}
return nil
/*
_, err := a.Client.App.Init(ctx)
if err != nil {
slog.Error("Failed to mark project as initialized", "error", err)
return err
}
return nil
*/
}
func (a *App) CreateSession(ctx context.Context) (*opencode.Session, error) {

View file

@ -30,7 +30,7 @@ func (cg *agentsContextGroup) GetChildEntries(
query = strings.TrimSpace(query)
agents, err := cg.app.Client.App.Agents(
agents, err := cg.app.Client.Agent.List(
context.Background(),
)
if err != nil {

View file

@ -160,7 +160,7 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if filePath := strings.TrimSpace(strings.TrimPrefix(text, "@")); strings.HasPrefix(text, "@") && filePath != "" {
statPath := filePath
if !filepath.IsAbs(filePath) {
statPath = filepath.Join(m.app.Info.Path.Cwd, filePath)
statPath = filepath.Join(util.CwdPath, filePath)
}
if _, err := os.Stat(statPath); err == nil {
attachment := m.createAttachmentFromPath(filePath)
@ -623,7 +623,7 @@ func (m *editorComponent) SetValueWithAttachments(value string) {
if end > start {
filePath := value[start:end]
slog.Debug("test", "filePath", filePath)
if _, err := os.Stat(filepath.Join(m.app.Info.Path.Cwd, filePath)); err == nil {
if _, err := os.Stat(filepath.Join(util.CwdPath, filePath)); err == nil {
slog.Debug("test", "found", true)
attachment := m.createAttachmentFromFile(filePath)
if attachment != nil {
@ -818,7 +818,7 @@ func (m *editorComponent) createAttachmentFromFile(filePath string) *attachment.
mediaType := getMediaTypeFromExtension(ext)
absolutePath := filePath
if !filepath.IsAbs(filePath) {
absolutePath = filepath.Join(m.app.Info.Path.Cwd, filePath)
absolutePath = filepath.Join(util.CwdPath, filePath)
}
// For text files, create a simple file reference
@ -872,7 +872,7 @@ func (m *editorComponent) createAttachmentFromPath(filePath string) *attachment.
mediaType := getMediaTypeFromExtension(extension)
absolutePath := filePath
if !filepath.IsAbs(filePath) {
absolutePath = filepath.Join(m.app.Info.Path.Cwd, filePath)
absolutePath = filepath.Join(util.CwdPath, filePath)
}
return &attachment.Attachment{
ID: uuid.NewString(),

View file

@ -187,7 +187,7 @@ func renderContentBlock(
style = style.BorderRightForeground(borderColor)
}
} else {
style = style.PaddingLeft(renderer.paddingLeft + 1).PaddingRight(renderer.paddingRight + 1)
style = style.PaddingLeft(renderer.paddingLeft).PaddingRight(renderer.paddingRight)
}
content = style.Render(content)

View file

@ -200,7 +200,7 @@ func (m *statusComponent) View() string {
func (m *statusComponent) startGitWatcher() tea.Cmd {
cmd := util.CmdHandler(
GitBranchUpdatedMsg{Branch: getCurrentGitBranch(m.app.Info.Path.Root)},
GitBranchUpdatedMsg{Branch: getCurrentGitBranch(m.app.Project.Worktree)},
)
if err := m.initWatcher(); err != nil {
return cmd
@ -209,7 +209,7 @@ func (m *statusComponent) startGitWatcher() tea.Cmd {
}
func (m *statusComponent) initWatcher() error {
gitDir := filepath.Join(m.app.Info.Path.Root, ".git")
gitDir := filepath.Join(m.app.Project.Worktree, ".git")
headFile := filepath.Join(gitDir, "HEAD")
if info, err := os.Stat(gitDir); err != nil || !info.IsDir() {
return err
@ -226,7 +226,7 @@ func (m *statusComponent) initWatcher() error {
}
// Also watch the ref file if HEAD points to a ref
refFile := getGitRefFile(m.app.Info.Path.Cwd)
refFile := getGitRefFile(util.CwdPath)
if refFile != headFile && refFile != "" {
if _, err := os.Stat(refFile); err == nil {
watcher.Add(refFile) // Ignore error, HEAD watching is sufficient
@ -247,7 +247,7 @@ func (m *statusComponent) watchForGitChanges() tea.Cmd {
for {
select {
case event, ok := <-m.watcher.Events:
branch := getCurrentGitBranch(m.app.Info.Path.Root)
branch := getCurrentGitBranch(m.app.Project.Worktree)
if !ok {
return GitBranchUpdatedMsg{Branch: branch}
}
@ -276,8 +276,8 @@ func (m *statusComponent) updateWatchedFiles() {
if m.watcher == nil {
return
}
refFile := getGitRefFile(m.app.Info.Path.Root)
headFile := filepath.Join(m.app.Info.Path.Root, ".git", "HEAD")
refFile := getGitRefFile(m.app.Project.Worktree)
headFile := filepath.Join(m.app.Project.Worktree, ".git", "HEAD")
if refFile != headFile && refFile != "" {
if _, err := os.Stat(refFile); err == nil {
// Try to add the new ref file (ignore error if already watching)
@ -330,7 +330,7 @@ func NewStatusCmp(app *app.App) StatusComponent {
}
homePath, err := os.UserHomeDir()
cwdPath := app.Info.Path.Cwd
cwdPath := util.CwdPath
if err == nil && homePath != "" && strings.HasPrefix(cwdPath, homePath) {
cwdPath = "~" + cwdPath[len(homePath):]
}

View file

@ -460,11 +460,13 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
"opencode updated to "+msg.Properties.Version+", restart to apply.",
toast.WithTitle("New version installed"),
)
case opencode.EventListResponseEventIdeInstalled:
return a, toast.NewSuccessToast(
"Installed the opencode extension in "+msg.Properties.Ide,
toast.WithTitle(msg.Properties.Ide+" extension installed"),
)
/*
case opencode.EventListResponseEventIdeInstalled:
return a, toast.NewSuccessToast(
"Installed the opencode extension in "+msg.Properties.Ide,
toast.WithTitle(msg.Properties.Ide+" extension installed"),
)
*/
case opencode.EventListResponseEventSessionDeleted:
if a.app.Session != nil && msg.Properties.Info.ID == a.app.Session.ID {
a.app.Session = &opencode.Session{}