diff --git a/agentd/config.py b/agentd/config.py index 652b638..e5acff0 100644 --- a/agentd/config.py +++ b/agentd/config.py @@ -91,11 +91,19 @@ def semantic_errors(data): for ex in t.get("executors", []): if ex not in execs: errs.append("terminals.%s: unknown executor '%s'" % (tname, ex)) - if t.get("transport") == "warpgate-ssh": - if t.get("os") != "windows" or t.get("launch") != "schtasks": - errs.append("terminals.%s: warpgate-ssh currently supports only os=windows, launch=schtasks" % tname) - if t.get("target") != "win10": - errs.append("terminals.%s: warpgate-ssh helper scripts only reach target 'win10' for now" % tname) + if t.get("transport") == "warpgate-ssh" and t.get("os") == "windows": + if t.get("launch") != "schtasks": + errs.append("terminals.%s: warpgate-ssh on windows needs launch=schtasks" % tname) + if t.get("target", tname) != "win10": + errs.append("terminals.%s: the Windows helper scripts only reach target 'win10' for now" % tname) + elif t.get("transport") == "warpgate-ssh": + if t.get("launch") != "nohup": + errs.append("terminals.%s: warpgate-ssh on %s needs launch=nohup" % (tname, t.get("os"))) + for key in ("repo", "run_root"): + if key in t and not str(t[key]).startswith("/"): + errs.append("terminals.%s.%s: must be an absolute path on the remote (no ~)" % (tname, key)) + if not data.get("vault", {}).get("config"): + errs.append("terminals.%s: remote POSIX terminals need vault.config (relay identity)" % tname) if t.get("transport") == "local" and t.get("os") != "linux": errs.append("terminals.%s: local transport supports only os=linux" % tname) for ename, e in execs.items(): diff --git a/agentd/executors/base.py b/agentd/executors/base.py index ca9dc9b..37f0c14 100644 --- a/agentd/executors/base.py +++ b/agentd/executors/base.py @@ -87,13 +87,16 @@ class RunnerExecutor(Executor): def start(self, run): t = self.transport run_dir = t.join(self.run_root(), run.run_id) - t.mkdir(run_dir, clean=True) - t.write_text(t.join(run_dir, "prompt.md"), run.prompt) script_name, script = t.runner(run_dir, run.repo, self.command(run, run_dir), self.stdout_name) - script_path = t.join(run_dir, script_name) - t.write_text(script_path, script) task = "agentd-" + run.run_id - t.launch(task, script_path, run_dir) + files = {"prompt.md": run.prompt, script_name: script} + if hasattr(t, "start_run"): # remote POSIX: stage + launch in one relay round trip + t.start_run(task, run_dir, files, script_name) + else: + t.mkdir(run_dir, clean=True) + for name, text in files.items(): + t.write_text(t.join(run_dir, name), text) + t.launch(task, t.join(run_dir, script_name), run_dir) return {"run_dir": run_dir, "task": task, "thread_id": run.thread_id} def poll(self, handle): diff --git a/agentd/transports/local.py b/agentd/transports/local.py index 5d49830..e5563fa 100644 --- a/agentd/transports/local.py +++ b/agentd/transports/local.py @@ -4,17 +4,23 @@ import signal import subprocess from pathlib import Path +# Shared with the remote POSIX transport (warpgate_ssh): plain sh + `date +FMT`, so it also runs on macOS. RUNNER = """#!/usr/bin/env bash -cd {cwd} || {{ echo "exit=97 at $(date -Is) (cd failed)" > {d}/exit.txt; exit 97; }} +cd {cwd} || {{ echo "exit=97 at $(date +%Y-%m-%dT%H:%M:%S%z) (cd failed)" > {d}/exit.txt; exit 97; }} echo $$ > {d}/pid.txt -date -Is > {d}/started.txt +date +%Y-%m-%dT%H:%M:%S%z > {d}/started.txt ( {command} ) < {d}/prompt.md > {d}/{stdout} 2> {d}/stderr.txt -echo "exit=$? at $(date -Is)" > {d}/exit.txt +echo "exit=$? at $(date +%Y-%m-%dT%H:%M:%S%z)" > {d}/exit.txt """ +def sh_quote(s): + """POSIX shell single-quote literal (always quoted, `'` -> `'\\''`).""" + return "'" + str(s).replace("'", "'\\''") + "'" + + class LocalTransport: os = "linux" @@ -28,7 +34,7 @@ class LocalTransport: return os.path.join(*parts) def quote(self, s): - return "'" + str(s).replace("'", "'\\''") + "'" + return sh_quote(s) def mkdir(self, path, clean=False): p = Path(path) diff --git a/agentd/transports/warpgate_ssh.py b/agentd/transports/warpgate_ssh.py index 82ae0f3..eaad1a4 100644 --- a/agentd/transports/warpgate_ssh.py +++ b/agentd/transports/warpgate_ssh.py @@ -1,16 +1,59 @@ -"""Windows terminal behind Warpgate, reached through the server-access relay helper scripts: - win10-ps.sh