Removes brain_write legacy domain/type/knowledge-path params (ADR-0012) and migrates the previously-missed cmd/hyperguild CLI caller (hyperguild brain write) from <type> <slug> to <wing> <hall> <slug>, fixing a 100%% regression the first review round caught. Adds TestWrite_CLIPayloadRoundTrips exercising the real Handler.Write over HTTP to pin the wire contract. Closes #79. Co-authored-by: Mathias <mthbqv@gmail.com>
108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
func runBrain(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) error {
|
|
if len(args) == 0 {
|
|
return errors.New("subcommand required (query|write|pass-rate)")
|
|
}
|
|
switch args[0] {
|
|
case "query":
|
|
return runBrainQuery(ctx, args[1:], stdin, stdout, stderr)
|
|
case "write":
|
|
return runBrainWrite(ctx, args[1:], stdin, stdout, stderr)
|
|
case "pass-rate":
|
|
return runBrainPassRate(ctx, args[1:], stdin, stdout, stderr)
|
|
default:
|
|
return fmt.Errorf("unknown subcommand: %s (expected query|write|pass-rate)", args[0])
|
|
}
|
|
}
|
|
|
|
func runBrainQuery(ctx context.Context, args []string, _ io.Reader, stdout, stderr io.Writer) error {
|
|
fs := flag.NewFlagSet("brain query", flag.ContinueOnError)
|
|
fs.SetOutput(stderr)
|
|
asJSON := fs.Bool("json", false, "output JSON instead of human-readable")
|
|
limit := fs.Int("limit", 5, "maximum number of results")
|
|
if err := fs.Parse(args); err != nil {
|
|
return fmt.Errorf("parse flags: %w", err)
|
|
}
|
|
if fs.NArg() < 1 {
|
|
return errors.New("topic required")
|
|
}
|
|
topic := fs.Arg(0)
|
|
|
|
res, err := newBrainClient().Query(ctx, topic, *limit)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if *asJSON {
|
|
enc := json.NewEncoder(stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(res)
|
|
}
|
|
for _, hit := range res.Results {
|
|
fmt.Fprintf(stdout, "%s score=%d %s\n", hit.Path, hit.Score, hit.Title) //nolint:errcheck
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func runBrainWrite(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) error {
|
|
fs := flag.NewFlagSet("brain write", flag.ContinueOnError)
|
|
fs.SetOutput(stderr)
|
|
if err := fs.Parse(args); err != nil {
|
|
return fmt.Errorf("parse flags: %w", err)
|
|
}
|
|
if fs.NArg() < 3 {
|
|
return errors.New("wing, hall and slug required (e.g. brain write homelab facts my-slug)")
|
|
}
|
|
wing := fs.Arg(0)
|
|
hall := fs.Arg(1)
|
|
slug := fs.Arg(2)
|
|
|
|
res, err := newBrainClient().Write(ctx, wing, hall, slug, stdin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintln(stdout, res.Path) //nolint:errcheck
|
|
return nil
|
|
}
|
|
|
|
func runBrainPassRate(ctx context.Context, args []string, _ io.Reader, stdout, stderr io.Writer) error {
|
|
fs := flag.NewFlagSet("brain pass-rate", flag.ContinueOnError)
|
|
fs.SetOutput(stderr)
|
|
asJSON := fs.Bool("json", false, "output JSON instead of human-readable")
|
|
window := fs.String("window", "7d", "lookback window (e.g. 1h, 24h, 7d, 30d)")
|
|
if err := fs.Parse(args); err != nil {
|
|
return fmt.Errorf("parse flags: %w", err)
|
|
}
|
|
if fs.NArg() < 1 {
|
|
return errors.New("skill required")
|
|
}
|
|
skill := fs.Arg(0)
|
|
|
|
res, err := newBrainClient().PassRate(ctx, skill, *window)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if *asJSON {
|
|
enc := json.NewEncoder(stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(res)
|
|
}
|
|
if res.PassRate == nil {
|
|
fmt.Fprintf(stdout, "%s: no data (window: %s)\n", res.Skill, res.Window) //nolint:errcheck
|
|
return nil
|
|
}
|
|
fmt.Fprintf(stdout, "%s: %d / %d = %.0f%% (window: %s)\n", res.Skill, res.Pass, res.Total, *res.PassRate*100, res.Window) //nolint:errcheck
|
|
return nil
|
|
}
|