a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
130 lines
4.4 KiB
Go
130 lines
4.4 KiB
Go
// Package vscode implements the Gortex init integration for
|
|
// Visual Studio Code's native MCP runtime (1.102+). VS Code's
|
|
// schema differs from the Claude / Cursor canonical shape in two
|
|
// ways:
|
|
//
|
|
// - top-level key is "servers" (not "mcpServers")
|
|
// - stdio is the inferred default; no "type" field is required
|
|
//
|
|
// The VS Code docs document both project-level (.vscode/mcp.json)
|
|
// and user-level configurations; the user-level file lives under
|
|
// the platform-specific VS Code profile directory and is accessed
|
|
// via the "MCP: Open User Configuration" command. We write the
|
|
// project-level file today and leave user-level to a follow-up once
|
|
// the official per-OS paths are confirmed.
|
|
//
|
|
// Docs: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
|
|
package vscode
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
|
|
"github.com/zzet/gortex/internal/agents"
|
|
"github.com/zzet/gortex/internal/agents/internalutil"
|
|
)
|
|
|
|
const Name = "vscode"
|
|
const DocsURL = "https://code.visualstudio.com/docs/copilot/chat/mcp-servers"
|
|
|
|
type Adapter struct{}
|
|
|
|
func New() *Adapter { return &Adapter{} }
|
|
func (a *Adapter) Name() string { return Name }
|
|
func (a *Adapter) DocsURL() string { return DocsURL }
|
|
|
|
func (a *Adapter) Detect(env agents.Env) (bool, error) {
|
|
if _, err := os.Stat(filepath.Join(env.Root, ".vscode")); err == nil {
|
|
return true, nil
|
|
}
|
|
if p, err := exec.LookPath("code"); err == nil && p != "" {
|
|
return true, nil
|
|
}
|
|
if env.Home != "" {
|
|
candidates := []string{
|
|
filepath.Join(env.Home, "Library", "Application Support", "Code"),
|
|
filepath.Join(env.Home, ".config", "Code"),
|
|
filepath.Join(env.Home, ".vscode"),
|
|
}
|
|
for _, dir := range candidates {
|
|
if _, err := os.Stat(dir); err == nil {
|
|
return true, nil
|
|
}
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (a *Adapter) Plan(env agents.Env) (*agents.Plan, error) {
|
|
p := &agents.Plan{Files: []agents.FileAction{
|
|
{Path: filepath.Join(env.Root, ".vscode", "mcp.json"), Action: agents.ActionWouldMerge, Keys: []string{"servers"}},
|
|
}}
|
|
if env.Mode != agents.ModeGlobal && env.SkillsRouting != "" {
|
|
p.Files = append(p.Files, agents.FileAction{
|
|
Path: filepath.Join(env.Root, ".github", "copilot-instructions.md"), Action: agents.ActionWouldMerge,
|
|
Keys: []string{"communities-block"},
|
|
})
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
func (a *Adapter) Apply(env agents.Env, opts agents.ApplyOpts) (*agents.Result, error) {
|
|
res := &agents.Result{Name: Name, DocsURL: DocsURL}
|
|
// Global mode skips this adapter — user-level VS Code MCP
|
|
// config lives at a platform-specific path (via the "MCP: Open
|
|
// User Configuration" command) which we don't resolve today.
|
|
if env.Mode == agents.ModeGlobal {
|
|
return res, nil
|
|
}
|
|
detected, _ := a.Detect(env)
|
|
res.Detected = detected
|
|
if !detected && !opts.ForceDetect {
|
|
internalutil.Logf(env.Stderr, "[gortex init] skip VS Code / Copilot setup (VS Code not detected)")
|
|
return res, nil
|
|
}
|
|
internalutil.Logf(env.Stderr, "[gortex init] setting up VS Code / GitHub Copilot integration...")
|
|
|
|
path := filepath.Join(env.Root, ".vscode", "mcp.json")
|
|
action, err := agents.MergeJSON(env.Stderr, path, func(root map[string]any, _ bool) (bool, error) {
|
|
servers, ok := root["servers"].(map[string]any)
|
|
if !ok {
|
|
servers = make(map[string]any)
|
|
}
|
|
if _, exists := servers["gortex"]; exists && !opts.Force {
|
|
return false, nil
|
|
}
|
|
// VS Code's native MCP runtime (1.102+) infers stdio from
|
|
// command/args presence, so no "type" field is needed. Env
|
|
// is optional — we set it for parity with other adapters.
|
|
servers["gortex"] = map[string]any{
|
|
"command": "gortex",
|
|
"args": []string{"mcp"},
|
|
"env": map[string]string{"GORTEX_INDEX_WORKERS": "8"},
|
|
}
|
|
root["servers"] = servers
|
|
return true, nil
|
|
}, opts)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.Files = append(res.Files, action)
|
|
|
|
// Copilot reads .github/copilot-instructions.md on every chat
|
|
// turn. Write a marker-guarded community-routing block there
|
|
// when skills were generated — codebase-specific navigation
|
|
// that MCP tool descriptions can't carry.
|
|
if env.SkillsRouting != "" {
|
|
copilotPath := filepath.Join(env.Root, ".github", "copilot-instructions.md")
|
|
routingAction, err := agents.UpsertMarkedBlock(env.Stderr, copilotPath, env.SkillsRouting,
|
|
agents.CommunitiesStartMarker, agents.CommunitiesEndMarker, opts)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.Files = append(res.Files, routingAction)
|
|
}
|
|
|
|
res.Configured = true
|
|
return res, nil
|
|
}
|