Files
mesh-catalog/modules/power/cmd/power/tools.go
T
jochen 6315556152 power: a machine's power as a module holding node-power; the laptop's resume and lid move onto it (hq ADR 0211)
Code around sleep was written into the service manager's sleep units by the module that needed it,
and the mesh could not tell a sleeping machine from a lost one. power runs every module's code for
the six moments, each piece bounded, owns logind's power handling from its settings, and says
booted, sleeping, woke, shutting-down and the power source on the bus, sleeping under logind's
delay lock before the machine sleeps.
2026-10-04 17:19:27 +02:00

82 lines
3.2 KiB
Go

package main
import (
"context"
"fmt"
"strings"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// Tools are the module's tools over MCP (novox/hq ADR 0211): the machine's power now, the code
// modules contributed for each moment, the recent power history, running one moment on demand, and
// the module's own check.
func Tools(m *Machine, w *Watcher) []stdio.Tool {
return []stdio.Tool{
{
Name: "power_state",
Description: "This machine's power now: since when it runs, mains or battery and the charge, the lid, " +
"logind's power-key and lid settings in force, and what the watcher last saw: its delay lock, " +
"the last sleep and wake, and events still waiting for the bus.",
Run: func(map[string]any) (any, error) { return m.State(w), nil },
},
{
Name: "power_hooks",
Description: "The code every module contributed for each power moment (after boot, on mains, on battery, " +
"before sleep, after waking, before shutdown), as placed on this machine, each piece with its module.",
Run: func(map[string]any) (any, error) { return m.Hooks(), nil },
},
{
Name: "power_history",
Description: "The machine's recent power events from the journal: each boot, every sleep and wake, and " +
"every moment's run with each module's outcome.",
Input: map[string]any{
"boots": map[string]any{"type": "integer", "description": "how many boots back (default 3, at most 20)"},
},
Run: func(args map[string]any) (any, error) {
n := 3
if v, ok := args["boots"].(float64); ok {
n = int(v)
}
if n < 1 || n > 20 {
return nil, fmt.Errorf("boots is 1 to 20")
}
return m.History(context.Background(), n)
},
},
{
Name: "power_run",
Description: "Run one moment's contributed code now, as the machine would, to test it: each module's " +
"piece on its own, bounded. `supply` runs on-mains or on-battery for the source the machine is on. " +
"Answers the runner's lines. Needs sudo -n.",
Input: map[string]any{
"type": "object",
"properties": map[string]any{
"moment": map[string]any{"type": "string", "enum": append(append([]string(nil), Moments...), "supply"),
"description": "the moment to run"},
},
"required": []string{"moment"},
},
Run: func(args map[string]any) (any, error) {
moment, _ := args["moment"].(string)
known := moment == "supply"
for _, mo := range Moments {
known = known || mo == moment
}
if !known {
return nil, fmt.Errorf("no moment %q; the moments are %s and supply", moment, strings.Join(Moments, ", "))
}
out, err := m.privileged(context.Background(), RunnerPath, moment, "--force")
return map[string]any{"moment": moment, "said": strings.Split(strings.TrimSpace(out), "\n")}, err
},
},
{
Name: "power_check",
Description: "Whether this machine's power handling is as the mesh declares it: the module's units enabled, " +
"the runner and every moment's file in place, logind's power file the mesh's and the only one, no " +
"hand-placed sleep hooks, the watcher's delay lock held and no events stuck before the bus.",
Run: func(map[string]any) (any, error) { return m.Check(context.Background(), w), nil },
},
}
}