All checks were successful
CI / build (push) Successful in 2m41s
Split monolithic app.go into focused modules (dashboard, chat, workflow, config, agents, terminal, commands, handlers). Add proper error handling for installer commands, proxy pipes, and MCP config parsing. Fix daemon channel buffer, cap orchestrator history, compile think regex once, and set HTTP timeouts on preview server. Improve CI with Go module caching, dependency download step, and test stage with race detection. 😘 Generated with Crush Assisted-by: GLM-5-Turbo via Crush <crush@charm.land>
130 lines
3.2 KiB
Go
130 lines
3.2 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/muyue/muyue/internal/config"
|
|
"github.com/muyue/muyue/internal/installer"
|
|
"github.com/muyue/muyue/internal/orchestrator"
|
|
"github.com/muyue/muyue/internal/workflow"
|
|
)
|
|
|
|
func startInstallCmd(cfg *config.MuyueConfig, tools []string, index int) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
inst := installer.New(cfg)
|
|
result := inst.InstallTool(tools[index])
|
|
|
|
if index+1 < len(tools) {
|
|
return installBatchMsg{
|
|
result: result,
|
|
tools: tools,
|
|
index: index,
|
|
config: cfg,
|
|
}
|
|
}
|
|
return installCompleteMsg{results: []installer.InstallResult{result}}
|
|
})
|
|
}
|
|
|
|
func sendAIMessage(orch *orchestrator.Orchestrator, input string) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
if orch == nil {
|
|
return aiErrMsg{err: fmt.Errorf("orchestrator not configured")}
|
|
}
|
|
resp, err := orch.Send(input)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
})
|
|
}
|
|
|
|
func startWorkflowCmd(orch *orchestrator.Orchestrator, goal string) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
resp, err := orch.StartWorkflow(goal)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
})
|
|
}
|
|
|
|
func workflowChatCmd(orch *orchestrator.Orchestrator, input string) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
wf := orch.Workflow
|
|
switch wf.Phase {
|
|
case workflow.PhaseGathering:
|
|
resp, err := orch.AnswerQuestion(input)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
case workflow.PhaseReviewing:
|
|
approved, feedback := workflow.ParseApproval(input)
|
|
resp, err := orch.ReviewPlan(approved, feedback)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
default:
|
|
resp, err := orch.Send(input)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
}
|
|
})
|
|
}
|
|
|
|
func generatePlanCmd(orch *orchestrator.Orchestrator) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
resp, err := orch.GeneratePlan()
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
})
|
|
}
|
|
|
|
func reviewPlanCmd(orch *orchestrator.Orchestrator, approved bool, feedback string) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
resp, err := orch.ReviewPlan(approved, feedback)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
})
|
|
}
|
|
|
|
func continueWorkflowCmd(orch *orchestrator.Orchestrator, output string) tea.Cmd {
|
|
return tea.Cmd(func() tea.Msg {
|
|
resp, err := orch.ContinueExecution(output)
|
|
if err != nil {
|
|
return aiErrMsg{err: err}
|
|
}
|
|
return aiResponseMsg{content: resp}
|
|
})
|
|
}
|
|
|
|
func (m Model) handleChatSubmit() (tea.Model, tea.Cmd) {
|
|
input := m.chatInput
|
|
m.chatLog = append(m.chatLog, userMsgStyle.Render("you: "+input))
|
|
m.chatInput = ""
|
|
m.chatLoading = true
|
|
m.viewport.SetContent(m.renderContent())
|
|
m.viewport.GotoBottom()
|
|
|
|
if strings.HasPrefix(input, "/plan ") {
|
|
goal := strings.TrimPrefix(input, "/plan ")
|
|
return m, startWorkflowCmd(m.orch, goal)
|
|
}
|
|
|
|
if m.orch != nil && m.orch.Workflow != nil && m.orch.Workflow.Phase != workflow.PhaseIdle {
|
|
return m, workflowChatCmd(m.orch, input)
|
|
}
|
|
|
|
return m, sendAIMessage(m.orch, input)
|
|
}
|