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
108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
// Package openclaw implements the Gortex init integration for
|
|
// OpenClaw. OpenClaw's config lives at ~/.openclaw/openclaw.json
|
|
// in JSON5 format; MCP servers go under the nested "mcp.servers"
|
|
// table:
|
|
//
|
|
// {
|
|
// "mcp": {
|
|
// "servers": {
|
|
// "gortex": {"command": "gortex", "args": [...], "env": {...}}
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// We emit plain JSON — OpenClaw's JSON5 parser accepts vanilla
|
|
// JSON, and writing strict JSON sidesteps dependency on a JSON5
|
|
// encoder. Users can hand-edit the file afterwards and JSON5
|
|
// features (comments, trailing commas) won't be stripped because
|
|
// we never read back; we always overwrite the gortex entry only.
|
|
//
|
|
// Docs: https://docs.openclaw.ai/gateway/configuration-reference.md
|
|
package openclaw
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
|
|
"github.com/zzet/gortex/internal/agents"
|
|
"github.com/zzet/gortex/internal/agents/internalutil"
|
|
)
|
|
|
|
const Name = "openclaw"
|
|
const DocsURL = "https://docs.openclaw.ai/cli/mcp"
|
|
|
|
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 p, err := exec.LookPath("openclaw"); err == nil && p != "" {
|
|
return true, nil
|
|
}
|
|
if env.Home == "" {
|
|
return false, nil
|
|
}
|
|
if _, err := os.Stat(filepath.Join(env.Home, ".openclaw")); err == nil {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (a *Adapter) Plan(env agents.Env) (*agents.Plan, error) {
|
|
if env.Home == "" {
|
|
return &agents.Plan{}, nil
|
|
}
|
|
return &agents.Plan{Files: []agents.FileAction{{
|
|
Path: filepath.Join(env.Home, ".openclaw", "openclaw.json"),
|
|
Action: agents.ActionWouldMerge,
|
|
Keys: []string{"mcp"},
|
|
}}}, nil
|
|
}
|
|
|
|
func (a *Adapter) Apply(env agents.Env, opts agents.ApplyOpts) (*agents.Result, error) {
|
|
res := &agents.Result{Name: Name, DocsURL: DocsURL}
|
|
detected, _ := a.Detect(env)
|
|
res.Detected = detected
|
|
if !detected && !opts.ForceDetect {
|
|
internalutil.Logf(env.Stderr, "[gortex init] skip OpenClaw setup (openclaw not detected)")
|
|
return res, nil
|
|
}
|
|
if env.Home == "" {
|
|
return res, fmt.Errorf("openclaw: requires a resolved home directory")
|
|
}
|
|
internalutil.Logf(env.Stderr, "[gortex init] setting up OpenClaw integration...")
|
|
|
|
path := filepath.Join(env.Home, ".openclaw", "openclaw.json")
|
|
action, err := agents.MergeJSON(env.Stderr, path, func(root map[string]any, _ bool) (bool, error) {
|
|
mcp, ok := root["mcp"].(map[string]any)
|
|
if !ok {
|
|
mcp = make(map[string]any)
|
|
}
|
|
servers, ok := mcp["servers"].(map[string]any)
|
|
if !ok {
|
|
servers = make(map[string]any)
|
|
}
|
|
if _, exists := servers["gortex"]; exists && !opts.Force {
|
|
return false, nil
|
|
}
|
|
servers["gortex"] = map[string]any{
|
|
"command": "gortex",
|
|
"args": []string{"mcp"},
|
|
"env": map[string]string{"GORTEX_INDEX_WORKERS": "8"},
|
|
}
|
|
mcp["servers"] = servers
|
|
root["mcp"] = mcp
|
|
return true, nil
|
|
}, opts)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.Files = append(res.Files, action)
|
|
res.Configured = true
|
|
return res, nil
|
|
}
|