// The fonts module's tools (novox/hq research 026/04, 026/05): what faces the account has, what the // generic families resolve to, which face draws a character, which font files were copied by hand // and may go, and rebuilding the font cache. A Go bundle the node's runtime launches and speaks MCP // to over stdio (ADR 0188, ADR 0193); it runs as the operator account. package main import ( "fmt" "os" stdio "git.novox.be/novox/mesh-sdk/go" ) // providedBy names what installs a program the tools run, for a failure that says so. var providedBy = map[string]string{ "fc-list": "the fontconfig package", "fc-match": "the fontconfig package", "fc-scan": "the fontconfig package", "fc-cache": "the fontconfig package", "fc-conflist": "the fontconfig package", "pacman": "this is not an Arch machine", } func main() { if err := stdio.Serve("", tools()); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func tools() []stdio.Tool { return []stdio.Tool{ { Name: "fonts_families", Description: "The font families installed for the operator account, each with its styles, how many files, " + "whether it is monospaced, and where it comes from: package (under /usr/share/fonts), account (copied into " + "the home by hand) or other. (r)", Input: map[string]any{ "contains": map[string]any{"type": "string", "description": "only families whose name contains this, any case"}, "limit": map[string]any{"type": "integer", "description": "at most this many families (default 500, at most 2000)"}, }, Run: func(args map[string]any) (any, error) { contains, err := optText(args, "contains", "") if err != nil { return nil, err } limit, err := optWhole(args, "limit", 500, 1, 2000) if err != nil { return nil, err } return Families(contains, limit) }, }, { Name: "fonts_match", Description: "What the generic families resolve to for this account: monospace, sans-serif, system-ui, serif and " + "emoji by default, or the patterns given. Each answer names the face, its file, the face the fonts module " + "decided on, and whether they agree. (r)", Input: map[string]any{ "patterns": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "fontconfig patterns to resolve instead, such as \"monospace:bold\" or \"Inter\""}, }, Run: func(args map[string]any) (any, error) { patterns, err := optList(args, "patterns") if err != nil { return nil, err } return Match(patterns) }, }, { Name: "fonts_glyph", Description: "Which installed fonts have a given character, and which face monospace and sans-serif would draw " + "it with. The character is given as itself or as a code point (U+F120, 0xF120). (r)", Input: map[string]any{ "character": map[string]any{"type": "string", "description": "one character, or its code point as U+XXXX or 0xXXXX"}, }, Run: func(args map[string]any) (any, error) { ch, err := text(args, "character") if err != nil { return nil, err } return Glyph(ch) }, }, { Name: "fonts_sources", Description: "Every font file copied into the account's font directories by hand, with its family, whether it " + "duplicates another, and whether a package now provides that family; and the families installed by " + "packages, with the package. Says which hand-copied files can be removed and why; removes nothing. (r)", Input: map[string]any{}, Run: func(map[string]any) (any, error) { return Sources() }, }, { Name: "fonts_config", Description: "The fontconfig file the fonts module owns: whether it is in place, whether fontconfig loads it, " + "and the account's other fontconfig files beside it. (r)", Input: map[string]any{}, Run: func(map[string]any) (any, error) { return Config() }, }, { Name: "fonts_cache_rebuild", Description: "Rebuild the font cache: the account's (default), or the system's with system: true, which needs " + "root and goes through sudo without a prompt. Answers how long it took. (a)", Input: map[string]any{ "system": map[string]any{"type": "boolean", "description": "rebuild the system cache instead of the account's"}, }, Run: func(args map[string]any) (any, error) { system, err := optFlag(args, "system", false) if err != nil { return nil, err } return CacheRebuild(system) }, }, } }