Server setup in the app
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"g.fc.run/ai/byre/internal/tailscale"
|
||||
)
|
||||
|
||||
const (
|
||||
needRequired = "required"
|
||||
needAgent = "agent"
|
||||
needOptional = "optional"
|
||||
)
|
||||
|
||||
type check struct {
|
||||
Name string `json:"name"`
|
||||
Need string `json:"need"`
|
||||
For string `json:"for"`
|
||||
OK bool `json:"ok"`
|
||||
Fix string `json:"fix"`
|
||||
Blocking bool `json:"blocking"`
|
||||
}
|
||||
|
||||
func checks() []check {
|
||||
return []check{
|
||||
gitCheck(),
|
||||
tailscaleCheck(),
|
||||
command("claude", needAgent, "Claude models", "curl -fsSL https://claude.ai/install.sh | bash, then run claude once to sign in"),
|
||||
command("codex", needAgent, "GPT models", "brew install --cask codex, then run codex once to sign in"),
|
||||
command("agy", needAgent, "Gemini models", "brew install --cask antigravity-cli, then run agy once to sign in"),
|
||||
command("npx", needOptional, "reviewers' Playwright browser tools", "brew install node"),
|
||||
appCheck("Google Chrome", needOptional, "browser tools for agents and reviewers", "brew install --cask google-chrome"),
|
||||
}
|
||||
}
|
||||
|
||||
func gitCheck() check {
|
||||
c := check{Name: "git", Need: needRequired, For: "worktrees, snapshots and merges", Fix: "xcode-select --install"}
|
||||
path, err := exec.LookPath("git")
|
||||
// /usr/bin/git is a stub that offers to install the Command Line Tools when they're missing.
|
||||
c.OK = err == nil && (path != "/usr/bin/git" || exec.Command("xcode-select", "-p").Run() == nil)
|
||||
return c
|
||||
}
|
||||
|
||||
func tailscaleCheck() check {
|
||||
problem := tailscale.Problem(context.Background())
|
||||
return check{Name: "Tailscale", Need: needRequired, For: "the server's HTTPS address and identity", OK: problem == "", Fix: problem}
|
||||
}
|
||||
|
||||
func command(name, need, purpose, fix string) check {
|
||||
_, err := exec.LookPath(name)
|
||||
return check{Name: name, Need: need, For: purpose, OK: err == nil, Fix: fix}
|
||||
}
|
||||
|
||||
func appCheck(name, need, purpose, fix string) check {
|
||||
_, err := os.Stat("/Applications/" + name + ".app")
|
||||
return check{Name: name, Need: need, For: purpose, OK: err == nil, Fix: fix}
|
||||
}
|
||||
|
||||
func markBlocking(cs []check) bool {
|
||||
agentOK := false
|
||||
for _, c := range cs {
|
||||
agentOK = agentOK || (c.Need == needAgent && c.OK)
|
||||
}
|
||||
ready := true
|
||||
for i, c := range cs {
|
||||
cs[i].Blocking = !c.OK && (c.Need == needRequired || (c.Need == needAgent && !agentOK))
|
||||
ready = ready && !cs[i].Blocking
|
||||
}
|
||||
return ready
|
||||
}
|
||||
|
||||
func checkCmd() {
|
||||
cs := checks()
|
||||
ready := markBlocking(cs)
|
||||
out, err := json.Marshal(struct {
|
||||
Ready bool `json:"ready"`
|
||||
Checks []check `json:"checks"`
|
||||
}{ready, cs})
|
||||
if err != nil {
|
||||
fatal("encode checks", "err", err)
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
|
||||
func requireChecks() {
|
||||
cs := checks()
|
||||
if markBlocking(cs) {
|
||||
return
|
||||
}
|
||||
fmt.Println("byre can't run on this Mac yet. It needs git, Tailscale, and at least one of claude, codex and agy:")
|
||||
for _, c := range cs {
|
||||
if c.Blocking {
|
||||
fmt.Printf(" %s: %s\n", c.Name, c.Fix)
|
||||
}
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -44,6 +44,7 @@ const plistTemplate = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
`
|
||||
|
||||
func installCmd() {
|
||||
requireChecks()
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
fatal("find executable", "err", err)
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@ func main() {
|
||||
serveCmd(os.Args[2:])
|
||||
case "install":
|
||||
installCmd()
|
||||
case "check":
|
||||
checkCmd()
|
||||
case "run":
|
||||
runCmd(os.Args[2:])
|
||||
default:
|
||||
@@ -24,7 +26,7 @@ func main() {
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, "usage: byre serve | byre install | byre run [--resume ID]")
|
||||
fmt.Fprintln(os.Stderr, "usage: byre serve | byre install | byre check | byre run [--resume ID]")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user