feat: add Cobra CLI, LSP/MCP registries, workflow engine, and enriched dashboard
Major changes: - Refactor CLI entry point to Cobra commands (root, setup, scan, doctor, install, update, lsp, mcp, skills, config, version) - Add LSP registry with health checks, auto-install, and editor config generation - Add MCP registry with editor detection, status tracking, and per-editor configuration - Add workflow engine with planner and step execution for automated task chains - Add conversation search, export (Markdown/JSON), and detailed token counting - Add streaming shell chat handler with tool call/result events - Add skill validation, dry-run testing, and export endpoints - Enrich dashboard with Tools/Activity/Status tabs and tool cards grid - Add PRD documentation - Complete i18n for both EN and FR 💘 Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
142
internal/lsp/registry_test.go
Normal file
142
internal/lsp/registry_test.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package lsp
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultLSPRegistry(t *testing.T) {
|
||||
reg := DefaultLSPRegistry()
|
||||
if reg.SchemaVersion != "v1" {
|
||||
t.Errorf("Expected v1, got %s", reg.SchemaVersion)
|
||||
}
|
||||
if len(reg.Servers) == 0 {
|
||||
t.Error("Default LSP registry should have servers")
|
||||
}
|
||||
|
||||
names := map[string]bool{}
|
||||
for _, s := range reg.Servers {
|
||||
if names[s.Name] {
|
||||
t.Errorf("Duplicate server name: %s", s.Name)
|
||||
}
|
||||
names[s.Name] = true
|
||||
if s.Command == "" {
|
||||
t.Errorf("Server %s missing command", s.Name)
|
||||
}
|
||||
if s.Language == "" {
|
||||
t.Errorf("Server %s missing language", s.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveAndLoadLSPRegistry(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
SetLSPRegistryPath(filepath.Join(tmpDir, "lsp-registry.yaml"))
|
||||
|
||||
reg := DefaultLSPRegistry()
|
||||
if err := SaveLSPRegistry(reg); err != nil {
|
||||
t.Fatalf("SaveLSPRegistry failed: %v", err)
|
||||
}
|
||||
|
||||
loaded, err := LoadLSPRegistry()
|
||||
if err != nil {
|
||||
t.Fatalf("LoadLSPRegistry failed: %v", err)
|
||||
}
|
||||
if len(loaded.Servers) != len(reg.Servers) {
|
||||
t.Errorf("Expected %d servers, got %d", len(reg.Servers), len(loaded.Servers))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitLSPRegistry(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
SetLSPRegistryPath(filepath.Join(tmpDir, "lsp-reg.yaml"))
|
||||
|
||||
if err := InitLSPRegistry(); err != nil {
|
||||
t.Fatalf("InitLSPRegistry failed: %v", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(tmpDir, "lsp-reg.yaml")); os.IsNotExist(err) {
|
||||
t.Error("LSP registry file should be created")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectProjectLanguages(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
os.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte("module test\ngo 1.24\n"), 0644)
|
||||
os.WriteFile(filepath.Join(tmpDir, "package.json"), []byte(`{"name": "test"}`), 0644)
|
||||
|
||||
languages := DetectProjectLanguages(tmpDir)
|
||||
if len(languages) == 0 {
|
||||
t.Error("Should detect languages")
|
||||
}
|
||||
|
||||
langSet := map[string]bool{}
|
||||
for _, l := range languages {
|
||||
langSet[l] = true
|
||||
}
|
||||
if !langSet["go"] {
|
||||
t.Error("Should detect Go")
|
||||
}
|
||||
if !langSet["typescript"] {
|
||||
t.Error("Should detect TypeScript/JS from package.json")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectProjectLanguagesEmpty(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
languages := DetectProjectLanguages(tmpDir)
|
||||
if len(languages) != 0 {
|
||||
t.Errorf("Empty dir should detect no languages, got %v", languages)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateNeovimConfig(t *testing.T) {
|
||||
servers := []RegistryEntry{
|
||||
{Name: "gopls", Language: "go", NeovimSetup: "lspconfig.gopls.setup{}"},
|
||||
{Name: "pyright", Language: "python", NeovimSetup: "lspconfig.pyright.setup{}"},
|
||||
}
|
||||
|
||||
config := GenerateNeovimConfig(servers)
|
||||
if config == "" {
|
||||
t.Error("Config should not be empty")
|
||||
}
|
||||
if len(config) < 50 {
|
||||
t.Error("Config seems too short")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateHelixConfig(t *testing.T) {
|
||||
servers := []RegistryEntry{
|
||||
{Name: "gopls", Language: "go", HelixLanguage: "go"},
|
||||
}
|
||||
|
||||
config := GenerateHelixConfig(servers)
|
||||
if config == "" {
|
||||
t.Error("Config should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateVSCodeRecommendations(t *testing.T) {
|
||||
servers := []RegistryEntry{
|
||||
{Name: "gopls", Language: "go"},
|
||||
{Name: "pyright", Language: "python"},
|
||||
}
|
||||
|
||||
exts := GenerateVSCodeRecommendations(servers)
|
||||
if len(exts) == 0 {
|
||||
t.Error("Should return some extensions")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthCheck(t *testing.T) {
|
||||
healthy, detail := HealthCheck("gopls")
|
||||
if healthy && detail == "" {
|
||||
t.Error("If healthy, should have version detail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthCheckUnknown(t *testing.T) {
|
||||
_, _ = HealthCheck("nonexistent-server")
|
||||
}
|
||||
Reference in New Issue
Block a user