Files
alex b7fea83ed6 feat(bridge): establish local pi status bridge
Deliver the initial local bridge, Noctalia v4/v5 adapters, desktop client, service unit, tests, and implementation documentation for persistent Pi status and control.
2026-07-27 14:51:45 +02:00

90 lines
3.1 KiB
Lua

local request_in_flight = false
local function shell_quote(value)
return "'" .. string.gsub(value, "'", "'\\\"'\\\"'") .. "'"
end
local function ui_binary()
local configured = noctalia.getenv("PI_STATUS_UI_BINARY")
if configured ~= nil and configured ~= "" then return configured end
return (noctalia.getenv("HOME") or "") .. "/projects/pi-status-bridge/ui/src-tauri/target/release/pi-status-ui"
end
local function socket_path()
local runtime = noctalia.getenv("XDG_RUNTIME_DIR")
if runtime == nil or runtime == "" then return nil end
return runtime .. "/pi-status-bridge/bridge.sock"
end
local function current_agent_id()
return noctalia.state.get("agent_id")
end
local function discover_home_agent(socket)
if request_in_flight then return end
request_in_flight = true
noctalia.runAsync("pi-status-bridge-client --socket \"" .. socket .. "\" request '{\"op\":\"list_agents\"}'", function(result)
request_in_flight = false
if result.exitCode ~= 0 then return end
local home = noctalia.getenv("HOME")
for id, worktree in string.gmatch(result.stdout, "\"id\":\"([^\"]+)\",\"worktreePath\":\"([^\"]+)\"") do
if worktree == home then
noctalia.state.set("agent_id", id)
noctalia.state.set("project_path", worktree)
return
end
end
end)
end
function update()
noctalia.setUpdateInterval(2000)
local agent_id = current_agent_id()
local socket = socket_path()
if socket == nil then
barWidget.setGlyph("alert-triangle")
barWidget.setText("Pi offline")
barWidget.setTooltip("Bridge socket is unavailable")
return
end
if agent_id == nil then
discover_home_agent(socket)
barWidget.setGlyph("terminal-2")
barWidget.setText("Pi home")
barWidget.setTooltip("Starting the default Home agent; click to open Pi Status UI")
return
end
if request_in_flight then return end
request_in_flight = true
local command = "pi-status-bridge-client --socket \"" .. socket
.. "\" request '{\"op\":\"get_state\",\"agentId\":\"" .. agent_id .. "\"}'"
noctalia.runAsync(command, function(result)
request_in_flight = false
if result.exitCode ~= 0 then
noctalia.state.set("agent_id", nil)
discover_home_agent(socket)
barWidget.setGlyph("terminal-2")
barWidget.setText("Pi reconnecting")
barWidget.setTooltip("Refreshing the Home Pi agent")
return
end
local streaming = string.find(result.stdout, "\"isStreaming\":true", 1, true) ~= nil
barWidget.setGlyph(streaming and "terminal-2" or "terminal")
barWidget.setText(streaming and "Pi working" or "Pi ready")
barWidget.setTooltip(noctalia.state.get("project_path") or "Selected Pi folder")
end)
end
function onClick()
local command = "setsid -f env TMPDIR=/tmp " .. shell_quote(ui_binary())
.. " --show >/tmp/pi-status-ui.log 2>&1"
noctalia.runAsync(command, function(result)
if result.exitCode ~= 0 then
barWidget.setGlyph("alert-triangle")
barWidget.setText("Pi UI unavailable")
barWidget.setTooltip("Build Pi Status UI or set PI_STATUS_UI_BINARY")
end
end)
end