Files
hyperguild/cmd/hyperguild/mode.go
T
mathiasandClaude Opus 4.8 a7db0dd00d
CI / Lint / Test / Vet (pull_request) Successful in 12s
CI / Mirror to GitHub (pull_request) Has been skipped
feat(mode): brain+gitea in all modes; drop iceboxed routing entry (#75)
Step 7 of the consolidation: reflect gitea-mcp as an available connection
(Gitea-as-audit-trail is an invariant going forward) and stop emitting the
now-iceboxed routing pod.

- cmd/hyperguild mode.go: every mode (cloud/client-local/sovereign) now lists
  brain + gitea; removed the client-local `routing` entry (koala:30310, the
  iceboxed pod). Tests updated to the new contract.
- .mcp.json: add gitea-mcp (git-mcp.d-ma.be, Bearer ${GITEA_MCP_TOKEN}).
- cmd/hyperguild/README: modes doc updated (brain+gitea, no routing).

Refs #75.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:27:31 +02:00

109 lines
2.9 KiB
Go

package main
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"os"
)
func runMode(ctx context.Context, args []string, _ io.Reader, stdout, stderr io.Writer) error {
fs := flag.NewFlagSet("mode", flag.ContinueOnError)
fs.SetOutput(stderr)
out := fs.String("out", ".mcp.json", "output file path")
force := fs.Bool("force", false, "overwrite an existing file")
// Pull the first positional (mode name) out so flags after it still parse
// with stdlib flag (which stops at the first non-flag arg).
if len(args) < 1 {
return errors.New("name required (cloud|client-local|sovereign)")
}
name := args[0]
if err := fs.Parse(args[1:]); err != nil {
return fmt.Errorf("parse flags: %w", err)
}
brainURL := os.Getenv("BRAIN_URL")
if brainURL == "" {
brainURL = defaultBrainURL
}
var doc map[string]any
switch name {
case "cloud":
doc = modeCloud(brainURL)
case "client-local":
doc = modeClientLocal(brainURL)
case "sovereign":
doc = modeSovereign(brainURL)
default:
return fmt.Errorf("unknown mode: %s (expected cloud|client-local|sovereign)", name)
}
if !*force {
if _, err := os.Stat(*out); err == nil {
return fmt.Errorf("%s exists (use --force to overwrite)", *out)
}
}
body, err := json.MarshalIndent(doc, "", " ")
if err != nil {
return fmt.Errorf("marshal mode doc: %w", err)
}
if err := os.WriteFile(*out, append(body, '\n'), 0o644); err != nil {
return fmt.Errorf("write %s: %w", *out, err)
}
fmt.Fprintf(stdout, "wrote %s (mode: %s)\n", *out, name) //nolint:errcheck
return nil
}
// giteaMCPURL is the public Gitea MCP endpoint (OAuth via Dex/Authentik). Gitea
// is the audit-trail invariant of the consolidated single harness (#75), so every
// mode lists it as an available connection.
const giteaMCPURL = "https://git-mcp.d-ma.be/mcp"
func brainEntry(brainURL string) map[string]any {
return map[string]any{
"url": brainURL + "/mcp",
"description": "Brain MCP — knowledge query, write, ingestion, session log",
}
}
func giteaEntry() map[string]any {
return map[string]any{
"url": giteaMCPURL,
"description": "Gitea MCP — issues/PRs/repo ops (audit-trail invariant)",
}
}
func modeCloud(brainURL string) map[string]any {
return map[string]any{
"mcpServers": map[string]any{
"brain": brainEntry(brainURL),
"gitea": giteaEntry(),
},
}
}
func modeClientLocal(brainURL string) map[string]any {
// The routing pod is iceboxed (#75); the consolidated harness is brain + gitea.
return map[string]any{
"mcpServers": map[string]any{
"brain": brainEntry(brainURL),
"gitea": giteaEntry(),
},
}
}
func modeSovereign(brainURL string) map[string]any {
return map[string]any{
"_mode_note": "Sovereign mode primarily uses Crush + LiteLLM. This .mcp.json is provided as Claude Code fallback (e.g. emergency offline editing).",
"mcpServers": map[string]any{
"brain": brainEntry(brainURL),
"gitea": giteaEntry(),
},
}
}