--- name: services_status kind: function lang: go domain: infra version: "1.0.0" purity: impure signature: "func ServicesStatus(registryRoot string) ([]ServiceStatus, error)" description: "Lista todas las apps registradas con tag 'service' y reporta su estado: unidad systemd activa, puerto escuchando, y pc_id local." tags: [doctor, systemd, services, health] uses_functions: [] uses_types: - error_go_core returns: [] returns_optional: false error_type: "error_go_core" imports: - database/sql - net - os - os/exec - regexp - github.com/mattn/go-sqlite3 tested: true tests: - "sin apps registradas retorna slice vacio sin error" - "DB inexistente retorna error" - "parseFirstPort extrae primer puerto valido" - "readFnPC ignora comentarios y retorna primer valor" test_file_path: "functions/infra/services_status_test.go" file_path: "functions/infra/services_status.go" params: - name: registryRoot desc: "Ruta absoluta al directorio raiz del registry (donde vive registry.db)" output: "Slice de ServiceStatus con estado systemd, puerto y pc_id por cada app con tag 'service'. Error si no se puede abrir registry.db." --- ## Ejemplo ```go statuses, err := ServicesStatus("/home/lucas/fn_registry") if err != nil { log.Fatal(err) } for _, s := range statuses { fmt.Printf("%s unit=%s port=%d listening=%v\n", s.Name, s.UnitActive, s.Port, s.PortListening) } ``` ## Notas - `UnitName` se asume `.service`. Si la app usa otro nombre, el estado sera `not-installed`. - La heuristica de puerto busca el primer entero en `[1024, 65535]` en `notes` o `description`. Si la app menciona varios numeros, toma el primero que encaje. Puede fallar si `notes` contiene IDs numericos antes que el puerto real. - `UnitActive` intenta `systemctl --user is-active` primero; si el unit no se encuentra, reintenta con scope de sistema. Valores posibles: `active`, `inactive`, `failed`, `not-installed`, `unknown`. - `PortListening` hace un dial TCP a `127.0.0.1:` con timeout 500ms. Solo aplica si `Port > 0`. - `HostMatch` lee `~/.fn_pc` — primer linea no vacia no comentada.