feat: initial release of muyue - AI-powered dev environment assistant
Some checks failed
CI / build (macos-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled

Complete implementation of muyue v0.1.0, a single-binary Go tool that
transforms the development environment with AI-powered orchestration.

Core features:
- TUI with 5 tabs (Dashboard/Chat/Workflow/Agents/Config) using Charm stack
- AI chat via MiniMax M2.7 with async message handling
- Structured Plan→Execute workflow engine (gather→plan→review→execute)
- System scanner detecting 14 tools + 8 runtimes across Linux/macOS/Windows
- Auto-installer for Crush, Claude Code, BMAD, Starship, runtimes
- Background update daemon with hourly checks
- LSP auto-config for 16 language servers
- MCP auto-config for 12 servers (deployed to Crush + Claude Code)
- Skills system with 5 built-ins + AI-powered generation
- Crush/Claude Code proxy for unified control
- HTML preview server for visual outputs
- First-time setup wizard with interactive profiling
- Cross-platform: Linux (primary), macOS, Windows, WSL

CI/CD:
- GitHub Actions CI: build + test + lint on Linux/macOS/Windows
- Release workflow: cross-compile 6 binaries with checksums on tag push

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
Augustin
2026-04-19 22:29:20 +02:00
commit f0ccd265da
25 changed files with 4743 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
package profiler
import (
"fmt"
"strings"
"github.com/charmbracelet/huh"
"github.com/muyue/muyue/internal/config"
"github.com/muyue/muyue/internal/scanner"
)
func RunFirstTimeSetup() (*config.MuyueConfig, error) {
cfg := config.Default()
result := scanner.ScanSystem()
fmt.Println("Welcome to muyue! Let's set up your environment.\n")
var name, pseudo, email string
var languages []string
var editor string
var aiProvider string
nameField := huh.NewInput().
Title("What's your name?").
Placeholder("Augustin").
Value(&name)
pseudoField := huh.NewInput().
Title("Your pseudo?").
Placeholder("muyue").
Value(&pseudo)
emailField := huh.NewInput().
Title("Your email (for git config)?").
Placeholder("you@example.com").
Value(&email)
langOptions := []huh.Option[string]{
{Key: "Go", Value: "go"},
{Key: "TypeScript/JavaScript", Value: "typescript"},
{Key: "Python", Value: "python"},
{Key: "Rust", Value: "rust"},
{Key: "Java", Value: "java"},
{Key: "C/C++", Value: "c"},
{Key: "Ruby", Value: "ruby"},
{Key: "PHP", Value: "php"},
{Key: "Swift", Value: "swift"},
{Key: "Kotlin", Value: "kotlin"},
}
langSelect := huh.NewMultiSelect[string]().
Title("Which languages do you work with?").
Options(langOptions...).
Value(&languages)
editorOptions := []huh.Option[string]{
{Key: "VS Code", Value: "code"},
{Key: "Neovim", Value: "nvim"},
{Key: "Vim", Value: "vim"},
{Key: "Emacs", Value: "emacs"},
{Key: "JetBrains", Value: "jetbrains"},
{Key: "Helix", Value: "hx"},
{Key: "Sublime Text", Value: "subl"},
}
editorSelect := huh.NewSelect[string]().
Title("Preferred editor?").
Options(editorOptions...).
Value(&editor)
aiOptions := []huh.Option[string]{
{Key: "MiniMax M2.7", Value: "minimax"},
{Key: "Z.AI GLM", Value: "zai"},
{Key: "Anthropic Claude", Value: "anthropic"},
{Key: "OpenAI", Value: "openai"},
}
aiSelect := huh.NewSelect[string]().
Title("Which AI provider for orchestration?").
Options(aiOptions...).
Value(&aiProvider)
form := huh.NewForm(
huh.NewGroup(nameField, pseudoField, emailField),
huh.NewGroup(langSelect),
huh.NewGroup(editorSelect),
huh.NewGroup(aiSelect),
)
if err := form.Run(); err != nil {
return nil, fmt.Errorf("profile form: %w", err)
}
cfg.Profile.Name = name
cfg.Profile.Pseudo = pseudo
cfg.Profile.Email = email
cfg.Profile.Languages = languages
cfg.Profile.Preferences.Editor = editor
cfg.Profile.Preferences.DefaultAI = aiProvider
for i := range cfg.AI.Providers {
cfg.AI.Providers[i].Active = cfg.AI.Providers[i].Name == aiProvider
}
_ = result
return cfg, nil
}
func AskAPIKey(providerName string) (string, error) {
var apiKey string
field := huh.NewInput().
Title(fmt.Sprintf("Enter your %s API key:", providerName)).
Description("The key will be stored locally in ~/.muyue/config.yaml").
EchoMode(huh.EchoModePassword).
Value(&apiKey)
form := huh.NewForm(huh.NewGroup(field))
if err := form.Run(); err != nil {
return "", err
}
return strings.TrimSpace(apiKey), nil
}