import os,sys,subprocess,time,signal,json,pathlib,tkinter as tk
checkout,side,mode,out,volume=sys.argv[1:]
os.makedirs(out,exist_ok=True)
root=tk.Tk();root.title('Desktop console-write reproduction');root.geometry('960x135+0+940');root.configure(bg='#18202c')
label=tk.Label(root,text='',font=('DejaVu Sans',16),bg='#18202c',fg='white',justify='left');label.pack(padx=12,pady=12)
def status(s):
 label.config(text=f'{side.upper()} | {mode}\n{s}');root.update()
def wait(n):
 end=time.monotonic()+n
 while time.monotonic()<end: root.update();time.sleep(.1)
logdir=pathlib.Path(volume);logdir.mkdir(exist_ok=True)
for name in ['stdout.log','stderr.log','fill']:
 p=logdir/name
 if p.exists(): p.unlink()
env=os.environ.copy();env.pop('ELECTRON_RUN_AS_NODE',None);env.update(T3CODE_HOME=out+'/home',T3CODE_DEV_SEED='0',T3CODE_DISABLE_AUTO_UPDATE='1',XDG_CONFIG_HOME=out+'/config')
app=subprocess.Popen([checkout+'/apps/desktop/node_modules/electron/dist/electron',checkout+'/apps/desktop/dist-electron/main.cjs','--no-sandbox','--disable-gpu'],cwd=checkout+'/apps/desktop',env=env,stdout=open(logdir/'stdout.log','ab'),stderr=open(logdir/'stderr.log','ab'))
status('Launching real Electron app; waiting 30 seconds')
wait(30)
subprocess.run(['import','-window','root',out+'/startup.png'])
# Record the same timed quit interaction for every run.
rec=subprocess.Popen(['ffmpeg','-y','-loglevel','error','-f','x11grab','-video_size','1920x1080','-framerate','5','-i',os.environ['DISPLAY'],'-c:v','libx264','-preset','ultrafast','-pix_fmt','yuv420p',out+'/raw.mp4'])
status('App running; about to exhaust log volume' if mode!='control' else 'Writable logs; about to send SIGTERM');wait(2)
errors=[]
if mode!='control':
 try:
  with open(logdir/'fill','wb',buffering=0) as f:
   while True:f.write(b'0'*4096)
 except OSError as e:errors.append({'operation':'fill','code':e.errno,'message':e.strerror})
 for name in ['stdout.log','stderr.log']:
  try:
   with open(logdir/name,'ab',buffering=0) as f:
    while True:f.write(b'0'*512)
  except OSError as e:errors.append({'operation':'append '+name,'code':e.errno,'message':e.strerror})
probe=None
if mode!='control':
 probeenv=env.copy();probeenv['ELECTRON_RUN_AS_NODE']='1'
 probejs="const fs=require('fs');try{fs.writeSync(fs.openSync(process.argv[1],'a'),Buffer.alloc(4096));console.log('write succeeded')}catch(e){console.log(JSON.stringify({code:e.code,errno:e.errno,message:e.message.split(',')[0]}))}"
 probe=subprocess.run([checkout+'/apps/desktop/node_modules/electron/dist/electron','-e',probejs,str(logdir/'stdout.log')],env=probeenv,capture_output=True,text=True).stdout.strip()
status('Both log appends failed; sending SIGTERM'  if errors else 'Sending SIGTERM with writable logs');wait(2)
app.send_signal(signal.SIGTERM)
status('SIGTERM sent; observing app for 20 seconds');wait(20)
code=app.poll();status('RESULT: exited with status '+str(code) if code is not None else 'RESULT: still running 20 seconds after SIGTERM');wait(3)
subprocess.run(['import','-window','root',out+'/result.png']);wait(.5);subprocess.run(['import','-window','root',out+'/result-2.png'])
rec.send_signal(signal.SIGINT);rec.wait()
windows=subprocess.run(['xdotool','search','--onlyvisible','--name','Error'],capture_output=True,text=True).stdout
if code is None:
 app.kill();app.wait()
summary={'side':side,'mode':mode,'exitAfterSigterm':code,'errorWindows':bool(windows.strip()),'writeFailures':errors,'electronWriteProbe':probe}
open(out+'/summary.json','w').write(json.dumps(summary,indent=2));print(json.dumps(summary),flush=True)
# Save logs before the next run; private paths are removed from public transcripts later.
for name in ['stdout.log','stderr.log']:
 data=(logdir/name).read_bytes().rstrip(b'0');open(out+'/'+name,'wb').write(data)
root.destroy()
