ؚPjCLdZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl m Z m Z ddlmZddlZddlmZddlmZeeej,j,dz dZd Zd Zed Zed Zej9d dZdZdZdZ ejBddZ"ejBddZ#ejBddZ$ejBddZ%dZ&dZ'dejPfdZ)de*fdZ+de*de*fdZ,de-e.fd Z/e fd!e0de-e.fd"Z1de-e.fd#Z2d$e*ddfd%Z3de*ddfd&Z4ejjd'z Z6ed(Z7d)d*d+e6d,d-d.gZ8dHd/Z9de:fd0Z;de:fd1Zde.fd4Z?de.fd5Z@de:fd6ZAd7e.d8e-e.ddfd9ZBd:ZCd;ZDefde:de:fd?ZGdHd@ZHde:fdAZIde:fdBZJeKdCk(rdDejvre9ydEejvr#eIZMejeMrdydFydGejvr#eJZMejeMrdydFyeHyy)JuLoop Adrian↔Elon — protocollo msg/ack su vault.db con handshake Vision. Protocollo: msg-a2e-{ts} : Adrian → Elon (pending se no ack-a2e) ack-a2e-{ts} : Elon → conferma lettura msg-e2a-{ts} : Elon → Adrian (risposta/aggiornamento) ack-e2a-{ts} : Adrian → conferma lettura State machine pre-pull (Vision-driven): CHROME_DOWN → avvia Chrome WRONG_PAGE → naviga al Project GENERATING → aspetta max 2 min READY_WARM → sessione attiva, kernel in memoria → testo diretto READY_COLD → sessione fredda, kernel da caricare → /pull AUTH_ERROR → Telegram Mauro, stop CAPTCHA → Telegram Mauro, stop ERROR → Telegram Mauro, stop Uso: python3 elon_pull.py # interattivo, aspetta risposta python3 elon_pull.py --fire-and-forget # non-blocking (manutenzione notturna) python3 elon_pull.py --retry-if-pending # cron: ritenta solo se msg-a2e senza ack >2h python3 elon_pull.py --restart-chrome # riavvia solo Chrome N)datetimetimezone)Path) load_dotenv)sync_playwrightz.envz>https://claude.ai/project/019c85a9-a4ba-737c-a803-b10f4a7769b4z$019c85a9-a4ba-737c-a803-b10f4a7769b4zhttp://localhost:9222z(/mnt/ssd/data/vault-secondbrain/vault.dbz/tmp/elon_pull_debugT)exist_ok,xADRIAN_BOT_TOKENTELEGRAM_CHAT_IDOPENROUTER_BASE_URLzhttps://openrouter.ai/api/v1OPENROUTER_API_KEYzanthropic/claude-sonnet-4-5ireturncbtjt}tj|_|S)N)sqlite3connectDB_PATHRow row_factory)conns ./mnt/ssd/adrian/vault-secondbrain/elon_pull.py_dbrDs! ??7 #D{{D Kcftjtjj dS)Nz%Y%m%dT%H%M%S%fZ)rnowrutcstrftimerr_tsr"Js! << % . ./A BBrtextct}d|}tjddd|d}t}|j d|d||f|j |j |S)z:Scrive un msg-a2e per Elon in vault.db. Ritorna il msg_id.zmsg-a2e- agent_memoryadrianelon)tipofromtotszNINSERT OR REPLACE INTO items(id, type, body, file, meta) VALUES (?,?,?,NULL,?)osr"jsondumpsrexecutecommitclose)r#r+msg_idmetars r send_messager5Nsf Bt_F ::~xvUWX YD 5DLLX tT" KKM4::< Mrct}|jdj}|j|Dcgc] }t |c}Scc}w)u6msg-a2e senza ack-a2e — non ancora ricevuti da Elon.a SELECT i.id, i.body, json_extract(i.meta,'$.ts') as ts FROM items i WHERE i.id LIKE 'msg-a2e-%' AND NOT EXISTS ( SELECT 1 FROM items a WHERE a.id = 'ack-' || substr(i.id, 5) ) ORDER BY ts ASC rr0fetchallr2dictrrowsrs rpending_msgs_a2er=\K 5D <<    JJL! "DG "" "Ahoursctjtjj |dzz }t }g}|D]a} |j dxsdjdd}tj|j }||kr|j|c|S#t$r|j|YwxYw)u?msg-a2e pendenti da più di `hours` ore — candidati al retry.ir+rZz+00:00) rrrr timestampr=getreplace fromisoformatappend Exception)r@cutoffpendingstalemts_strts rstale_msgs_a2erOls \\(,, ' 1 1 3edl BF G E  eeDk'R00h?F&&v.88:A6z Q  L  LLO s AB,,C C ct}|jdj}|j|Dcgc] }t |c}Scc}w)u<msg-e2a senza ack-e2a — risposte di Elon non ancora lette.a SELECT i.id, i.body, json_extract(i.meta,'$.ts') as ts FROM items i WHERE i.id LIKE 'msg-e2a-%' AND NOT EXISTS ( SELECT 1 FROM items a WHERE a.id = 'ack-' || substr(i.id, 5) ) ORDER BY ts ASC r7r:s rpending_responsesrQ|r>r?r3cd|ddz}t}tjd|d|d}t}|j d|dd |f|j |j y) u7Adrian acka una risposta di Elon (msg-e2a → ack-e2a).zack-Nr%r&)r(acksbyr+zMINSERT OR IGNORE INTO items(id, type, body, file, meta) VALUES (?,?,?,NULL,?)r,rr-)r3ack_idr+r4rs r ack_responserWsf fQRj F B ::~vXUWX YD 5DLLW r4  KKM4::*:, G*D9    s'7 AAz.config/chrome-debug-elonz/tmp/elon_pull_chrome.sentinelzgoogle-chrome-stablez--remote-debugging-port=9222z--user-data-dir=z--no-first-runz--profile-directory=Defaultz--start-maximizedctjgddd}|jjDcgc]}|j st | }}|D]'} t j|tj)|r0tdt|d|dtjdtj!dit j"d d i}tj$t&|tj(tj( td t+d D]Z}tjd t,j.j1ddtj3dtdytdycc}w#t$rYQwxYw#t4$rYwxYw)N)pgrepz-fzchrome-debug-elonT)capture_outputr#z[chrome] Terminati z processi (pids: )) missing_okDISPLAYz:0)envstdoutstderru,[chrome] Chrome riavviato — attendo CDP...zhttp://localhost:9222/jsonr r[r&z[chrome] CDP pronto.z+[chrome] WARNING: CDP non risponde dopo 20s) subprocessrunrisplitstripintr,killsignalSIGTERMProcessLookupErrorprintlentimesleepCHROME_SENTINELunlinkenvironPopen CHROME_CMDDEVNULLrangeurllibrequesturlopen write_textrH)resultppidspidrh_s rrestart_chromersr ^^@QU\` aF"MM//1 ?qQWWYCF ?D ?  GGC (   #CI;.?vQGH 1 d+ )RZZ )D )CZS1C1CJL^L^_ 89 2Y 1   NN " "#? " K  & &x 0 ( )   78- @"       s0F F"$F#AF3# F0/F03 F?>F?ct tjjtdzdy#t$rYywxYw)Nz/jsonr rmTF)rrrCDP_URLrHr!rr _chrome_uprs8w0!< s (+ 77cBtjxr tS)uOTrue se il Chrome su porta 9222 è stato avviato da Adrian (sentinel presente).)r{existsrr!rr_chrome_is_oursrs  ! ! # 4 4raLAnalizza questo screenshot di Claude.ai e rispondi SOLO con un JSON: { "state": "ready_warm" | "ready_cold" | "generating" | "auth_error" | "captcha" | "error", "kernel_loaded": true | false, "details": "" } Definizioni: - ready_warm: input box visibile e libero, conversazione con messaggi visibili (sessione attiva) - ready_cold: input box visibile e libero, nessun messaggio nel thread (sessione nuova/vuota) - generating: spinner di caricamento, pulsante "Stop", o testo che si sta generando - auth_error: pagina di login, "Session expired", errore di autenticazione - captcha: captcha Cloudflare o simile - error: pagina rotta, 404, errore generico non classificabile kernel_loaded: true se vedi messaggi precedenti di una sessione strutturata (non solo UI vuota). Rispondi SOLO con il JSON, nessun testo aggiuntivo. img_bytesc PtsddddS tj|j}t j t ddtddtd d d d |id dtdgdgdddd}|j|jddddj}tjd|tj}|r#tj|j!S ddddS#t"$r}t%d|Yd}~"d}~wwxYw)z=Manda screenshot a Claude Vision e ritorna lo stato rilevato. ready_coldFzvision non configuratastate kernel_loadeddetailsz/chat/completionszBearer zapplication/json) Authorizationz Content-Typeuser image_urlurlzdata:image/png;base64,)typerr#)rr#)rolecontentr)modelmessages temperature max_tokens)headersr.r[choicesmessagerz\{.*\}z[vision] Errore: Nzvision fallita, assumo cold)OPENROUTER_KEYbase64 b64encodedecoder^r_OPENROUTER_URL VISION_MODEL VISION_PROMPTraise_for_statusr.rqresearchDOTALLloadsgrouprHrw)rb64resprawrLes r _vision_staters@ %Jbcc'y)002zz/ 0(//?&@Rde%"!,EE[\_[`Ca;bc!'?  !!  " iik)$Q' 29=CCE IIibii 0 ::aggi( ( "EFc dd ' !!%&&'sC.D D% D  D%c  |j}tdz }|j|t|}t d|dd|dd|d|S#t $r'}t d|d d t |d cYd }~Sd }~wwxYw) u%Screenshot + Vision → stato pagina.z pre_pull.pngz[state] rz | kernel=rz | rz[state] Errore detection: errorFrN) screenshot DEBUG_DIR write_bytesrrwrHstr)pageimgfnamerrs r _detect_staters MooN* #c" w( 53I2J#eT]N^M_`a M *1#./ 5SVLLMsAA BB;BBc |j}d|vsd|jvr tdyy#t$r}td|Yd}~yd}~wwxYw)uCheck passivo — nessun click, nessun menu aperto. Legge il testo della pagina: se Claude.ai segnala 'non disponibile' per il vault lo connettore è offline. Zero interazioni UI, zero overlay.z"Vault Second Brain non disponibilez"vault second brain non disponibileuM[connector] ⚠️ Vault Second Brain non disponibile (rilevato passivamente)FTz"[connector] Errore check passivo: N)rlowerrwrH)rrrs r_check_connectorr%s^,,. /7 :>bfmfsfsfu>u a b  21#67s15 AAArrJc*|jdj}|j|jd|j ddk(xr|j dd}|rdj d|Dnd }|rA|r?t |tkr-d |zd z}td t |d t |dn$|sdndt |d}td|dd}|j||jjdy)uManda il trigger a Elon: testo diretto (warm) o #boot (cold). Il prefisso # segnala comunicazione unattended Adrian↔Elon.z[contenteditable="true"]r r ready_warmrFz --- c3&K|] }|d yw)bodyNr!).0rLs r z _send_trigger..>s  NN4MM rcl|jdjD]}t|jvs|cSy)z(Trova la pagina del Project Elon o None.rN)contextspages PROJECT_UUIDr)browserpgs r_get_elon_pagerPs8q!'' 266 !I rcPtstdtn+tstdtn td|jj t }|jdjr|jdjdnd}|r|jdt|}|sbtd|jdj}|jd|jtdd |jd ||fS) zAConnette CDP, trova/crea la pagina Elon. Ritorna (browser, page).u,[loop] Chrome non in esecuzione — avvio...uO[loop] Chrome attivo ma non istanziato da Adrian — chiudo e riavvio pulito...u6[loop] Chrome già nostro — riuso sessione esistenterNzK() => { window.moveTo(0,0); window.resizeTo(screen.width, screen.height); }u([loop] Project non trovato — navigo...domcontentloaded` wait_untilr[ )rrwrrchromiumconnect_over_cdprrrevaluaternew_pagegoto PROJECT_URLr)rrrs r_setup_browserrXs < <=   _` FGjj))'2G,3+;+;A+>+D+D7  A  $ $Q '$D  cd ' "D  89"++- cd +*\ ) 3C E8I4J3K2NO 1 ))+  ( r wait_responsec t}|jdj}|j|r||dxsdj ret |dj }t}|jd|j |jtd|t}|s tdytdt|d  t5}t|\}}t|}|d d k(rHt|} | s0td td |j dddyt|}|d dvrAd|d d|d} td| t| |j dddy|d dk(rFtd|dd|jt dd|j#dt|}t%|stdtdt'|||td|rtdd} g} | t(krt+j,t.| t.z } t1} | rtd| d nG| d!zdk(r&|j3t5t6d"| d#z $td%| d&| t(kr|j| r-| D]'} td'| d(d)| dt9| d()n'td*ntd+|j dddy,#1swYyxYw#t:$r&}td-|td.|Yd}~yd}~wwxYw)/zELogica comune: state machine + trigger. Ritorna True se pull inviato.z2SELECT body FROM items WHERE id='da-adrian-a-elon'rrz4UPDATE items SET body='' WHERE id='da-adrian-a-elon'u[loop] Messaggio legacy → u2[loop] Nessun msg-a2e pendente — niente da fare.Fz[loop] z msg-a2e pendentirru'[loop] Timeout generazione — rinunciouI⚠️ elon_pull: Elon stava generando da troppo tempo, /pull posticipatoN) auth_errorcaptchau⚠️ elon_pull: u) rilevato — intervento Mauro richiesto rrz[loop] Errore pagina: u — ricarico ProjectrrrruJ[loop] ⚠️ Connettore Vault potenzialmente offline — procedo comunqueuN⚠️ elon_pull: connettore Vault potrebbe essere offline (Elon verificherà)z[loop] Trigger inviato.z"[loop] Attendo risposta di Elon...rz[loop] Elon ha risposto (zs).rpoll_zs.png)pathz[loop] Attendo... (rz --- Risposta Elon [idz] --- u$[loop] Timeout — nessuna risposta.uP[loop] /pull inviato (fire-and-forget). Elon risponderà alla prossima sessione.Tz[loop] Errore: u⚠️ elon_pull fallito: )rr0fetchoner2rqr5r1rwr=rxrrrrr`rrrrrRESPONSE_TIMEOUTryrz POLL_INTERVALrQrrrrWrH)rrlegacyr3rJrrrrreadymsgelapsed responsesr<rs r _pull_corers^ 5D \\N O X X ZFJJL 6&>'R..0fVn2245u KL tzz| ,VH56 G  BC GCL>!2 34E  ? !*1-MGT"$'EW~-+D1CDijMMO ? ? &d+W~!::*5>*::dejkteudvwuo&# )? ? ,W~(.uY/?.@@UVW +2De T%%d+%d+$D)bcjk $w / + ,:;  00JJ}-},G 1 3I  9'#FG|q(SuWIU=S1S-TU/y;< 00 &. 5agYgai[QR$QtW-.@Ahi ? ? ? B  s#$.qc23sX) M3AL; MA L;M%D%L; A'L;2M;MMM M6M11M6ctdy)NTrrr!rrroros T"rctdS)NFrr r!rrfire_and_forgetr s E **rct}|stdtdytdt|dtdt S)uLRitenta pull solo se ci sono msg-a2e senza ack da più di PENDING_AGE_H ore.z[retry] Nessun msg-a2e stale (>uh) — niente da fare.Fz[retry] z msg-a2e senza ack da >uh — ritento pull.)rOrw PENDING_AGE_Hrxr )rKs rretry_if_pendingrsI  E  / >TUV HSZL 7 FY Z[  r__main__z--restart-chromez--fire-and-forgetrlz--retry-if-pending)rN)F)O__doc__rr.r,rrtrrnsysryurllib.requestrrrpathlibrr^dotenvrplaywright.sync_apir__file__parentrrrrrmkdirrr GENERATE_WAITr getenvr\r]rrrr Connectionrrr"r5listr9r=floatrOrQrWr`homeCHROME_PROFILEr{rrboolrrrbytesrrrrrrrrrrror r__name__argvokexitr!rrr&s 2  ' / DN ! ! ( (6 12Q 7 (@A,-    ")).3")).3 "))13QR"))0"5/  W   CSC s s  #$t* # #0 % DJ  #4: #        C  D  $))+ ;;78"~&'!  96D557 (eUeteB M4 M d "!t!d4j!T!4</<   YdYtYx#++$ zSXX%  (  b a  )  b a  r