LXC deployment: live config for agentd-01, oregon rollback config, win10 helpers and board protocol in the repo

- config/agentd.yaml is now the agentd-01 live config (state /var/lib/plane-agentd, logs /var/log/plane-agentd);
  config/agentd.oregon.yaml keeps the oregon dispatcher settings for rollback (cron/agentd-tick.sh uses it).
- cron/agentd-tick-lxc.sh: the LXC cron entry.
- tools/win10/: win10-ps.sh / win10-put.sh (vault client dir via AGENT_ACCESS_HOME); relative helpers_dir
  resolves against the repo, default tools/win10.
- config/protocols/gwent-board-protocol.md: copy of gwent/design/board-protocol.md used in prompts.
- agentd.log_dir (default state_dir).
- smoke --watch: create the item and wait for the scheduled dispatcher instead of ticking locally.
This commit is contained in:
jj.wang
2026-10-21 11:56:15 +00:00
parent 4f45d368ad
commit 27ea9119a5
12 changed files with 230 additions and 20 deletions
+7 -3
View File
@@ -121,15 +121,17 @@ def cmd_smoke(cfg, a):
body["labels"] = [labels[x] for x in a.labels.split(",")]
issue = pl.create_issue(p["id"], body)
key = "%s-%s" % (p.get("key_prefix", a.project), issue["sequence_id"])
print("created %s; ticking every %ss (timeout %s min)" % (key, a.interval, a.timeout))
d = Agentd(cfg)
print("created %s; %s every %ss (timeout %s min)" % (
key, "watching (the scheduled dispatcher runs it)" if a.watch else "ticking", a.interval, a.timeout), flush=True)
d = None if a.watch else Agentd(cfg)
states = pl.states(p["id"])
done_states = {states[p["states"][k]] for k in ("review", "waiting")}
deadline = time.time() + a.timeout * 60
state = None
while time.time() < deadline:
try:
d.tick(project=a.project, only_issue=issue["id"])
if d:
d.tick(project=a.project, only_issue=issue["id"])
except Busy as exc:
print("skip: %s" % exc)
state = pl.get_issue(p["id"], issue["id"]).get("state")
@@ -199,6 +201,8 @@ def parser():
s.add_argument("--interval", type=int, default=30)
s.add_argument("--timeout", type=int, default=30, help="minutes")
s.add_argument("--labels", default="", help="comma-separated Plane labels, e.g. model:sol")
s.add_argument("--watch", action="store_true",
help="do not tick here; only wait for the scheduled dispatcher (use when it runs on another host)")
s.add_argument("--as", dest="as_")
s.set_defaults(fn=cmd_smoke)
sub.add_parser("check-config", help="validate the config and list token env vars").set_defaults(fn=cmd_check_config)
+12 -2
View File
@@ -155,8 +155,18 @@ class Config:
return p if p.is_absolute() else ROOT / p
def helpers_dir(self, terminal):
d = self.terminals[terminal].get("helpers_dir") or self.agentd.get("helpers_dir") or str(ROOT / "tools")
return Path(os.path.expanduser(d))
d = self.terminals[terminal].get("helpers_dir") or self.agentd.get("helpers_dir") or "tools/win10"
p = Path(os.path.expanduser(d))
return p if p.is_absolute() else ROOT / p
@property
def log_dir(self):
"""agentd.log lives here (default: state_dir)."""
d = self.agentd.get("log_dir")
if not d:
return self.state_dir
p = Path(os.path.expanduser(d))
return p if p.is_absolute() else ROOT / p
def token_env(self, terminal):
"""Environment variable that carries the terminal's Plane token (== the Vault key name)."""
+4 -3
View File
@@ -17,8 +17,9 @@ class Busy(Exception):
class Store:
def __init__(self, state_dir, echo=True):
def __init__(self, state_dir, echo=True, log_dir=None):
self.dir = Path(state_dir)
self.log_dir = Path(log_dir) if log_dir else self.dir
self.echo = echo
self.path = self.dir / "agentd-state.json"
@@ -59,9 +60,9 @@ class Store:
self._atomic_write(self.dir / "heartbeat.json", info)
def log(self, msg):
self.dir.mkdir(parents=True, exist_ok=True)
self.log_dir.mkdir(parents=True, exist_ok=True)
line = time.strftime("%Y-%m-%dT%H:%M:%S") + " " + msg
if self.echo:
print(line, flush=True)
with open(self.dir / "agentd.log", "a", encoding="utf-8") as fh:
with open(self.log_dir / "agentd.log", "a", encoding="utf-8") as fh:
fh.write(line + "\n")