// localization's tools bundle (novox/hq to-be 42 Phase 1, research 026/05), and its step. // // Served by the node's runtime over MCP on stdio through the Go SDK (ADR 0188, ADR 0193) when it is // started with no arguments. Started as `localization-tools set-time-zone ` it is instead the // module's step, which the host runs once as root for every version of the bundle (localization.go // says why the time zone is a step and not a file). package main import ( "context" "fmt" "os" stdio "git.novox.be/novox/mesh-sdk/go" ) // binaryName is what the build names this bundle's executable: the manifest's `binary`. const binaryName = "localization-tools" func bg() context.Context { return context.Background() } func main() { m := ThisMachine() if len(os.Args) > 1 { if len(os.Args) != 3 || os.Args[1] != "set-time-zone" { fmt.Fprintf(os.Stderr, "usage: %s [set-time-zone ]\n", binaryName) os.Exit(2) } said, err := m.SetTimeZoneStep(os.Args[2]) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } fmt.Println(said) return } // An empty name serves as the module the runtime names (MESH_SERVED_MODULE): localization. if err := stdio.Serve("", tools(m)); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func tools(m *Machine) []stdio.Tool { return []stdio.Tool{ { Name: "localization_get", Description: "The machine's locale (LANG and every LC_* localed reports), whether LANG is generated, its time zone, " + "whether the clock keeps local time, whether NTP is on and synchronised, the console keymap and the X11 keyboard " + "settings — and for each of locale, zone and keymap whether it is what the module declares " + "(en_US.UTF-8, Europe/Brussels, us).", Input: schema(map[string]any{}), Run: func(map[string]any) (any, error) { return m.Get() }, }, { Name: "localization_time_zone", Description: "The time zone: read it; list the zones matching a word (match); or set one (set), through the time " + "daemon with sudo -n, read back after. The module declares Europe/Brussels and its step sets it again " + "whenever the module's bundle changes, which the answer says when another zone is set.", Input: schema(map[string]any{ "set": map[string]any{"type": "string", "description": "a zone to set, as timedatectl list-timezones names it (optional)"}, "match": map[string]any{"type": "string", "description": "list the zones whose name holds this word (optional)"}, }), Run: func(args map[string]any) (any, error) { set, err := text(args, "set", false) if err != nil { return nil, err } match, err := text(args, "match", false) if err != nil { return nil, err } return m.TimeZone(set, match) }, }, { Name: "localization_locales", Description: "The locales: generated (locale -a), enabled in /etc/locale.gen, the LANG of /etc/locale.conf and " + "whether it is generated, and how many glibc can generate — listed when a word narrows them (match).", Input: schema(map[string]any{ "match": map[string]any{"type": "string", "description": "list the generatable locales whose name holds this word (optional)"}, }), Run: func(args map[string]any) (any, error) { match, err := text(args, "match", false) if err != nil { return nil, err } return m.Locales(match) }, }, { Name: "localization_keymaps", Description: "The console keymap in force and the keymaps this machine has (localectl list-keymaps), narrowed to a word when given; at most 500 listed.", Input: schema(map[string]any{ "match": map[string]any{"type": "string", "description": "list only keymaps whose name holds this word (optional)"}, }), Run: func(args map[string]any) (any, error) { match, err := text(args, "match", false) if err != nil { return nil, err } return m.Keymaps(match) }, }, } }