Bootstrap tamq local tmux agent message queue
Some checks failed
tamq-ci / test (push) Failing after 36s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02f34-ead4-7a60-85cd-d7f08e22fa0e
This commit is contained in:
tegwick 2026-08-24 01:18:40 +02:00
parent 521bbe5afc
commit 4d915a2617
58 changed files with 1882 additions and 1 deletions

77
src/tamq/tmux.py Normal file
View file

@ -0,0 +1,77 @@
from __future__ import annotations
import os
import shlex
from uuid import uuid4
import subprocess
from dataclasses import dataclass
from .registry import repository_paths, validate_targets
class TmuxError(RuntimeError):
pass
@dataclass
class Endpoint:
session: str
pid: int
repos: list[str]
instance_id: str = ""
@property
def endpoint_id(self) -> str:
return f"tmux-amq-{self.pid}"
@property
def instance_key(self) -> str:
return self.instance_id or self.endpoint_id
class TmuxManager:
def __init__(self, session: str = "tamq"):
self.session = session
def _run(self, *args: str, check: bool = True) -> str:
result = subprocess.run(["tmux", *args], text=True, capture_output=True, check=False)
if check and result.returncode:
raise TmuxError(result.stderr.strip() or "tmux command failed")
return result.stdout.strip()
def ensure(self, repos: list[str], command: str = "codex") -> Endpoint:
if not repos:
raise TmuxError("at least one repository is required")
try:
validate_targets(repos)
except Exception as exc:
raise TmuxError(str(exc)) from exc
result = subprocess.run(["tmux", "has-session", "-t", self.session], capture_output=True)
if result.returncode != 0:
self._run("new-session", "-d", "-s", self.session, "-n", "__tamq_boot", "-c", os.getcwd(), "sleep", "infinity")
pid_text = self._run("display-message", "-p", "-t", self.session, "#{pid}")
try:
pid = int(pid_text)
except ValueError as exc:
raise TmuxError(f"unable to determine tmux PID: {pid_text!r}") from exc
endpoint = Endpoint(self.session, pid, list(dict.fromkeys(repos)), f"tmux-amq-{pid}-{uuid4().hex[:12]}")
paths = repository_paths()
windows = self._run("list-windows", "-t", self.session, "-F", "#{window_name}").splitlines()
for index, repo in enumerate(endpoint.repos):
if repo not in windows:
if index == 0 and "__tamq_boot" in windows:
self._run("rename-window", "-t", f"{self.session}:__tamq_boot", repo)
windows[windows.index("__tamq_boot")] = repo
else:
try:
repo_path = paths[repo]
except KeyError as exc:
raise TmuxError(f"gita path missing for registered repository: {repo}") from exc
self._run("new-window", "-d", "-t", self.session, "-n", repo, "-c", repo_path, "sleep", "infinity")
tap = ["tamq", "tap", "--repo", repo, "--endpoint", endpoint.endpoint_id, "--", command]
self._run("send-keys", "-t", f"{self.session}:{repo}", shell_join(tap), "C-m")
return endpoint
def shell_join(parts: list[str]) -> str:
return " ".join(shlex.quote(part) for part in parts)