#!/usr/bin/python3
import os,sys,subprocess,selectors,socket,json,datetime,signal,hashlib
base='/tmp/ev-23840'
real='/usr/local/nvm/versions/node/v24.21.0/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex'
if 'app-server' not in sys.argv[1:]:os.execv(real,[real,*sys.argv[1:]])
p=subprocess.Popen([real,*sys.argv[1:]],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=sys.stderr.buffer)
open(base+'/gate-cli.pid','w').write(str(p.pid)+'\n')
log=open(base+'/gate-events.jsonl','a',buffering=1)
def emit(kind,**kw):log.write(json.dumps({'at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'kind':kind,**kw})+'\n')
def end(sig,frame):
 emit('stop',pid=p.pid,signal=sig)
 if p.poll() is None:p.send_signal(sig)
 sys.exit(0)
signal.signal(signal.SIGTERM,end);signal.signal(signal.SIGINT,end)
sockpath=base+'/gate-control-'+str(os.getpid())+'.sock';open(base+'/gate-socket-path.txt','w').write(sockpath);ctl=socket.socket(socket.AF_UNIX);ctl.bind(sockpath);ctl.listen();sel=selectors.DefaultSelector();sel.register(ctl,selectors.EVENT_READ,'control');sel.register(sys.stdin.buffer,selectors.EVENT_READ,'stdin');sel.register(p.stdout,selectors.EVENT_READ,'stdout')
child=None;root=None;held=[];released=False;buf=b''
emit('spawn',pid=p.pid,realBinary=real)
while True:
 for key,_ in sel.select():
  if key.data=='control':
   c,_=ctl.accept();command=c.recv(100)
   if command.strip()==b'release':
    released=True
    for line,f in held:sys.stdout.buffer.write(line);sys.stdout.buffer.flush();emit('released-real-frame',sha256=hashlib.sha256(line).hexdigest(),frame=f)
    c.sendall(json.dumps({'released':len(held)}).encode());held.clear()
   c.close();continue
  if key.data=='stdin':
   data=os.read(sys.stdin.fileno(),65536)
   if not data:
    if p.poll() is None:p.terminate()
    sys.exit(0)
   p.stdin.write(data);p.stdin.flush();continue
  data=os.read(p.stdout.fileno(),65536)
  if not data:sys.exit(p.wait())
  buf+=data
  while b'\n' in buf:
   line,buf=buf.split(b'\n',1);line+=b'\n'
   try:f=json.loads(line);q=f.get('params',{});i=q.get('item',{});method=f.get('method')
   except ValueError:sys.stdout.buffer.write(line);sys.stdout.buffer.flush();continue
   if child is None and i.get('type')=='subAgentActivity' and i.get('kind')=='started':
    child=i['agentThreadId'];root=q['threadId'];emit('native-child-discovered',rootNativeId=root,childNativeId=child)
   hold=not released and child is not None and ((method=='turn/completed' and q.get('threadId')==child) or (i.get('type')=='subAgentActivity' and i.get('kind')!='started' and i.get('agentThreadId')==child))
   if hold:held.append((line,f));emit('held-real-frame',sha256=hashlib.sha256(line).hexdigest(),frame=f);continue
   sys.stdout.buffer.write(line);sys.stdout.buffer.flush()
