// rofi's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): its implementation of // node-launcher's verb `menu` — the dmenu-compatible command as a tool — and its own tools, served by // the node's runtime as the operator account. package main import ( "fmt" "os" stdio "git.novox.be/novox/mesh-sdk/go" ) 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: "node-launcher.menu", Description: fmt.Sprintf("Show a list in the operator's session and answer the line they choose: "+ "the launcher's dmenu-compatible command as a tool. Answers chosen and its index, or cancelled "+ "when they closed it or did not answer within timeout_seconds (default %d, at most %d).", menuDefault, menuMost), Input: map[string]any{ "type": "object", "properties": map[string]any{ "items": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "the choices, one line each"}, "prompt": map[string]any{"type": "string", "description": "the prompt (default: Choose)"}, "message": map[string]any{"type": "string", "description": "a line of explanation above the list"}, "allow_custom": map[string]any{"type": "boolean", "description": "accept a typed answer that is not in the list (default false)"}, "timeout_seconds": map[string]any{"type": "integer", "description": fmt.Sprintf("give up after this long (default %d, at most %d)", menuDefault, menuMost)}, }, "required": []string{"items"}, }, Run: func(args map[string]any) (any, error) { q, err := menuQuestion(args) if err != nil { return nil, err } return Menu(q) }, }, { Name: "rofi_applications", Description: "The desktop applications the launcher offers on this machine, from every desktop entry " + "directory in the order the launcher reads them (the account's first): id, name, what it runs, " + "categories and the file. Hidden entries are left out unless asked for.", Input: map[string]any{ "query": map[string]any{"type": "string", "description": "only entries whose name, generic name, keywords or command contain this (any case)"}, "show_hidden": map[string]any{"type": "boolean", "description": "include entries marked NoDisplay or Hidden (default false)"}, "limit": map[string]any{"type": "integer", "description": "at most this many (default 200, at most 2000)"}, }, Run: func(args map[string]any) (any, error) { query, err := text(args, "query", false) if err != nil { return nil, err } hidden, err := flag(args, "show_hidden", false) if err != nil { return nil, err } limit, err := whole(args, "limit", 200, 1, 2000) if err != nil { return nil, err } return Applications(applicationDirs(), query, hidden, limit), nil }, }, { Name: "rofi_themes", Description: "The launcher's themes on this machine — the mesh's, the operator's own and the " + "distribution's — each with its file, and which one the configuration uses.", Run: func(map[string]any) (any, error) { return Themes(themeDirs(), configFile()), nil }, }, { Name: "rofi_run", Description: "Start a program in the operator's session, as the launcher would: a desktop entry by " + "its id (firefox.desktop), or a command as its words. It runs under the account's own service " + "manager, so it outlives this call; answers the unit it runs as and what it ran.", Input: map[string]any{ "application": map[string]any{"type": "string", "description": "a desktop entry id, as rofi_applications answers it"}, "command": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "a program and its arguments, one word each"}, }, Run: func(args map[string]any) (any, error) { app, err := text(args, "application", false) if err != nil { return nil, err } command, err := texts(args, "command") if err != nil { return nil, err } return Run(app, command) }, }, } }