colibri/scripts/colibri_poll.py
Sam & Claude f3d8532dbd
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
feat(freebsd): cross-host TCP bridge + agent polling loop
- colibri_bridge.in: socat rc.d bridge, binds Tailscale IP
  only, REQUIRE: colibri_daemon for boot ordering
- newsyslog-colibri-bridge.conf: bridge log rotation
- colibri-agent-loop.md: document Hermes cronjob setup
  (2min poller + 5min worker, NOT system cron)
- colibri_poll.py: socket-based task poller, filters by
  agent UUID
- colibri_task_done.py: transition-task via raw socket
- colibri_daemon.in: drop 'local' (not POSIX), add
  status_cmd() for FreeBSD rc.subr compatibility

Live and tested on osa (FreeBSD 15.0).
2026-06-19 12:18:52 +02:00

76 lines
2.1 KiB
Python
Executable file

#!/usr/bin/env python3
"""Colibri task poller — checks the board for tasks assigned to an agent.
Defaults from env vars so cron can run it without arguments.
Matches by agent UUID (COLIBRI_AGENT_ID) since tasks reference agent_id, not name.
Queries COLIBRI_SOCKET directly, no CLI dependency needed."""
import json
import os
import socket
import sys
import time
AGENT_ID = os.environ.get("COLIBRI_AGENT_ID", "")
SOCKET_PATH = os.environ.get("COLIBRI_SOCKET", "/var/run/colibri/colibri.sock")
def _send_cmd(cmd: dict) -> dict:
"""Send a JSON command to the Colibri daemon socket, return response."""
payload = (json.dumps(cmd) + "\n").encode()
try:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.settimeout(5)
sock.connect(SOCKET_PATH)
sock.sendall(payload)
sock.shutdown(socket.SHUT_WR)
chunks = []
while True:
data = sock.recv(4096)
if not data:
break
chunks.append(data)
sock.close()
return json.loads(b"".join(chunks).decode())
except Exception as e:
print(json.dumps({"error": str(e)}))
sys.exit(0)
def resolve_agent_id(name_or_id: str) -> str:
"""If given a UUID, return it. If given a name, look up the ID from the daemon."""
if len(name_or_id) > 30 and "-" in name_or_id:
return name_or_id # looks like a UUID
resp = _send_cmd({"cmd": "list-agents"})
if not resp.get("ok"):
return name_or_id
for agent in resp.get("data", []):
if agent.get("name") == name_or_id:
return agent["id"]
return name_or_id
def main():
agent_id = resolve_agent_id(AGENT_ID)
if not agent_id:
print("[]")
sys.exit(0)
resp = _send_cmd({"cmd": "list-tasks", "status": "started"})
if not resp.get("ok"):
print("[]")
sys.exit(0)
tasks = resp.get("data", [])
mine = [t for t in tasks if t.get("agent_id") == agent_id]
if mine:
print(json.dumps(mine, indent=2))
else:
print("[]")
if __name__ == "__main__":
main()