#!/usr/bin/env python3 """Subprocess-safe remote program-state sync. Reads jupyter binding JSON, fetches program-state.jsonl via jupyter Contents API (HTTP GET), writes to local path. Designed to be called via asyncio.create_subprocess_exec with a hard timeout — if the pod is unreachable, the parent kills this process cleanly. Usage: python3 sync_remote_state.py """ import json import sys import urllib.request import urllib.error import ssl def main(): if len(sys.argv) != 3: sys.exit(1) binding_path = sys.argv[1] local_path = sys.argv[2] try: with open(binding_path, encoding='utf-8') as f: data = json.load(f) except (OSError, json.JSONDecodeError): sys.exit(1) binding = data.get('binding', {}) base_url = binding.get('base_url', '').rstrip('/') api_path = binding.get('workspace_api_path', '') if not base_url or not api_path: sys.exit(1) cookies_list = data.get('cookies', []) cookie_str = '; '.join(f"{c['name']}={c['value']}" for c in cookies_list) xsrf = data.get('xsrf_token', '') file_api_path = f"{api_path}/output/program-state.jsonl" url = f"{base_url}/api/contents/{file_api_path}?content=1&type=file" ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_peer = False req = urllib.request.Request(url) req.add_header('Cookie', cookie_str) if xsrf: req.add_header('X-XSRFToken', xsrf) try: resp = urllib.request.urlopen(req, timeout=8, context=ctx) body = json.loads(resp.read()) except (urllib.error.URLError, OSError, json.JSONDecodeError, TimeoutError): sys.exit(1) content = body.get('content', '') if not content or not content.strip(): sys.exit(0) # Preserve local-only _synthetic entries local_synthetics = [] try: with open(local_path, encoding='utf-8') as f: for line in f: if '"_synthetic"' in line: try: obj = json.loads(line) if obj.get('_synthetic'): local_synthetics.append(line.rstrip('\n')) except (json.JSONDecodeError, ValueError): pass except OSError: pass merged = content.rstrip('\n') if local_synthetics: merged += '\n' + '\n'.join(local_synthetics) merged += '\n' # Skip rewrite if unchanged try: with open(local_path, encoding='utf-8') as f: if f.read() == merged: sys.exit(0) except OSError: pass import os os.makedirs(os.path.dirname(local_path), exist_ok=True) with open(local_path, 'w', encoding='utf-8') as f: f.write(merged) if __name__ == '__main__': main()