
    g5jJA                        d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	 dZ
dZdZd!dZd"dZd#dZd$dZd%dZd&dZd'dZdd gZdS )(u  CLI subcommand: ``hermes send`` — pipe text from shell scripts to any
configured messaging platform (Telegram, Discord, Slack, Signal, SMS, etc.).

This is a thin wrapper around ``tools.send_message_tool.send_message_tool``
that exposes its functionality as a standalone CLI entry point so ops
scripts, cron jobs, CI hooks, and monitoring daemons can reuse the gateway's
already-configured credentials without having to reimplement each platform's
REST API client.

Design notes:

* No LLM, no agent loop — the subcommand just resolves arguments, reads the
  message body, calls the shared tool function, and prints/returns the
  result. It is intentionally fast, cheap, and side-effect-only.
* For platforms that send via bot token (Telegram, Discord, Slack, Signal,
  SMS, WhatsApp-CloudAPI, …) no running gateway is required. The tool
  talks directly to each platform's REST endpoint. For platforms that rely
  on a persistent adapter connection (plugin platforms, Matrix in some
  modes, …) a live gateway is needed; the underlying tool surfaces that
  error to the caller.
* Exit codes follow the classic Unix convention:
    0 — delivery (or list) succeeded
    1 — delivery failed at the platform level
    2 — usage / argument / config error (argparse already uses 2)
    )annotationsN)Path)Optional      
positionalOptional[str]	file_pathreturnc                \   | r| S |r|dk    rt           j                                        S 	 t          |                              d          S # t
          $ rD t          d| d| d| d| d	t           j        	           t          j        t                     Y nPt          $ rD}t          d
| d| t           j        	           t          j        t                     Y d}~nd}~ww xY wt           j                                        s"t           j                                        }|r|S dS )u8  Resolve the message body from (in order):

    1. An explicit positional message argument.
    2. ``--file PATH`` or ``--file -`` (where ``-`` means stdin).
    3. Piped stdin when it is not attached to a TTY.

    Returns ``None`` when nothing is available — callers must treat that as
    a usage error.
    -utf-8encodinghermes send: z is not a text file. --file reads the message *body* (logs, reports, markdown).
To send an image/document/audio file as a native attachment, reference it with MEDIA: in the message text instead:
  hermes send --to telegram "MEDIA:z6"
  hermes send --to telegram "optional caption MEDIA:zv"
Add [[as_document]] to deliver an image as an uncompressed file:
  hermes send --to telegram "[[as_document]] MEDIA:"filezhermes send: cannot read z: N)sysstdinreadr   	read_textUnicodeDecodeErrorprintstderrexit_USAGE_EXITOSErrorisatty)r   r
   excdatas       9/home/rurouni/.hermes/hermes-agent/hermes_cli/send_cmd.py_read_message_bodyr#   )   s      "9>>###	"	??,,g,>>>! 	" 	" 	"S	 S S 7@	S S
 HQS S GPS S S Z
 
 
 
 H[!!!!! 	" 	" 	"@i@@3@@szRRRRH[!!!!!!!!	" 9 y~~ 	K4s   "A AC)	C)%:C$$C)arg_toc                Z    | r(|                                  r|                                  S dS )zAReturn a cleaned ``--to`` value, or ``None`` when nothing is set.N)strip)r$   s    r"   _resolve_targetr'   Z   s,     &,,.. ||~~4    result_jsonstr	json_modeboolquietintc                  	 | rt          j        |           ni }n# t           j        $ r d| d}Y nw xY w|r$t          t          j        |d                     n|rn|                    d          r%t          d|d          t          j                   no|                    d          r7|                    d	          }|rt          |           n3t          d
           n#t          t          j        |d                     |                    d          rt          S |                    d          rt          S |                    d          rt          S t          S )zPrint the tool result in the requested format and return the exit code.

    The underlying ``send_message_tool`` always returns a JSON string. We
    parse it, decide success/failure, and format accordingly.
    z#invalid JSON from send_message_tool)errorrawr   )indentr0   r   r   successnotesentskipped)
jsonloadsJSONDecodeErrorr   dumpsgetr   r   _FAILURE_EXIT_SUCCESS_EXIT)r)   r+   r-   payloadr4   s        r"   _emit_resultr?   a   s   W-8@$*[)))b W W W B+VVW
  1dj+++,,,,	 1;;w 
	14''"2443:FFFFF[[## 	1;;v&&D df $*WQ///000{{7 {{9 {{9 s    22platform_filterc          
     h   	 ddl m}m} n<# t          $ r/}t	          d| t
          j                   t          cY d}~S d}~ww xY w	  |            }n<# t          $ r/}t	          d| t
          j                   t          cY d}~S d}~ww xY wt          |	                    d          pi           }| r| 
                                                                fd|                                D             }|sJt	          d	|  d
d                    t          |                    pd t
          j                   t          S |}|r2t	          t          j        d|idt"                               t$          S t'          |                                          s4t	          d           t	          d           t	          d           t$          S | t	           |                       t$          S t          |          D ]}||         }	t	          | d           |	st	          d           .|	D ]k}
|
	                    dd          }|
	                    d          p|
	                    d          pd}|r||k    rd| dnd}t	          d| d| |            lt	                       t$          S )u4  Print the channel directory (all configured targets across platforms).

    Uses ``load_directory()`` for structured JSON output and
    ``format_directory_for_display()`` for the human-readable rendering that
    the send_message tool itself shows to the model — keeps the two surfaces
    identical.
    r   )format_directory_for_displayload_directoryz/hermes send: failed to load channel directory: r   Nz/hermes send: failed to read channel directory: 	platformsc                L    i | ] \  }}|                                 k    ||!S  )lower).0kvkeys      r"   
<dictcomp>z!_list_targets.<locals>.<dictcomp>   s1    KKKTQ!''))s:J:JAq:J:J:Jr(   z,hermes send: no targets found for platform 'z'. Configured: z, z(none)r   )r2   defaultz@No messaging platforms configured or no channels discovered yet.zBSet one up with `hermes gateway setup`, or run the gateway once soz@channel discovery can populate ~/.hermes/channel_directory.json.:z  (no channels discovered yet)name?idchat_id z  []z  )gateway.channel_directoryrB   rC   	Exceptionr   r   r   r<   dictr;   r&   rG   itemsjoinsortedr7   r:   r*   r=   anyvalues)r@   r+   rB   rC   r    r1   rD   filtered	plat_namechannelschrO   rR   suffixrK   s                 @r"   _list_targetsrb      s\   	
 	
 	
 	
 	
 	
 	
 	
 	
    EEECJWWWWn   EEECJWWWW SWW[))/R00I 
##%%++--KKKKY__%6%6KKK 	!J J J#yy	):):;;GxJ JZ   
 ! 	 dj+y1!SIIIJJJy!!"" PQQQRSSSPQQQ **,,---I&&  	Y'ooo 	2333 	3 	3B66&#&&DffTll=bffY&7&7=2G)0LW__%7%%%%"F1y1141112222s7    
A$A A A	
A 
B$BBBNonec                 X   	 ddl m}  n# t          $ r d} Y nw xY w	 ddlm}  |            }n# t          $ r Y dS w xY w|dz  }| ry|                                re	  | t          |          dd           nH# t          $ r0 	  | t          |          dd	           n# t          $ r Y nw xY wY nt          $ r Y nw xY wddl}|d
z  }|                                sdS 	 ddl	}n# t          $ r Y dS w xY w	 t          |dd          5 }|                    |          pi }ddd           n# 1 swxY w Y   n# t          $ r Y dS w xY w	 ddlm}	  |	|          }n# t          $ r Y nw xY w	 ddlm}
 |
                    t!          |t"                    r|ni           }n# t          $ r Y nw xY wt!          |t"                    sdS |                                D ]O\  }}t!          |t          t&          t(          t*          f          s.||j        v r8t          |          |j        |<   PdS )u  Populate ``os.environ`` from ``~/.hermes/.env`` AND bridge top-level
    ``config.yaml`` keys into the environment so the underlying gateway
    config loader sees platform credentials and home channel IDs.

    ``send_message_tool`` reads tokens and home-channel IDs via
    ``os.getenv(...)`` on each call. The gateway process does two things at
    startup that ``hermes send`` must replicate when invoked standalone:

    1. ``load_dotenv(~/.hermes/.env)`` — brings bot tokens into the env.
    2. Bridge top-level simple values from ``~/.hermes/config.yaml`` into
       ``os.environ`` (without overriding existing env vars). This is where
       ``TELEGRAM_HOME_CHANNEL`` and friends live when the user saved them
       via ``hermes config set``.

    See ``gateway/run.py`` for the canonical version of this bridge — we
    intentionally reimplement the minimum needed here so ``hermes send``
    doesn't pull in the full gateway module just to resolve a home channel.
    r   )load_dotenvN)get_hermes_homez.envTr   )overrider   zlatin-1zconfig.yamlrr   )_expand_env_vars)managed_scope)dotenvre   rV   hermes_cli.configrf   existsr*   r   osyamlopen	safe_loadri   
hermes_clirj   apply_managed_overlay
isinstancerW   rX   r.   floatr,   environ)re   rf   homeenv_pathrn   config_pathro   fhr1   ri   rj   rK   vals                r"   _load_hermes_envr|      sw   (&&&&&&&   555555      f}H 	x(( 		KHwGGGGG! 	 	 	CMMD9MMMMM    	 	 	D	 III&K    +sW555 	+..$$*C	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+   666666s##   
,,,,,,11C9N9N2V##TVWW    c4   IIKK # #S#S%677 	"*c((
3# #s   	 - 
;;A6 6
B;BB;
B*'B;)B**B;/	B;:B;C# #
C10C15D7 D+D7 +D//D7 2D/3D7 7
EE	E 
E('E(,2F 
F,+F,argsargparse.Namespacec           	     t   t                       t          | dd          rEt          | dd          }t          |t          | dd                    }t          j        |           t          t          | dd                    }|s4t          dt          j        	           t          j        t                     t          t          | dd          t          | d
d                    }||
                                s4t          dt          j        	           t          j        t                     t          | dd          }|r| d|                                 }ddlm} d||d} ||          }t          |t          | dd          t          | dd                    }t          j        |           dS )z9Entry point wired into the top-level argparse dispatcher.list_targetsFmessageNr7   )r+   tozhermes send: --to PLATFORM[:channel[:thread]] is required
Examples:
  hermes send --to telegram "hello"
  hermes send --to discord:#ops --file report.md
  hermes send --list      # list available targetsr   r   znhermes send: no message provided. Pass text as a positional argument, use --file PATH, or pipe data via stdin.subjectz

r   )send_message_toolsend)actiontargetr   r-   )r+   r-   )r|   getattrrb   r   r   r'   r   r   r   r#   r&   lstriptools.send_message_toolr   r?   )	r}   r@   	exit_coder   r   r   r   	tool_argsresults	            r"   cmd_sendr   *  s     t^U++  "$	488!/WT6SX=Y=YZZZ	WT46677F 	A
 	
 	
 	
 	
 	 i&&fd## G gmmooA	
 	
 	
 	

 	 dIt,,G 544'.."2"244 :99999  I y))F$..dGU++  I
 HYr(   argparse.ArgumentParserc                   |                      ddddt          j                  }|                    dddd	d
           |                    ddd	d           |                    dddd	d           |                    dddd	d           |                    dddddd           |                    dd ddd!"           |                    d#ddd$"           |                    t
          %           |S )&zCreate the ``send`` subparser and return it.

    Kept as a standalone function so the top-level parser builder can wire
    it in next to the other messaging subcommands without cluttering
    ``_parser.py`` or ``main.py``.
    r   zASend a message to a configured platform (scripts, cron jobs, CI).u!  Pipe text from any shell script to any messaging platform Hermes is already configured for. Reuses the gateway's platform credentials (~/.hermes/.env + ~/.hermes/config.yaml) — no LLM, no agent loop, no running gateway required for bot-token platforms like Telegram/Discord/Slack/Signal.a  Examples:
  hermes send --to telegram "deploy finished"
  echo "RAM 92%" | hermes send --to telegram:-1001234567890
  hermes send --to discord:#ops --file /tmp/report.md
  hermes send --to slack:#eng --subject "[CI]" --file build.log
  hermes send --to telegram "MEDIA:/tmp/chart.png"   # send a media attachment
  hermes send --list                  # all platforms
  hermes send --list telegram         # filter by platform

Exit codes: 0 ok, 1 delivery/backend error, 2 usage error.)helpdescriptionepilogformatter_classz-tz--toTARGETNzDelivery target. Format: 'platform' (home channel), 'platform:chat_id', 'platform:chat_id:thread_id', or 'platform:#channel-name'. Examples: telegram, telegram:-1001234567890:17585, discord:#ops, slack:C0123ABCD, signal:+15551234567.)metavarrM   r   r   rP   z4Message text. If omitted, read from --file or stdin.)nargsrM   r   z-fz--filePATHzRead message body from PATH (text only). Use '-' to force stdin. To send an image/document as an attachment, use MEDIA:<path> in the message text instead.z-sz	--subjectLINEz6Prepend a subject/header line before the message body.z-lz--listr   
store_trueFzRList available targets. Optional positional filter: `hermes send --list telegram`.)destr   rM   r   z-qz--quietz,Suppress stdout on success (exit code only).)r   rM   r   z--jsonz6Emit raw JSON result instead of human-readable output.)func)
add_parserargparseRawDescriptionHelpFormatteradd_argumentset_defaultsr   )
subparsersparsers     r"   register_send_subparserr   p  s    ""P<	I !<- #  F2 #     C	     (  
 
 
 E     a     ;     E	     X&&&Mr(   r   r   )r   r	   r
   r	   r   r	   )r$   r	   r   r	   )r)   r*   r+   r,   r-   r,   r   r.   )r@   r	   r+   r,   r   r.   )r   rc   )r}   r~   r   rc   )r   r   )__doc__
__future__r   r   r7   r   pathlibr   typingr   r   r<   r=   r#   r'   r?   rb   r|   r   r   __all__rF   r(   r"   <module>r      s&   4 # " " " " "   



             . . . .b   * * * *ZB B B BJT# T# T# T#nC C C CLd d d dN 0
1r(   