Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

62 lines · 2.0 KBRaw History
1/**
2 * The terminal's pseudo-terminal, as a small Python program (standard library only, so the image
3 * needs no native Node module). It forks a login shell on a PTY, copies its stdin to the PTY and the
4 * PTY to its stdout, and reads control lines (JSON) on fd 3: `{"cols": 120, "rows": 40}` resizes.
5 * It exits with the shell.
6 */
7export const PTY_HELPER = String.raw`
8import fcntl, json, os, pty, select, signal, struct, sys, termios
9
10def winsize(fd, rows, cols):
11 fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", rows, cols, 0, 0))
12
13pid, fd = pty.fork()
14if pid == 0:
15 shell = os.environ.get("SHELL") or "/bin/bash"
16 os.execvp(shell, [shell, "-l"])
17
18winsize(fd, int(os.environ.get("DIFFINERY_PTY_ROWS", "24")), int(os.environ.get("DIFFINERY_PTY_COLS", "80")))
19stdin, stdout = sys.stdin.fileno(), sys.stdout.fileno()
20pending = b""
21watch = [fd, stdin, 3]
22while True:
23 try:
24 ready, _, _ = select.select(watch, [], [])
25 except InterruptedError:
26 continue
27 if fd in ready:
28 try:
29 data = os.read(fd, 65536)
30 except OSError:
31 data = b""
32 if not data:
33 break
34 os.write(stdout, data)
35 if stdin in ready:
36 data = os.read(stdin, 65536)
37 if not data:
38 watch.remove(stdin)
39 else:
40 os.write(fd, data)
41 if 3 in ready:
42 data = os.read(3, 4096)
43 if not data:
44 watch.remove(3)
45 continue
46 pending += data
47 while b"\n" in pending:
48 line, pending = pending.split(b"\n", 1)
49 try:
50 m = json.loads(line)
51 rows, cols = int(m["rows"]), int(m["cols"])
52 if 1 <= rows <= 1000 and 1 <= cols <= 1000:
53 winsize(fd, rows, cols)
54 except Exception:
55 pass
56try:
57 os.kill(pid, signal.SIGHUP)
58except OSError:
59 pass
60_, status = os.waitpid(pid, 0)
61sys.exit(os.waitstatus_to_exitcode(status) if hasattr(os, "waitstatus_to_exitcode") else 0)
62`;