
    5iPM              	          U d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
mZmZ  ej                  dd      Z e ej                  dd            Z ej                  d	d
      Ze de de de de de de ddZeeef   ed<   e de ddZeeef   ed<    ej.                  d      Z ej2                  ej4                  d       	 ddlmZmZmZ ddlm Z  ddl!m"Z" ddl#Z#dZ$dXd ed!ed"eeef   fd#Z&d"eeef   fd$Z'e$r ed%d&d'(      Z(e(jS                  e d)gd*d+gd)g,       e(jU                  d-      d"eeef   fd.       Z+e(jU                  d/      d"eeef   fd0       Z,e(j[                  d1      d2ed"eeef   fd3       Z.e(j[                  d4      d2ed"eeef   fd5       Z/e(j[                  d6      e(jU                  d6      d"eeef   fd7              Z0e(j[                  d8      d2ed"eeef   fd9       Z1e(j[                  d:      d2ed"eeef   fd;       Z2e3d<k(  rHe$s" e4d=        e4d>        ejj                  d?        e4d@        e4dAe dBe         e4dCe         e4dD e	e      jm                                  e4         e4dE        e4dF        e4dG        e4dH        e4dI        e4dJ        e4dK        e4dL        e4         e4dM       ejo                         D ]  \  Z8Z9 e4dNe8 dOe9          e4         e&dP      Z:e:jU                  dQdR      jw                         Z< e4dSe<         e4dTe< dBe d6        e4         e#jz                  dUeeddVW       yy# e%$ r dZ$Y w xY w)Yu  
Genesis n8n Local API Bridge
A FastAPI server that n8n (on Elestio cloud) calls to execute local Genesis actions.

WHY THIS EXISTS:
n8n runs on Elestio cloud. Genesis scripts run on WSL local machine at /mnt/e/genesis-system.
n8n's executeCommand nodes cannot reach WSL directly.
This FastAPI server runs locally and bridges the gap: n8n calls HTTP → this runs the scripts.

USAGE:
    # Start the server (add to tmux or systemd)
    python3 /mnt/e/genesis-system/core/n8n_local_api.py

    # Or with uvicorn for production
    uvicorn core.n8n_local_api:app --host 0.0.0.0 --port 5000 --reload

    n8n then calls: http://<WSL_IP>:5000/trigger-agent
    (WSL IP can be found via: hostname -I | awk '{print $1}')

ENDPOINTS:
    POST /trigger-agent       — Run a Genesis agent task via execution layer
    POST /update-dashboard    — Update a dashboard with new data
    POST /health-check        — Run genesis health check and return status
    POST /spawn-session       — Spawn or resume a tmux session
    POST /run-script          — Run a specific script by name (allowlisted)
    GET  /health              — Simple liveness check
    GET  /status              — Full system status
    N)Path)AnyOptionalGENESIS_ROOTz/mnt/e/genesis-systemN8N_LOCAL_API_PORT5000N8N_LOCAL_API_HOSTz0.0.0.0z!/core/genesis_heartbeat.py statusz /core/genesis_heartbeat.py pulsez/core/circuit_breaker.py statusz$/core/genesis_memory_hub.py --healthz%/scripts/youtube_to_genesis_memory.pyz/core/genesis_memory_hub.pyz%/core/gemini_rate_maximizer.py status)zgenesis-heartbeatzheartbeat-pulsezcircuit-breakerzmemory-hub-healthzyoutube-scoutzmemory-synczrate-limit-statusALLOWED_SCRIPTSz/agent_status.txtz/hive/SWARM_METRICS_REPORT.md)zagent-statuszhive-metricsDASHBOARD_PATHSn8n_local_apiz1%(asctime)s [%(levelname)s] %(name)s: %(message)s)levelformat)FastAPIHTTPExceptionRequest)CORSMiddleware)JSONResponseTFcmdtimeoutreturnc                 p   	 t        j                  | ddd|t              }|j                  dk(  |j                  j                         dd |j                  j                         dd |j                  dS # t         j                  $ r dd	| d
ddcY S t        $ r}dt        |      ddcY d}~S d}~ww xY w)z
    Run a shell command safely and return structured output.

    Args:
        cmd:     Shell command string
        timeout: Max seconds to wait

    Returns:
        Dict with stdout, stderr, returncode, success.
    T)shellcapture_outputtextr   cwdr   Ni  i  )successstdoutstderr
returncodeFzCommand timed out after s)r   errorr   )

subprocessrunr   r   r   stripr   TimeoutExpired	Exceptionstr)r   r   resultes       +/mnt/e/genesis-system/core/n8n_local_api.py_run_commandr,   S   s    E
 ((A-mm))+ET2mm))+DS1 ++	
 	
 $$ d -EgYa+P`bcc E 3q6DDEs$   A2A5 5B5B5B0*B50B5c                  Z   t         j                   j                         j                         t        t              j                         t        j                  j                         d   d} t        d      }|j                  dd      | d<   t        d      }|j                  dd      | d<   | S )	z'Collect basic system health indicators.r   )	timestampgenesis_root_existspython_versionz0tmux list-sessions 2>/dev/null || echo 'no tmux'r   unknowntmux_sessionsz"df -h /mnt/e 2>/dev/null | tail -1disk_e)datetimeutcnow	isoformatr   r   existssysversionsplitr,   get)statustmuxdfs      r+   _get_system_statusr?   s   s     &&--/99;#L188:++++-a0F JKD"hhx;F? 
:	;Bvvh	2F8M    zGenesis n8n Local API BridgezBridges n8n (Elestio cloud) to Genesis scripts running on WSL local machine. n8n calls these endpoints instead of executeCommand nodes.z1.0.0)titledescriptionr9   *GETPOST)allow_originsallow_methodsallow_headersz/healthc                     K   dt         j                   j                         j                         t        t	        t              j                         dS w)z
        Liveness check. n8n calls this every 5 minutes to verify the bridge is alive.

        Returns:
            JSON: {"status": "ok", "timestamp": "...", "genesis_root": "..."}
        ok)r<   r.   genesis_rootgenesis_root_accessible)r4   r5   r6   r   r   r7    r@   r+   healthrN      sD      !**113==?('+L'9'@'@'B	
 	
s   AAz/statusc                     K   t               S w)z
        Full Genesis system status. Returns health of all key components.

        Returns:
            JSON with tmux sessions, disk space, Genesis root accessibility.
        )r?   rM   r@   r+   r<   r<      s      "##s   z/trigger-agentrequestc                 *  K   	 | j                          d{   }|j                  dd      j	                         }|j                  dd      }|j                  d	i       }|st        dd
      t
        j                  d| d|dd         	 t        j                  j                  dt               ddlm}  ||      }d||t        |      dd t        j                  j                         j!                         dS 7 # t        $ r t        dd      w xY w# t"        $ r t%        t              dz  dz  }	 |j'                         r7t)        |d      5 }t        j*                  |      }	ddd       n# 1 sw Y   nxY wg }		j-                  dt/        t1        j0                                |||dt        j                  j                         j!                         dd       |j2                  j5                  dd       t)        |d      5 }t        j6                  |	|d       ddd       n# 1 sw Y   nxY wd|dt        |      t        j                  j                         j!                         dcY S # t        $ r@}
d|d |
 t        j                  j                         j!                         d!cY d}
~
cY S d}
~
ww xY wt        $ rD}
d|t        |
      t        j                  j                         j!                         d!cY d}
~
S d}
~
ww xY ww)"a  
        Trigger a Genesis agent task. Called by n8n to dispatch work to the
        Genesis Execution Layer (Gemini swarm).

        Request body:
            {
                "task": "Summarise latest voice leads and send Telegram report",
                "priority": "high",    // critical|high|normal|low
                "context": {}          // optional extra context
            }

        Returns:
            JSON with execution result or queued task ID.
        N  Invalid JSON bodystatus_codedetailtask prioritynormalcontextz'task' field is requiredz[trigger-agent] priority=z task=P   r   )execute_task_syncTi  )r   rW   rY   r)   r.   loopzrwl_queue.jsonrzn8n-r   pending)idrW   rY   r[   source	queued_atr<   parentsexist_okw   indent)r   rW   queued
queue_pathr.   Fz4Execution layer unavailable and queue write failed: )r   rW   r"   r.   )jsonr'   r   r;   r%   loginfor8   pathinsertr   core.genesis_execution_layerr]   r(   r4   r5   r6   ImportErrorr   r7   openloadappendinttimeparentmkdirdump)rP   bodyrW   rY   r[   r]   r)   rl   fqueuer*   s              r+   trigger_agentr      s     	M 'D xx#))+88J1((9b)C8RSS,XJfT#2YKHI7	HHOOA|,F&t,F$f+et,%..557AAC % ( 	MC8KLL	M0  %	l+f47GGJ"$$&j#. -! $		!- - - E TYY[!1 23  (&-!)!2!2!9!9!;!E!E!G'  !!''t'D*c* 2aIIeQq12 2 2  $ ""%j/!)!2!2!9!9!;!E!E!G   $ STUSVW!)!2!2!9!9!;!E!E!G	   	 Q%..557AAC	 	s   LD  C>D  A1LA/D =L>D   DLL:I8E5,	I85E>	:BI8H/&	I8/H8	4AI85L6L8	K3J<4K5L:L<KL9LLLLLz/update-dashboardc           
      n  K   	 | j                          d{   }|j                  dd      }|j                  di       }|j                  dd	      }|st        dd
      t        j                  |      }|s.t        dd|dt        t        j                                      t        |      }t        j                  j                         j                         }d| dt        j                  |d       d}	 |j                  j                  dd       |dk(  r|j                  |       n&t        |d      5 }	|	j!                  |       ddd       d|t#        |      ||dS 7 P# t        $ r t        dd      w xY w# 1 sw Y   7xY w# t        $ r}
d|t#        |
      dcY d}
~
S d}
~
ww xY ww)a  
        Update a Genesis dashboard or status file with new data from n8n.

        Request body:
            {
                "dashboard": "agent-status",  // key from DASHBOARD_PATHS
                "data": {"field": "value"},    // data to write
                "mode": "append"               // append|replace (default: append)
            }

        Returns:
            JSON confirming write success.
        NrR   rS   rT   	dashboardrX   datamoderv   z'dashboard' field is requiredzUnknown dashboard: z	. Known: z
--- n8n update @ z ---
rh   ri   
Trd   replacea)r   r   rp   r   r.   F)r   r   r"   )rm   r'   r   r;   r   listkeysr   r4   r5   r6   dumpsry   rz   
write_textrt   writer(   )rP   r|   r   r   r   path_strrp   r.   contentr}   r*   s              r+   update_dashboardr     s    	M 'D HH["-	xx#xx)C8WXX"&&y1,YM4H\H\H^C_B`a 
 H~%%,,.88:	'	{&DQR9S8TTVW	OKKdT:y ($_ %GGG$%  &D	& ; ( 	MC8KLL	M4% %  	O$9s1vNN	Osu   F5E* E'E* CF5<A F <FF &F5'E* *FF5F	F 	F2F-'F2(F5-F22F5z/health-checkc                  N  K   t         j                   j                         j                         } dt         d}t	        |d      }	 t        j                  |j                  dd            }dt         d
}t	        |d      }	 t        j                  |j                  dd            }|j                  d       xr |j                  dd      }t        d t        |t              r|j                         ng D               }| |xr |||t        t              j                         dS # t
        j                  $ r( |j                  dd      |j                  dd      d	}Y w xY w# t
        j                  $ r( |j                  dd      |j                  dd      d	}Y w xY ww)z
        Run the Genesis health check and return structured results.
        Called by the Health Monitor n8n workflow instead of executeCommand.

        Returns:
            JSON with heartbeat and circuit breaker status.
        python3 z-/core/genesis_heartbeat.py status 2>/dev/null
   r   r   z{}rX   r   )rawr"   z+/core/circuit_breaker.py status 2>/dev/nullr"   r   Fc              3   D   K   | ]  }|j                  d       dk(    yw)statert   N)r;   ).0vs     r+   	<genexpr>z#run_health_check.<locals>.<genexpr>m  s%      
 EE'Nf$
s    )r.   healthy	heartbeatcircuit_breakersrL   )r4   r5   r6   r   r,   rm   loadsr;   JSONDecodeErrorany
isinstancedictvaluesr   r7   )	r.   heartbeat_cmdr   heartbeat_datacircuit_cmdcircuitcircuit_dataheartbeat_ok
circuit_oks	            r+   run_health_checkr   O  s     %%,,.88:	 #<.0]^ ;		h!ZZ	h(EFN
 !.YZ{B7	b::gkk(D&ABL
 *--g66Z9==TY;Z 
/9,/Ml))+SU
 
 

 ##2
' ,'+L'9'@'@'B
 	
% ## 	h%.]]8R%@9==YaceKfgN	h ## 	b#*;;x#<w{{S[]_G`aL	bsO   AF%%D) ,F%%E' )B F%)8E$!F%#E$$F%'8F"F%!F""F%z/spawn-sessionc                   K   	 | j                          d{   }|j                  dd      }|j                  dd      }t	        d	| d
      }|j                  dd      j                         }|dk(  r1d|dt        j                  j                         j                         dS dt         d| d| d}t	        |d      }|j                  dd      ||j                  d      rdnd|j                  dd      xs |j                  dd      t        j                  j                         j                         dS 7 $# t        $ r t        dd      w xY ww)a  
        Spawn or resume a tmux session. Called by the Continuous Agent Spawner
        n8n workflow instead of executeCommand.

        Request body:
            {
                "session": "genesis",    // tmux session name
                "command": "claude --continue"  // command to run if session doesn't exist
            }

        Returns:
            JSON with session status.
        NrR   rS   rT   sessiongenesiscommandzclaude --continueztmux has-session -t z, 2>/dev/null && echo running || echo stoppedr   rX   runningTalready_running)r   r   actionr.   zcd z && tmux new-session -d -s z ''   r   r   Fspawnedfailedr   r"   )r   r   r   r"   r.   )
rm   r'   r   r;   r,   r%   r4   r5   r6   r   )rP   r|   r   r   checksession_state	spawn_cmdspawns           r+   spawn_sessionr   }  sV    	M 'D ((9i0((9&9: 3G9<hij		(B/557I%"+%..557AAC	  ,'B7)2gYVWX	Y3 yyE2#(99Y#7iXYYx,F		'20F!**113==?
 	
/ ( 	MC8KLL	Ms,   ED> D;D> DE;D> >EEz/run-scriptc           
        K   	 | j                          d{   }|j                  dd      }|j                  dd      }|t        vr.t        dd|d	t        t        j                                      t        |   }|j                  d
      sd| d| j                         n| d| j                         }t        j                  d| d|dd         t        |d      }||j                  dd      |j                  dd      |j                  dd      |j                  dd      t        j                  j                         j                         dS 7 B# t        $ r t        dd      w xY ww)a  
        Run a specific allowlisted Genesis script. Only scripts in ALLOWED_SCRIPTS
        can be executed. No arbitrary command execution.

        Request body:
            {
                "script": "youtube-scout",    // key from ALLOWED_SCRIPTS
                "args": "--dry-run"           // optional extra args
            }

        Returns:
            JSON with stdout/stderr/success.
        NrR   rS   rT   scriptrX   argszScript z not in allowlist. Allowed: python3r    z[run-script] : r\   <   r   r   Fr   r   r   r!   )r   r   r   r   r   r.   )rm   r'   r   r;   r
   r   r   
startswithr%   rn   ro   r,   r4   r5   r6   )rP   r|   script_namer   base_cmdfull_cmdr)   s          r+   
run_scriptr     s{    	M 'D hhx,xx#o-  0##'(<(<(>#?"@B  #;/?G?R?RS\?]XhZq/557#*AdV,224 	 	=R"?@h3 "zz)U3jj2.jj2. **\26!**113==?
 	
+ ( 	MC8KLL	Ms,   E6E EE D=E6E E33E6__main__z(ERROR: FastAPI and uvicorn are required.zBInstall with: pip3 install fastapi uvicorn --break-system-packages   z%
=== Genesis n8n Local API Bridge ===zListening on: http://:zGenesis root: zGenesis root accessible: z
Endpoints:u*     GET  /health          — liveness checku.     GET  /status          — full system statusu/     POST /trigger-agent   — dispatch agent tasku2     POST /update-dashboard — update dashboard fileu.     POST /health-check    — run health scriptsu.     POST /spawn-session   — spawn tmux sessionu2     POST /run-script      — run allowlisted scriptzAllowed scripts:z  r   z*hostname -I 2>/dev/null | awk '{print $1}'r   r1   z(WSL IP (use in n8n HTTP Request nodes): zn8n should call: http://zcore.n8n_local_api:appro   )hostportreload	log_level)   )>__doc__r4   rm   loggingosr#   r8   rx   pathlibr   typingr   r   getenvr   rw   API_PORTAPI_HOSTr
   r   r(   __annotations__r   	getLoggerrn   basicConfigINFOfastapir   r   r   fastapi.middleware.corsr   fastapi.responsesr   uvicorn_FASTAPI_AVAILABLErs   r,   r?   appadd_middlewarer;   rN   r<   postr   r   r   r   r   __name__printexitr7   itemsnamer   	ip_resultr%   wsl_ipr$   rM   r@   r+   <module>r      s  :    	  
    
 ryy)@Ayryy-v67299)95 !-~-NO ,~-MN ,~-LM ,~-QR ,~-RS ,~-HI ,~-RS#c3h  %~%67$~%BC#c3h 
 g(   
,,>776.
Ec EC Ec3h E@DcN & 
,I C efoe	   	WWY
$sCx. 
 
" 	WWY$$sCx. $ $ 	XXUW Uc3h U  Ut 	XX!"4O 4ODcN 4O #4Or 	XXoWW_'
DcN '
  '
X 	XX,
W ,
c3h ,
  ,
b 	XXm+
' +
d38n +
 +
b z89RS 
24	!(1XJ
78	N<.
)*	%d<&8&?&?&A%B
CD	G	,	
67	
:;	
;<	
>?	
:;	
:;	
>?	G	
$**, "	c4&3% !"	G IJI]]8Y/557F	4VH
=>	$VHAhZ}
EF	GGKK C e  s   M> >N	N	