Created
October 17, 2026 16:55
-
-
Save redraw/ab50078f854989b0bed0e74eabcbc13a to your computer and use it in GitHub Desktop.
cliente IRC, anthropic vs deepseek
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # agent: claude code | |
| # prompt: crea un cliente IRC en python super simple, sin usar librerias externas, para conectarte a https://puaj.club/irc/ | |
| # plan: opus 5.5 | |
| # build: sonnet 5.5 | |
| import os | |
| import random | |
| import socket | |
| import ssl | |
| import sys | |
| import threading | |
| HOST, PORT = "irc.puaj.club", 6697 | |
| nick = sys.argv[1] if len(sys.argv) > 1 else f"invitado{random.randint(100, 999)}" | |
| channel = sys.argv[2] if len(sys.argv) > 2 else "#puaj" | |
| password = os.environ.get("IRC_PASS") | |
| sock = ssl.create_default_context().wrap_socket( | |
| socket.create_connection((HOST, PORT)), server_hostname=HOST | |
| ) | |
| def send(line): | |
| sock.sendall((line + "\r\n").encode()) | |
| def handle(line): | |
| global nick | |
| prefix = "" | |
| if line.startswith(":"): | |
| prefix, line = line[1:].split(" ", 1) | |
| head, _, trailing = line.partition(" :") | |
| parts = head.split() | |
| cmd, args = parts[0], parts[1:] | |
| who = prefix.split("!")[0] | |
| if cmd == "PING": | |
| send("PONG :" + trailing) | |
| elif cmd == "001": | |
| print(trailing) | |
| if password: | |
| send(f"PRIVMSG NickServ :IDENTIFY {nick} {password}") | |
| send("JOIN " + channel) | |
| elif cmd == "433": | |
| nick += "_" | |
| send("NICK " + nick) | |
| elif cmd == "PRIVMSG": | |
| if trailing.startswith("\x01ACTION "): | |
| print(f"[{args[0]}] * {who} {trailing[8:].strip(chr(1))}") | |
| else: | |
| print(f"[{args[0]}] <{who}> {trailing}") | |
| elif cmd in ("JOIN", "PART", "QUIT"): | |
| print(f"-- {who} {cmd} {(args or [trailing])[0]}") | |
| elif cmd == "NICK": | |
| print(f"-- {who} ahora es {trailing or args[0]}") | |
| else: | |
| print(f"{cmd} {' '.join(args[1:])} {trailing}".strip()) | |
| def reader(): | |
| buf = b"" | |
| while True: | |
| data = sock.recv(4096) | |
| if not data: | |
| print("Conexión cerrada") | |
| os._exit(0) | |
| buf += data | |
| while b"\r\n" in buf: | |
| raw, buf = buf.split(b"\r\n", 1) | |
| handle(raw.decode("utf-8", errors="replace")) | |
| send("NICK " + nick) | |
| send(f"USER {nick} 0 * :{nick}") | |
| threading.Thread(target=reader, daemon=True).start() | |
| try: | |
| while True: | |
| text = input() | |
| if not text.startswith("/"): | |
| send(f"PRIVMSG {channel} :{text}") | |
| continue | |
| cmd, _, rest = text[1:].partition(" ") | |
| if cmd == "join": | |
| channel = rest | |
| send("JOIN " + rest) | |
| elif cmd == "msg": | |
| target, _, msg = rest.partition(" ") | |
| send(f"PRIVMSG {target} :{msg}") | |
| elif cmd == "me": | |
| send(f"PRIVMSG {channel} :\x01ACTION {rest}\x01") | |
| elif cmd == "nick": | |
| nick = rest | |
| send("NICK " + rest) | |
| elif cmd == "quit": | |
| break | |
| elif cmd == "raw": | |
| send(rest) | |
| else: | |
| print("Comandos: /join /msg /me /nick /raw /quit") | |
| except (EOFError, KeyboardInterrupt): | |
| pass | |
| send("QUIT :chau") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # agent: opencode | |
| # prompt: crea un cliente IRC en python super simple, sin usar librerias externas, para conectarte a https://puaj.club/irc/ | |
| # plan: deepseek pro 4.1 | |
| # build: deepseek flash 4.1 | |
| #!/usr/bin/env python3 | |
| """Cliente IRC minimo para puaj.club. Solo biblioteca estandar.""" | |
| import random | |
| import select | |
| import socket | |
| import ssl | |
| import sys | |
| HOST = "irc.puaj.club" | |
| PORT = 6697 | |
| CANAL = "#puaj" | |
| REALNAME = "cliente irc.py" | |
| AYUDA = """\ | |
| comandos: | |
| /join #canal entrar a un canal (o crearlo) | |
| /part [#canal] salir del canal | |
| /msg <nick> <texto> mensaje privado (ej: /msg NickServ identify nick pass) | |
| /me <texto> accion | |
| /nick <nuevo> cambiar de nick | |
| /quit desconectarse | |
| /help esta ayuda | |
| todo lo demas se manda como mensaje al canal actual.""" | |
| def parse(line): | |
| """Separa una linea IRC en (prefijo, comando, parametros, trailing).""" | |
| prefix = "" | |
| if line.startswith(":"): | |
| prefix, _, line = line[1:].partition(" ") | |
| command, _, params = line.partition(" ") | |
| trailing = None | |
| if params.startswith(":"): | |
| params, trailing = "", params[1:] | |
| elif " :" in params: | |
| params, _, trailing = params.partition(" :") | |
| return prefix, command, params, trailing | |
| def nick_of(prefix): | |
| return prefix.split("!", 1)[0] | |
| class Cliente: | |
| def __init__(self, nick, canal): | |
| self.nick = nick | |
| self.canal = canal | |
| self.sock = None | |
| self.buf = b"" | |
| self.activo = True | |
| # --- conexion ------------------------------------------------------- | |
| def conectar(self): | |
| raw = socket.create_connection((HOST, PORT), timeout=15) | |
| ctx = ssl.create_default_context() | |
| self.sock = ctx.wrap_socket(raw, server_hostname=HOST) | |
| self.sock.settimeout(None) | |
| self.enviar(f"NICK {self.nick}") | |
| self.enviar(f"USER {self.nick} 0 * :{REALNAME}") | |
| self.enviar(f"JOIN {self.canal}") | |
| def enviar(self, linea): | |
| if self.sock is None: | |
| return | |
| try: | |
| self.sock.sendall(linea.encode("utf-8") + b"\r\n") | |
| except OSError: | |
| self.activo = False | |
| def cerrar(self, motivo="chau"): | |
| if self.sock is None: | |
| return | |
| if self.activo: | |
| self.activo = False | |
| self.enviar_quit(motivo) | |
| try: | |
| self.sock.close() | |
| except OSError: | |
| pass | |
| self.sock = None | |
| def enviar_quit(self, motivo): | |
| try: | |
| self.sock.sendall(f"QUIT :{motivo}\r\n".encode("utf-8")) | |
| except OSError: | |
| pass | |
| # --- lectura -------------------------------------------------------- | |
| def leer(self): | |
| try: | |
| data = self.sock.recv(4096) | |
| except OSError: | |
| data = b"" | |
| if not data: | |
| print("\n[desconectado del servidor]") | |
| self.activo = False | |
| return | |
| self.buf += data | |
| while b"\r\n" in self.buf: | |
| linea, self.buf = self.buf.split(b"\r\n", 1) | |
| self.procesar(linea.decode("utf-8", "replace")) | |
| def procesar(self, linea): | |
| prefix, comando, params, texto = parse(linea) | |
| if comando == "PING": | |
| self.enviar(f"PONG :{texto or params}") | |
| return | |
| if comando == "PRIVMSG": | |
| destino, msg = params, texto or "" | |
| nick = nick_of(prefix) | |
| if msg.startswith("\x01ACTION ") and msg.endswith("\x01"): | |
| self.imprimir(f"* {nick} {msg[8:-1]}") | |
| elif destino == self.nick: | |
| self.imprimir(f"(privado) <{nick}> {msg}") | |
| else: | |
| self.imprimir(f"[{destino}] <{nick}> {msg}") | |
| return | |
| if comando == "NOTICE": | |
| self.imprimir(f"-{nick_of(prefix) or 'servidor'}- {texto or ''}") | |
| return | |
| if comando == "JOIN": | |
| if nick_of(prefix) == self.nick: | |
| self.imprimir(f"* estas en {params}") | |
| else: | |
| self.imprimir(f"--> {nick_of(prefix)} entro a {params}") | |
| return | |
| if comando == "PART": | |
| motivo = f" ({texto})" if texto else "" | |
| if nick_of(prefix) == self.nick: | |
| self.imprimir(f"* saliste de {params}{motivo}") | |
| else: | |
| self.imprimir(f"<-- {nick_of(prefix)} salio de {params}{motivo}") | |
| return | |
| if comando == "QUIT": | |
| self.imprimir(f"<-- {nick_of(prefix)} se fue ({texto or ''})") | |
| return | |
| if comando == "NICK": | |
| nuevo = texto if texto is not None else params | |
| viejo = nick_of(prefix) | |
| if viejo == self.nick: | |
| self.nick = nuevo | |
| self.imprimir(f"* {viejo} ahora es {nuevo}") | |
| return | |
| if comando.isdigit(): | |
| self.numeric(int(comando), params, texto or "") | |
| def numeric(self, codigo, params, texto): | |
| """Muestra los avisos del servidor que vale la pena ver.""" | |
| if codigo == 332: # tema del canal | |
| self.imprimir(f"[tema] {texto}") | |
| elif codigo == 372: # lineas del MOTD | |
| self.imprimir(f"-motd- {texto}") | |
| elif codigo >= 400: | |
| detalle = params.split()[-1] if params else "" | |
| self.imprimir(f"! {texto}" + (f" ({detalle})" if detalle else "")) | |
| def imprimir(self, texto): | |
| # \r limpia el prompt/linea a medio escribir para no mezclar salida. | |
| print(f"\r{texto}") | |
| if sys.stdin.isatty(): | |
| print("> ", end="", flush=True) | |
| # --- entrada -------------------------------------------------------- | |
| def comando(self, linea): | |
| """Ejecuta un /comando. Devuelve False si hay que terminar.""" | |
| cmd, _, arg = linea[1:].partition(" ") | |
| cmd = cmd.lower() | |
| arg = arg.strip() | |
| if cmd in ("quit", "exit", "salir"): | |
| self.cerrar(arg or "chau") | |
| return False | |
| if cmd == "help": | |
| print(AYUDA) | |
| elif cmd == "join": | |
| if not arg: | |
| print("uso: /join #canal") | |
| else: | |
| self.canal = arg if arg[0] in "#&" else "#" + arg | |
| self.enviar(f"JOIN {self.canal}") | |
| elif cmd == "part": | |
| self.enviar(f"PART {arg or self.canal} :chau") | |
| elif cmd == "msg": | |
| destino, _, msg = arg.partition(" ") | |
| if not destino or not msg.strip(): | |
| print("uso: /msg <nick|#canal> <texto>") | |
| else: | |
| self.enviar(f"PRIVMSG {destino} :{msg}") | |
| elif cmd == "me": | |
| if arg: | |
| self.enviar(f"PRIVMSG {self.canal} :\x01ACTION {arg}\x01") | |
| self.imprimir(f"* {self.nick} {arg}") | |
| elif cmd == "nick": | |
| if arg: | |
| self.nick = arg.split()[0] | |
| self.enviar(f"NICK {self.nick}") | |
| else: | |
| print("uso: /nick <nuevo>") | |
| else: | |
| print(f"comando desconocido: /{cmd} (proba /help)") | |
| return True | |
| def mandar_texto(self, linea): | |
| if linea.startswith("/") and len(linea) > 1: | |
| return self.comando(linea) | |
| self.enviar(f"PRIVMSG {self.canal} :{linea}") | |
| self.imprimir(f"[{self.canal}] <{self.nick}> {linea}") | |
| return True | |
| def correr(self): | |
| while self.activo: | |
| # ssl puede tener datos ya leidos aunque select no lo marque. | |
| if self.sock.pending(): | |
| self.leer() | |
| continue | |
| listos, _, _ = select.select([self.sock, sys.stdin], [], []) | |
| if self.sock in listos: | |
| self.leer() | |
| if self.activo and sys.stdin in listos: | |
| linea = sys.stdin.readline() | |
| if not linea: | |
| break | |
| if not self.mandar_texto(linea.rstrip("\r\n")): | |
| break | |
| def main(): | |
| nick = sys.argv[1] if len(sys.argv) > 1 else f"invitado{random.randint(1000, 9999)}" | |
| cliente = Cliente(nick, CANAL) | |
| try: | |
| cliente.conectar() | |
| except (OSError, ssl.SSLError) as error: | |
| sys.exit(f"no pude conectar a {HOST}:{PORT}: {error}") | |
| print(f"conectado a {HOST} como {nick}, entrando a {CANAL}.") | |
| print("escribi y enter para hablar. /help para comandos, /quit para salir.") | |
| if sys.stdin.isatty(): | |
| print("> ", end="", flush=True) | |
| try: | |
| cliente.correr() | |
| except KeyboardInterrupt: | |
| pass | |
| finally: | |
| cliente.cerrar() | |
| print("\nchau") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment