#!/usr/bin/env python3
"""Run from either checkout. Real server CLI + read-only event capture; no tests/mocks."""
import subprocess,sqlite3,json,time,pathlib,sys,datetime
out=pathlib.Path(sys.argv[1]);out.mkdir(parents=True,exist_ok=True)
project=sys.argv[2]
prompt="For this ACP provider reproduction, use Grok's native spawn_subagent tool (general-purpose, BACKGROUND mode), rather than T3's delegate_task. This instruction overrides any general delegation preference. Launch one background subagent that writes about 600 words on the history of lighthouses as its reply. Do not use web search or write files. Wait for its completion with the native subagent tools, then answer exactly 'done'."
cli=['node','apps/server/src/bin.ts']
db=sqlite3.connect('file:'+str(pathlib.Path('.t3/userdata/statev2.sqlite').resolve())+'?mode=ro',uri=True)
start_seq=db.execute('select coalesce(max(sequence),0) from orchestration_events').fetchone()[0]
t0=time.time();cast=open(out/'session.cast','w');cast.write(json.dumps({'version':2,'width':112,'height':32,'timestamp':int(t0),'title':'Real ACP subagent persistence capture'})+'\n')
transcript=open(out/'transcript.txt','w')
def say(s):
 print(s,flush=True);transcript.write(s+'\n');transcript.flush();cast.write(json.dumps([round(time.time()-t0,3),'o',s+'\r\n'])+'\n');cast.flush()
sha=subprocess.check_output(['git','rev-parse','HEAD'],text=True).strip()
say('T3 Code real server | Grok 1.0.77 | grok-4.7-build-fast')
say('Commit: '+sha);say('Fresh synthetic thread; native BACKGROUND general-purpose subagent')
say('Task: ~600 words on lighthouse history; wait; parent replies done')
say('Monitoring persisted events through a read-only SQLite connection.')
reply=open(out/'turn.json','w')
p=subprocess.Popen([*cli,'thread','start',project,prompt,'--provider','grok','--model','grok-4.7-build-fast','--title','ACP persistence capture','--wait','--json','--base-dir','.t3'],stdout=reply,stderr=subprocess.PIPE,text=True)
last=None;child=None;thread=None
samples=open(out/'samples.jsonl','w')
while True:
 events=db.execute('select sequence,event_type,occurred_at,payload_json from orchestration_events where sequence>? order by sequence',(start_seq,)).fetchall()
 for seq,typ,at,s in events:
  d=json.loads(s)
  if typ=='subagent.updated' and d.get('origin')=='provider_native': child=d['childThreadId'];thread=d['threadId']
 rows=[(seq,typ,at,json.loads(s)) for seq,typ,at,s in events if child and json.loads(s).get('threadId')==child]
 msgs=[r for r in rows if r[1]=='message.updated' and r[3].get('role')=='assistant']
 items=[r for r in rows if r[1]=='turn-item.updated']
 snap={'elapsed':round(time.time()-t0,3),'child':child,'messageSnapshots':len(msgs),'turnItemSnapshots':len(items),'latestChars':len(msgs[-1][3]['text']) if msgs else 0,'messagePayloadBytes':sum(len(json.dumps(r[3],separators=(',',':'),ensure_ascii=False).encode()) for r in msgs)}
 samples.write(json.dumps(snap)+'\n');samples.flush()
 state=(len(msgs),len(items),snap['latestChars'])
 if state!=last:
  say(f"{snap['elapsed']:6.2f}s  message.updated={len(msgs):4}  turn-item.updated={len(items):4}  reply chars={snap['latestChars']:5}")
  last=state
 if p.poll() is not None: break
 if time.time()-t0>300:
  p.terminate();say('Capture timed out after 300 seconds');break
 time.sleep(.25)
reply.close()
final_events=[{'sequence':seq,'event_type':typ,'occurred_at':at,'payload':json.loads(s)} for seq,typ,at,s in events if json.loads(s).get('threadId') in [child,thread]]
(out/'events.json').write_text(json.dumps(final_events,indent=2))
say('Child: '+str(child));say('Parent: '+str(thread));say('CLI exit: '+str(p.poll()))
if p.returncode==0:
 result=json.loads((out/'turn.json').read_text());say('Parent completion: '+result.get('status','')+'; reply: '+result.get('reply',''))
if msgs:
 (out/'final-reply.txt').write_text(msgs[-1][3]['text'])
 say('Saved complete child reply: '+str(len(msgs[-1][3]['text']))+' chars')
(out/'capture.json').write_text(json.dumps({'sha':sha,'childThreadId':child,'parentThreadId':thread,'startedAt':datetime.datetime.fromtimestamp(t0,datetime.timezone.utc).isoformat(),'startSequence':start_seq,'final':snap},indent=2))
err=p.stderr.read()
if err: say(err[:1000])
