
    `gj9.                        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	m
Z
mZmZmZ  ej                  e      Ze G d 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ZddZddd	 	 	 	 	 	 	 ddZy)u  Shared ``/blueprint`` command logic for CLI, TUI, and gateway.

The conversational counterpart to the dashboard's Automation Blueprints form. Where a
surface has a screen, the user fills a form (dashboard / GUI app) and the API
calls ``fill_blueprint`` -> ``create_job`` directly. Where a surface is just a
chat line, the user picks a blueprint by name and the agent asks for what it
needs — pick a blueprint by name and the agent asks you for what it needs, one
question at a time (the messaging-assistant model: pick a blueprint → it asks you
a couple things → done).

Subcommand shapes:
  /blueprint                      list the catalog
  /blueprint <name>               name-match a blueprint, then SEED THE AGENT to
                                    ask the user for each value conversationally
  /blueprint <name> slot=val …    fill + create the cron job directly
                                    (the deterministic dashboard / docs / power-
                                    user shortcut — no agent turn)

The ``<name>`` form is forgiving: exact key, unique prefix, or fuzzy match all
resolve; an ambiguous query lists the candidates; an unknown one suggests the
closest. When it resolves, the handler returns an ``agent_seed`` — a natural-
language instruction built from the blueprint's typed slots + schedule/prompt
templates — that the calling surface feeds to the agent as a normal user turn
(gateway: rewrite ``event.text`` and fall through, the ``/steer`` pattern; CLI:
a one-shot pending seed the main loop runs). The agent then asks for each slot
and calls the existing ``cronjob`` tool. No new tool, no second job engine.

Parsing is shlex-based so quoted free-text values (``criteria="from my boss"``)
survive.
    )annotationsN)	dataclass)AnyDictListOptionalTuplec                  *    e Zd ZU dZded<   dZded<   y)BlueprintCommandResulta  Outcome of a ``/blueprint`` invocation.

    ``text`` is always shown to the user. When ``agent_seed`` is set, the
    calling surface should ALSO hand that seed to the agent as the user's next
    turn (the blueprint was matched and now the agent gathers the slot values
    conversationally). When ``agent_seed`` is None the command is fully handled
    (catalog listing, direct create, or an error) and nothing is sent to the
    agent.
    strtextNzOptional[str]
agent_seed)__name__
__module____qualname____doc____annotations__r        K/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/blueprint_cmd.pyr   r   +   s     I $J$r   r   c                    | | S 	 ddl m}  |d      } |d      }|r|r|| |d      xs d  |d      xs d dS y # t        $ r Y y w xY w)Nr   )get_session_envHERMES_SESSION_PLATFORMHERMES_SESSION_CHAT_IDHERMES_SESSION_CHAT_NAMEHERMES_SESSION_THREAD_ID)platformchat_id	chat_name	thread_id)gateway.session_contextr   	Exception)explicitr   r   r   s       r   _resolve_originr$   ;   sx    ;"#<=!":;$",-GHPD,-GHPD	    s   4< 	AAc                    i }g }| D ]R  }d|v r;|j                  d      \  }}}|j                         }|r|j                         ||<   B|j                  |       T ||fS )zJSplit ``slot=value`` tokens from bare tokens. Returns (values, leftovers).=)	partitionstripappend)tokensvalues	leftoverstokk_vs          r   	_parse_kvr1   O   sq    FI #:mmC(GAq!	AGGIq	 9r   c                  
 ddl m}m} | xs dj                         j	                         

sdg fS  |
      }||g fS |D cg c]Y  }|j
                  j	                         j                  
      s,t        
fd|j                  j                         D              r|[ }}t        |      dk(  r|d   g fS t        |      dkD  rd|fS |D cg c]X  }
|j
                  j	                         v s8
|j                  j	                         v s
|j                  j	                         v r|Z }}t        |      dk(  r|d   g fS t        |      dkD  rd|fS |D cg c]  }|j
                   }}t        j                  
|dd	      }t        |      dk(  r ||d         g fS t        |      dkD  rd|D 	cg c]
  }	 ||	       c}	fS dg fS c c}w c c}w c c}w c c}	w )
u  Resolve a free-typed blueprint name to a blueprint.

    Returns ``(blueprint, candidates)``:
      * exact key or unique prefix / fuzzy match -> ``(blueprint, [])``
      * ambiguous (2+ plausible) -> ``(None, [candidates…])``
      * no plausible match -> ``(None, [])``

    Matching is forgiving because chat-line users type the name (unlike the
    dashboard/Discord where it's picked): exact key first, then case-insensitive
    prefix on key or title, then a difflib fuzzy pass.
    r   )CATALOGget_blueprint Nc              3  \   K   | ]#  }|j                         j                         % y w)N)lower
startswith).0wqs     r   	<genexpr>z"match_blueprint.<locals>.<genexpr>x   s"     @1qwwy##A&@s   ),      g333333?ncutoff)cron.blueprint_catalogr3   r4   r(   r7   keyr8   anytitlesplitlendescriptiondifflibget_close_matches)queryr3   r4   exactrprefixsubstrkeyscloser.   r;   s             @r   match_blueprintrR   ^   s    >	"##%ARx!Eby 55;;=##A&@@@ 	
F 
 6{aay"}
6{QV| aggmmo!5amm>Q>Q>S9S 	
F  6{aay"}
6{QV| ##aAEE#D#%%a3?E
5zQU1X&**
5zA~61mA&6668O9 $
 7s   AGAGG5Gc                >    ddl m} 	  ||       S # t        $ r Y yw xY w)Nr   )_humanize_schedulezon a schedule)rB   rT   r"   )	blueprint_hs     r   rT   rT      s&    ?)} s    	c           
        ddl m} g }|j                  d| j                   d| j                   d| j
                          |j                  d       |j                  d       | j                  D ]  }d|j                   d	|j                   d
g}|j                  r;|j                  ddj                  t        t        |j                                      |j                  dvr|j                  d|j                   d       |j                  r|j                  d       |j                  r|j                  d|j                          |j                  dj                  |              |j                  d       |j                  d| j                    dt#        |       d| j$                   d       dj                  |      S )al  Build the natural-language fill-request the agent will act on.

    The agent reads this as a normal user turn, asks the user for each unfilled
    slot one at a time, then calls the ``cronjob`` tool with the
    cron expression it builds from the blueprint's ``schedule_template`` and the
    rendered prompt. Defaults are stated so the agent can offer them.
    r   )WEEKDAY_PRESETSzSet up the 'z+' automation for me (automation blueprint 'z'). r5   zgAsk me for each of these, one at a time, offering the default in brackets if I don't have a preference:z-  ()u    — one of: , )Nr5   z [default: ]z (optional)    — zOnce you have my answers, create the job by calling the cronjob tool with action='create'. Build the schedule as a cron expression from this template: `zR` (fill {minute}/{hour} from the chosen time, {dow} from the weekday choice using z, {interval_min} from any interval). Use this exact prompt for the job (substituting my answers into any {slot} placeholders): "zA". Confirm the schedule and what it will do before you create it.
)rB   rX   r)   rE   rC   rH   slotslabelnameoptionsjoinmapr   defaultoptionalhelpschedule_templatedictprompt_template)rU   rX   linessbitss        r   build_blueprint_seedrn      s    7E	LL
y' (MM?$y445	7 
LL	LL	1 __ 
$QWWIRxq)*99KK-		#c1992E(F'GHI99J&KK+aii[23::KK&66KK%x()RWWT]#
$ 
LL	LL	$667 8_-. /66?6O6O5P QI	I	 99Ur   c                     ddl m}  dg}| D ]K  }|j                  d|j                   d|j                          |j                  d|j
                          M |j                  d       dj                  |      S )	Nr   r3   uL   Automation Blueprints — `/blueprint <name>` and I'll ask you what I need:
     • r]   z    z
Tip: `/blueprint <name>` walks you through it. Power users can pass values inline, e.g. `/blueprint morning-brief time=08:00`.r^   )rB   r3   r)   rC   rE   rH   rc   )r3   rk   rM   s      r   _fmt_catalogrr      sy    .\]E -vaeeWE!''34tAMM?+,- 
LL	J 99Ur   c                    d|  dg}|D ]-  }|j                  d|j                   d|j                          / |j                  d       dj                  |      S )N'u,   ' matches several blueprints — which one?
rq   r]   z5
Run `/blueprint <name>` with one of the names above.r^   )r)   rC   rE   rc   )rK   
candidatesrk   rM   s       r   _fmt_candidatesrv      s`    DEFE 5vaeeWE!''345	LLIJ99Ur   c                    ddl m} |D cg c]  }|j                   }}t        j                  | xs dj                         |dd      }d|  d}|r|d	d
j                  |      z   dz   z  }|dz  }|S c c}w )Nr   rp   r5   r>   g?r?   z!No automation blueprint matches 'z'.z Did you mean: r[   ?z# Run /blueprint to see the catalog.)rB   r3   rC   rI   rJ   r7   rc   )rK   r3   rM   rP   rQ   msgs         r   _fmt_no_matchrz      s    ."#aAEE#D#%%u{&9&9&;TQsSE-eWB
7C 499U#33c9900CJ $s   A4c                    | dk(  ryy)zPost-create management hint. /cron is a CLI-only slash command; on
    gateway platforms the user manages jobs by asking the agent (cronjob tool)
    or from the dashboard.clizManage it with /cron.z-Ask me to list, pause, or remove it any time.r   )surfaces    r   _manage_hintr~      s     %&:r   r|   )originr}   c          
     >   	 ddl m}m} 	 t        j                  | xs d      }|st        t                     S |d   }t        |dd       \  }}	t        |      \  }
}|
+|rt        t        ||            S t        t        |            S |s4t        |
      }d|
j                    d	t#        |
       d
}t        ||      S 	  ||
|t%        |            }	 ddlm}  |di |}|j-                  d      xs |j-                  dd      }t        d|
j                    d|rd| dndz   d|j-                  dd       dt/        |       z         S # t        $ r+}t        j                  d|       t        d      cY d}~S d}~ww xY w# t        $ r | xs dj                         }Y w xY w# |$ r3}t        d|
j                    d| d|
j&                   d      cY d}~S d}~ww xY w# t        $ r.}t        j                  d|       t        d|       cY d}~S d}~ww xY w)u  Dispatch a ``/blueprint`` invocation.

    Returns a :class:`BlueprintCommandResult`. When ``agent_seed`` is set the
    caller must feed it to the agent as the next user turn; otherwise the
    command is fully handled and only ``text`` is shown.

    ``args`` is everything after ``/blueprint``. ``origin`` lets a directly
    created job deliver back to the chat it was set up from. ``surface``
    (``"cli"`` | ``"gateway"``) picks the right wording for follow-up hints —
    ``/cron`` only exists on the CLI.
    r   )fill_blueprintBlueprintFillErrorz#blueprint catalog import failed: %sz4Automation Blueprints are unavailable in this build.Nr5   r=   zSetting up 'z' (u%   ). I'll ask you a couple of things…)r   )r   zCan't set up 'z': z
Or just run /blueprint z! and I'll ask you for the values.)
create_jobzblueprint create_job failed: %szFailed to create the job: schedule_displayschedulezScheduled 'rt   rY   rZ   z, delivering to deliverr   z. r   )rB   r   r   r"   loggerdebugr   shlexrF   
ValueErrorrr   r1   rR   rv   rz   rn   rE   rT   r$   rC   	cron.jobsr   getr~   )argsr   r}   r   r   er*   rK   r+   	_leftoverrU   ru   seedr   specr   jobscheds                     r   handle_blueprint_commandr      sJ   "^M
&TZR(
 %ln551IE!&*-FI+E2Iz)/%*LMM%mE&:;; #I.9??+3/A)/L.M N1 1 	 &dt<<
i8OPH( 4 
 GG&'C488J+CE!
ioo&a(!Rwa=r	+TXXi:;2l7>S=T
U	V c  ^:A>%&\]]^  &*"##%&8  
%Y__-S 4&&/mm_4UW
 	

  H6:%(B1#&FGGHsj   E F F* G% 	F E>8F>FF'&F'*G"/(GG"G"%	H.#HHH)r#   Optional[Dict[str, Any]]returnr   )r   zTuple[Dict[str, str], list])rK   r   r   zTuple[Optional[Any], List[Any]])r   r   )rK   r   ru   z	List[Any]r   r   )rK   r   r   r   )r}   r   r   r   )r   r   r   r   r}   r   r   r   )r   
__future__r   rI   loggingr   dataclassesr   typingr   r   r   r   r	   	getLoggerr   r   r   r$   r1   rR   rT   rn   rr   rv   rz   r~   r   r   r   r   <module>r      s   > #    ! 3 3			8	$ % % %(3l+\	; (,	H
H %H 	H
 Hr   