
    sji                      U d Z ddlm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
mZ ddlmZmZ ddlmZmZmZmZ ddlmZ ddlmZ dad	ed
<   ddZ ej        e          Z	 ddlmZm Z  ddl!m"Z"m#Z# n# e$$ r e%Ze%Z"dZ dZ#Y nw xY w ed           G d d                      Z& e'h d          Z(ded<   g  e&dddddd           e&dddddd d!           e&d"d#ddd$%           e&d&d'dd(           e&d)d*dd(           e&d+d,dd(           e&d-d.dd/0           e&d1d2d           e&d3d4ddd5d67           e&d8d9dd:0           e&d;d<dd0           e&d=d>dd?d@           e&dAdBddCdD           e&dEdFdddGdHI           e&dJdKddLdMD           e&dNdOddP0           e&dQdRdddSdTU           e&dVdWdXddYZ           e&d[d\dXdd]Z           e&d^d_dd d^`           e&dadbdddcdd           e&dedfdddgdd           e&dhdidddjdd           e&dkdlddmdndo           e&dpdqddrds           e&dtduddvddwdxy           e&dzd{dd|dnddz!           e&d}d~ddndd}           e&dddddd           e&ddddddd           e&dddd0           e&ddddddd!           e&ddddndd           e&ddddd           e&dddd           e&dddddddd           e&ddddddd           e&ddd           e&ddddd           e&ddddd           e&dddd0           e&ddd           e&dddXd(           e&dddXddd           e&dddXdddd!           e&dddXd0           e&dddXdd           e&dddXdddĬI           e&dddXddddǬȦ           e&ddddd̬ͦ           e&dddXdddѦ           e&dddXdddĬI           e&dddXddd֦           e&dddXd           e&dddXddܬͦ           e&dddXddͦ           e&dddXddͦ           e&dddXddZ           e&dddXddd)                    e           deI           e&dddXddͦ           e&dddXdddĬI           e&dddXdddI           e&ddddd@           e&dddd(           e&dddddd            e&dddddͦ           e&dddd           e&dd	ddd
dI           e&ddddddU           e&dddd0           e&dddd0           e&ddddddI           e&dddddd           e&d d!dd"d#D           e&d$d%ddd&ͦ           e&d'd(ddd)d֦           e&d*d+dd(           e&d,d-dd./           e&d0d1dd2/           e&d3d4ddd5d6I           e&d7d8dd(           e&d9d:ddd;dd<=           e&d>d?ddd@dAB           e&dCdDdddE           e&dFdGdddH           e&dIdJddK0           e&dLdMdddN           e&dOdPd           e&dQdRddS0           e&dTdUdddV           e&dWdXdddY%           e&dZd[ddd\Z           e&d]d^dd(           e&d_d`dddaZ           e&dbdcdd           e&dddeddfdddg           e&dhdiddj0           e&dkdldmddndoU          Z*dpedq<   dڐdsZ+ e+            Z,dredt<   dېdxZ-dܐdzZ.i Z/d{ed|<   e*D ]EZ0e0j1        s< e.e0          e/d}e0j2         <   e0j3        D ]Z4e0j5         d~e0j2         de/d}e4 <   Fi Z6ded<   e*D ]^Z0e0j1        sUe67                    e0j8        i           Z9e/d}e0j2                  e9d}e0j2         <   e0j3        D ]Z4e/d}e4          e9d}e4 <   _i Z:ded<   e*D ]%Z0e0j;        r e<e0j;                  e:d}e0j2         <   &dddZ=ded<    ej>        d          Z?e*D ]`Z0d}e0j2         Z@e@e:v se0jA        se?B                    e0jA                  ZCeCr+eCD                    d          E                    d          e:e@<   a e'd e*D                       ZFded<   dݐdZG e'd e*D                       ZHded<   dސdZIdސdZJdߐdZKdddZLddZMddZNddZOddZPdZQdZRh dZSdZT	 ddZUddZVddZWddZXddZYddZZdZ[	 e[Z\ ej>        d          Z] ej>        d          Z^ddZ_ddZ`e`Za	 	 dddZbdddńZcddƄZdddȄZedZfdZg ej>        dʦ          Zh e'h dˣ          ZidZj e'h dͣ          Zkdd΄ZlddτZmddd҄ZnddӄZo G dԄ de"          Zp G dք de          Zqdd؄ZrdS (  a  Slash command definitions and autocomplete for the Hermes CLI.

Central registry for all slash commands. Every consumer -- CLI help, gateway
dispatch, Telegram BotCommands, Slack subcommand mapping, autocomplete --
derives its data from ``COMMAND_REGISTRY``.

To add a command: add a ``CommandDef`` entry to ``COMMAND_REGISTRY``.
To add an alias: set ``aliases=("short",)`` on the existing ``CommandDef``.
    )annotationsN)CallableMapping)	dataclassfield)AnyDictOptionalTuple)is_truthy_value)INDICATOR_STYLESzSOptional[Tuple[Tuple[Optional[str], Optional[int], Optional[int]], Dict[str, Any]]]_personalities_memoreturnDict[str, Any]c                 >   ddl m}  ddlm} 	 ddlm}  |            }|                                }t          |          |j        |j	        f}n# t          $ r d}Y nw xY wt          t          d         |k    rt          d         S  | |                       }||fa|S )u@  Return the available personalities map, memoised on config mtime.

    Wraps ``available_personalities(load_cli_config())`` — the single owner of
    built-ins + user overrides. Built-ins are static for the process lifetime,
    so keying on the config file's path+mtime+size keeps the memo
    freshness-correct.
    r   load_cli_config)available_personalities)get_config_pathNNNN   )clir   hermes_cli.personalityr   hermes_cli.configr   statstrst_mtime_nsst_size	Exceptionr   )r   r   r   cfg_pathstsigpersonalitiess          7/home/agent/.hermes/hermes-agent/hermes_cli/commands.py_personalities_from_cli_configr%   &   s     $#####>>>>>>!555555"?$$]]__8}}bnbj9 ! ! ! ! &+>q+AS+H+H"1%%++OO,=,=>>M.s   A A AA)AutoSuggest
Suggestion)	Completer
CompletionT)frozenc                      e Zd ZU dZded<   ded<   ded<   dZded<   d	Zded
<   dZded<   dZded<   dZ	ded<   dZ
ded<   dZded<   dZded<   dZded<   dS )
CommandDefz%Definition of a single slash command.r   namedescriptioncategory tuple[str, ...]aliases 	args_hintsubcommandsFboolcli_onlygateway_onlyN
str | Nonegateway_config_gaterejectbusy_policybusy_handlerexecute)__name__
__module____qualname____doc____annotations__r2   r4   r5   r7   r8   r:   r<   r=   r>   r0       r$   r,   r,   V   s         //IIIMMM!G!!!!I#%K%%%%HL&*****"  K
  $L#### GrD   r,   >   r;   dispatchinterrupt_then_dispatchzfrozenset[str]VALID_BUSY_POLICIESstartz0Acknowledge platform start pings without a replySessionrE   )r8   r<   r=   newz0Start a new session (fresh session ID + history))resetz[name]rF   )r2   r4   r<   r=   topicz,Enable or inspect Telegram DM topic sessionsz[off|help|session-id])r8   r4   clearz$Clear screen and start a new session)r7   redrawz6Force a full UI repaint (recovers from terminal drift)historyzShow conversation historysavez8Export the current conversation (bare /save shows usage)z"<json|md|html> [filename] [redact]r4   retryz(Retry the last message (resend to agent)promptz<Compose your next prompt in $EDITOR (markdown), then send itz[initial text])compose)r7   r4   r2   undoz.Back up N user turns and re-prompt (default 1)z[N]titlez#Set a title for the current sessionhandoffzGHand off this session to a messaging platform (Telegram, Discord, etc.)z
<platform>)r4   r7   branchz5Branch the current session (explore a different path))fork)r2   r4   worktreez3Show, list, create, or prune isolated git worktreesz#[new [name]|list|prune [--dry-run]])rJ   listprune)r7   r4   r5   compresszhCompress conversation context (add 'here [N]' to keep recent N turns; --preview shows what would happen))compactz.[here [N] | focus topic | --preview|--dry-run]rollbackzWList or restore filesystem checkpoints (restores keep your hand-edits; --all overrides)z[number] [--all]snapshotz8Create or restore state snapshots of Hermes config/state)snapz[create|restore <id>|prune])r7   r2   r4   exportz?Export a profile (config, skills, theme) to a shareable archiveConfigurationz[profile] [-o output.tar.gz])r7   r4   importz0Import a shared profile archive as a new profilez <archive.tar.gz> [--name <name>]stopz%Kill all running background processes)r<   r=   pausez>Pause new work globally (emergency stop); '/pause off' resumesz[reason | off])r8   r4   r<   approvez#Approve a pending dangerous commandz[session|always]denyz;Deny a pending dangerous command (optionally with a reason)z[all] [reason]
backgroundzRun a prompt in the background)bgbtwz<prompt>)r2   r4   r<   agentsz$Show active agents and running tasks)tasks)r2   r<   journeyz"Open the learning journey timeline)learningmemory-graphz[list|delete <id>|edit <id>])r[   deleteedit)r2   r7   r4   r5   queuez4Queue a prompt for the next turn (doesn't interrupt))qsteerz>Inject a message after the next tool call without interrupting)r4   r<   r=   goalz?Set a standing goal Hermes works on across turns until achievedze[text | draft <text> | show | gate add <cmd> | pause | resume | clear | status | wait <pid> | unwait]	heartbeatz<Set a recurring prompt that re-enters this session when idle)hbz=[every <interval> <prompt> | status | pause | resume | clear])statusrf   resumerM   )r2   r4   r5   r<   refinez>Review this conversation now and save lessons to memory/skillsz[focus instructions]loopz7Re-run a prompt on a recurring interval in this session)	proactivezV[interval] <prompt> [--times N] [--until <condition>] | status | pause | resume | stopmoazTRun one prompt through the default Mixture of Agents preset, then restore your modelr;   subgoalz/Add or manage extra criteria on the active goalz[text | remove N | clear])r4   r<   ry   z,Show session, model, token, and context info)r<   egresszShow Docker egress proxy statusz[status])ry   )r4   r5   r<   r=   r>   contextziShow detailed context window view with usage gauge, category breakdown, compression stats, and throughput)ctxz[all])allwhoamiz-Show your slash command access (admin / user)Infoprofilez+Show active profile name and home directory)r<   r>   sethomez!Set this chat as the home channel)zset-home)r8   r2   rz   z!Resume a previously-named sessionsessionsz#Browse and resume previous sessionsconfigzShow current configurationmodelz2Switch model (session-scoped; --global to persist)z:[model] [--provider name] [--global|--session] [--refresh]zcodex-runtimez7Toggle codex app-server runtime for OpenAI/Codex models)codex_runtimez[auto|codex_app_server]personalityzSet a predefined personality	statusbarz#Toggle the context/model status bar)sb)r7   r2   batteryz8Toggle a color-coded battery indicator in the status barz[on|off|status])onoffry   
timestampsz2Toggle [HH:MM] timestamps on messages and /history)ts)r7   r4   r5   r2   diffz)Show git changes in the working directoryz'[staged|all|session] [--stat] [path...])stagedr   session)r4   r5   verbosez9Cycle tool progress display: off -> new -> all -> verbosezdisplay.tool_progress_command)r7   r:   r<   focusuB   Toggle focus view — show only your prompt and the final responsefooterz7Toggle gateway runtime-metadata footer on final replies)r4   r5   r<   yoloz7Toggle YOLO mode (skip all dangerous command approvals)	approvalsz:Show or set the persistent dangerous-command approval modez[manual|smart|off])manualsmartr   	reasoningz#Manage reasoning effort and displayz'[level|show|hide|full|clamp] [--global])noneminimallowmediumhighxhighmaxultrashowhider   r   fullclamp--globalfastuS   Toggle fast mode — OpenAI Priority Processing / Anthropic Fast Mode (Normal/Fast)z[normal|fast|status] [--global])normalr   ry   r   r   r   skinz%Show or change the display skin/theme	indicatorz!Pick the TUI busy-indicator style[|]voicezToggle voice modez[on|off|tts|status])r   r   ttsry   wakez*Toggle the 'Hey Hermes' wake word listenerbusyz/Control what Enter does while Hermes is workingz[queue|steer|interrupt|status])rs   ru   	interruptry   toolsz4Manage tools: /tools [list|disable|enable] [name...]zTools & Skillsz[list|disable|enable] [name...]toolsetszList available toolsetsskillsz*Search, install, inspect, or manage skillszskills.write_approval)
searchbrowseinspectinstallauditpendingrg   r;   r   approval)r7   r:   r5   memoryz7Review pending memory writes / toggle the approval gatez-[pending|approve|reject|approval] [id|on|off])r   rg   r;   r   bundlesz8List skill bundles (aliases /<name> for multiple skills))r>   petz>Toggle or adopt a petdex mascot (/pet, /pet list, /pet <slug>)z[toggle|list|scale <n>|<slug>])toggler[   scaler   hatchz,Generate a new petdex pet from a description)zgenerate-petz[description]learnzPLearn a reusable skill from anything you describe (dirs, URLs, this chat, notes)z<what to learn from>initzBGenerate or update AGENTS.md project instructions from a repo scanz[notes]cronzManage scheduled tasksz[subcommand])r[   addcreaterr   rf   rz   runremovesuggestionsz-Review suggested automations (accept/dismiss))suggestz[accept|dismiss N | catalog])acceptdismisscatalogrM   )r2   r4   r5   	blueprintz.Set up an automation from a blueprint template)bpz[name] [slot=value ...]curatorzGBackground skill maintenance (status, run, pin, archive, list-archived))ry   r   rf   rz   pinunpinrestorezlist-archivedkanbanz:Multi-profile collaboration board (tasks, links, comments))!r   boardsr   r[   lsr   assignreclaimreassigndiagnosticsdiaglinkunlinkclaimcommentcompleterr   blockunblockarchivetailrE   statsznotify-subscribeznotify-listznotify-unsubscribelogrunsrw   	assigneesr   specifygcreloadz.Reload .env variables into the running sessionz
reload-mcpzReload MCP servers from config)
reload_mcp)r2   zreload-skillsz?Re-scan ~/.hermes/skills/ for newly installed or removed skills)reload_skillsbrowserzaConnect browser tools to your live Chromium-family browser via CDP, or switch to Browser Use modez[connect|disconnect|status|use])connect
disconnectry   usepluginsz'List installed plugins and their statuscommandsz*Browse all commands and skills (paginated)z[page]gateway_commands)r8   r4   r<   r>   helpzQShow available commands (/help skills lists skill commands, /help <text> filters)gateway_helpz[skills|<filter>])r<   r>   r4   palettez,Open the fuzzy command palette (also Ctrl+P))r7   r<   restartz9Gracefully restart the gateway after draining active runs)r8   r<   usagezLShow token usage and rate limits; `reset` redeems a banked Codex limit resetz[reset [--force]]subscriptionz0View your Nous plan and change it in the browser)upgradetopupz7Show your Nous balance and manage billing on the portalinsightsz!Show usage insights and analyticsz[days]	platformsz&Show gateway/messaging platform status)gatewayplatformz1Pause, resume, or list a failing gateway platformz<pause|resume|list> [name]copyz-Copy the last assistant response to clipboardz[number]pastez*Attach clipboard image from your clipboardimagez.Attach a local image file for your next promptz<path>updatez)Update Hermes Agent to the latest versionversionzShow Hermes Agent version)v)r2   r<   r>   debugz@Upload debug report (system info + logs) and get shareable linksz[nous|local]quitz:Exit the CLI (use --delete to also remove session history)Exit)exitz
[--delete]zlist[CommandDef]COMMAND_REGISTRYdict[str, CommandDef]c                 P    i } t           D ]}|| |j        <   |j        D ]}|| |<   | S )z+Map every name and alias to its CommandDef.)r  r-   r2   )lookupcmdaliass      r$   _build_command_lookupr    sH    $&F    sx[ 	  	 EF5MM	 MrD   _COMMAND_LOOKUPr-   r   CommandDef | Nonec                    t                               |                                                     d                    S )zmResolve a command name or alias to its CommandDef.

    Accepts names with or without the leading slash.
    /)r  getlowerlstrip)r-   s    r$   resolve_commandr    s.    
 tzz||22377888rD   r  c                R    | j         r| j         d| j         d| j          dS | j        S )z;Build a CLI-facing description string including usage hint.z
 (usage: / ))r4   r.   r-   )r  s    r$   _build_descriptionr#    s:    
} I/HHSXHHHHHH?rD   dict[str, str]COMMANDSr  z (alias for /r"  zdict[str, dict[str, str]]COMMANDS_BY_CATEGORYzdict[str, list[str]]SUBCOMMANDS)r]   r^   r   r   ry   )ri   rj   rk   rl   rm   rs   rt   ru   rv   r   rw   rx   r{   r|   r}   r~   rn   ro   rp   )ContextzBackground & Automationzdict[str, tuple[str, ...]]HELP_SESSION_SUBGROUPSz[a-z]+(?:\|[a-z]+)+c              #  \   K   | ]'}|j         r|j        |j        g|j        R D ]}|V  (d S N)r7   r:   r-   r2   ).0r  r-   s      r$   	<genexpr>r-    su       3 3<3 23 (CK((	3 3 	 	3 3 3 3 3 3 3rD   GATEWAY_KNOWN_COMMANDSr9   r6   c                `    | sdS | t           v rdS t                      D ]\  }}}|| k    r dS dS )u  Return True if ``name`` resolves to a gateway-dispatchable slash command.

    This covers both built-in commands (``GATEWAY_KNOWN_COMMANDS`` derived
    from ``COMMAND_REGISTRY``) and plugin-registered commands, which are
    looked up lazily so importing this module never forces plugin
    discovery. Gateway code uses this to decide whether to emit
    ``command:<name>`` hooks — plugin commands get the same lifecycle
    events as built-ins.
    FT)r.  _iter_plugin_command_entries)r-   plugin_name_description
_args_hints       r$   is_gateway_known_commandr4    sZ      u%%%t1M1O1O  -\:$44 5rD   c              #  :   K   | ]}|j         d k    |j        V  dS )r;   N)r<   r-   )r,  r  s     r$   r-  r-    s9       ; ;COx,G,GCH,G,G,G,G; ;rD   ACTIVE_SESSION_BYPASS_COMMANDScommand_namec                F    | sdS t          |           }|duo
|j        dk    S )a  Return True when *command_name* must interrupt a running agent first.

    Derived from the registry: commands whose ``busy_policy`` is
    "interrupt_then_dispatch" (the /stop, /new, /reset class).  Guard 1
    (gateway/platforms/base.py) routes these through the cancel-handoff
    path that serializes cancellation + runner response + pending drain.
    Accepts aliases (e.g. "reset" resolves to "new").
    FNrF   )r  r<   )r7  r  s     r$   is_interrupt_then_dispatchr9    s5      u
,
'
'Cd?Ks2KKKrD   c                ,    | rt          |           dundS )u  Return True for any resolvable slash command.

    Rationale: every gateway-registered slash command either has a
    specific Level-2 handler in gateway/run.py (/stop, /new, /model,
    /approve, etc.) or reaches the running-agent catch-all that returns
    a "busy — wait or /stop first" response. In both paths the command
    is dispatched, not queued.

    Queueing is always wrong for a recognized slash command because the
    safety net in gateway.run discards any command text that reaches
    the pending queue — which meant a mid-run /model (or /reasoning,
    /voice, /insights, /title, /resume, /retry, /undo, /compress,
    /usage, /reload-mcp, /sethome, /reset) would silently
    interrupt the agent AND get discarded, producing a zero-char
    response. See issue #5057 / PRs #6252, #10370, #4665.

    ACTIVE_SESSION_BYPASS_COMMANDS remains the subset of commands with
    explicit Level-2 handlers; the rest fall through to the catch-all.
    NF)r  )r7  s    r$   should_bypass_active_sessionr;  "  s"    ( 9EO?<((44%OrD   set[str]c                    d t           D             } | st                      S 	 ddlm}  |            }n# t          $ r t                      cY S w xY wt                      }| D ]y}|}|j                            d          D ]/}t          |t                    r|	                    |          }-d} t          |d          r|                    |j                   z|S )zReturn canonical names of commands whose ``gateway_config_gate`` is truthy.

    Reads ``config.yaml`` and walks the dot-separated key path for each
    config-gated command.  Returns an empty set on any error so callers
    degrade gracefully.
    c                     g | ]}|j         	|S r0   )r:   )r,  cs     r$   
<listcomp>z)_resolve_config_gates.<locals>.<listcomp>@  s     BBB1A,ABQBBBrD   r   read_raw_config.NF)default)r  setr   rB  r   r:   split
isinstancedictr  r   r   r-   )gatedrB  cfgresultr  valkeys          r$   _resolve_config_gatesrN  9  s    CB(BBBE uu555555o   uuuuF 	! 	!*0055 	 	C#t$$ ggcll3... 	!JJsx   Ms   4 AAconfig_overridesset[str] | Nonec                \    | j         sdS | j        r||nt                      }| j        |v S dS )a}  Check if *cmd* should appear in gateway surfaces (help, menus, mappings).

    Unconditionally available when ``cli_only`` is False.  When ``cli_only``
    is True but ``gateway_config_gate`` is set, the command is available only
    when the config value is truthy.  Pass *config_overrides* (from
    ``_resolve_config_gates()``) to avoid re-reading config for every command.
    TNF)r7   r:   rN  r-   )r  rO  	overridess      r$   _is_gateway_availablerS  V  sG     < t
 %(8(D$$J_JaJa	x9$$5rD   r4   c                P    |                                                      d          S )zFReturn True when selecting a command without text would be incomplete.<)strip
startswithrQ   s    r$   _requires_argumentrX  f  s     ??'',,,rD   	list[str]c            	        t                      } g }t          D ]}t          ||           s|j        r
d|j         nd}g }|j        D ]Z}|                    dd          |j                            dd          k    r||j        k    rA|                    d| d           [|rdd                    |           d	nd}|                    d|j         | d
|j	         |            |S )z3Generate gateway help text lines from the registry.r!  r3   -_z`/`z	 (alias: z, r"  z` -- )
rN  r  rS  r4   r2   replacer-   appendjoinr.   )rR  linesr  argsalias_partsa
alias_notes          r$   gateway_help_linesrf  k  s!   %''IE N N$S)44 	&)m;"3="""!# 	* 	*Ayyc""ch&6&6sC&@&@@@Q#(]]yAyyy))))>IQ:;!7!7::::r
L#(LDLLsL
LLMMMMLrD   list[tuple[str, str, str]]c                    	 ddl m}  n# t          $ r g cY S w xY w	  |             pi }n# t          $ r g cY S w xY wg }|                                D ]\  }}t	          |t
                    rt	          |t                    s0t          |                    d          pd|           }t          |                    d          pd                                          }|	                    |||f           |S )am  Yield (name, description, args_hint) tuples for all plugin slash commands.

    Plugin commands are registered via
    :func:`hermes_cli.plugins.PluginContext.register_command`. They behave
    like ``CommandDef`` entries for gateway surfacing: they appear in the
    Telegram command menu, in Slack's ``/hermes`` subcommand mapping, and
    (via :func:`plugins.platforms.discord.adapter._register_slash_commands`) in
    Discord's native slash command picker.

    Lookup is lazy so importing this module never forces plugin discovery
    (which can trigger filesystem scans and environment-dependent
    behavior).
    r   get_plugin_commandsr.   Run /r4   r3   )
hermes_cli.pluginsrj  r   itemsrG  r   rH  r  rV  r_  )rj  r   entriesr-   metar.   r4   s          r$   r0  r0  ~  s5   :::::::   			&&((.B   			*,Gnn&& 7 7
d$$$ 	JtT,B,B 	$((=11C^T^^DD--344::<<	k956666Ns   	 ) 88list[tuple[str, str]]c                 Z   t                      } g }t          D ]E}t          ||           st          |j                  }|r|                    ||j        f           Ft                      D ]>\  }}}t          |          rt          |          }|r|                    ||f           ?|S )ac  Return (command_name, description) pairs for Telegram setMyCommands.

    Telegram command names cannot contain hyphens, so they are replaced with
    underscores.  Aliases are skipped -- Telegram shows one menu entry per
    canonical command.

    Built-in commands that require arguments (e.g. /queue, /steer, /background)
    are **included** because their handlers return usage text when selected
    without a payload, making them discoverable via autocomplete.

    Plugin-registered slash commands that require arguments are **excluded**
    because plugins may not provide a no-arg usage fallback.
    )	rN  r  rS  _sanitize_telegram_namer-   r_  r.   r0  rX  )rR  rK  r  tg_namer-   r.   r4   s          r$   telegram_bot_commandsrt    s     &''I$&F 6 6$S)44 	 *#(33 	6MM7CO4555(D(F(F 2 2$k9i(( 	)$// 	2MM7K0111MrD   <   d   >   r_  prependr^  )r   rJ   re   ry   r   rz   r   r   r  r   r
  r   r   rg   rh   rs   ru   ri   r   r   r  r  r   r   rootMapping[str, Any]pathc                    | }|D ]0}t          |t                    si c S |                    |          }1t          |t                    r|ni S r+  )rG  r   r  )rx  rz  noderM  s       r$   _nested_mappingr}    s[    D  $(( 	IIIxx}}dG,,444"4rD   dict[str, Any]c            	        	 ddl m}   |             pi }n# t          $ r i }Y nw xY wt          |t                    si }t          t          |dddd                    }|                    dt                    }	 t          |          }n# t          t          f$ r
 t          }Y nw xY wt          dt          t          |                    }t          |                    d	          pd
                                                                          }|t$          vrd
}|                    d          }t          |t&                    rd |D             }ng }|||dS )zReturn normalized Telegram command-menu config with safe defaults.

    Canonical user-facing path:
    ``platforms.telegram.extra.command_menu``.
    r   rA  r  telegramextracommand_menumax_commandsr   priority_moderw  priorityc                n    g | ]2}t          |                                          #t          |          3S r0   )r   rV  )r,  items     r$   r@  z1_telegram_command_menu_config.<locals>.<listcomp>  s3    LLL$#d))//:K:KLCIILLLrD   )r  r  r  )r   rB  r   rG  r   rH  r}  r  #_DEFAULT_TELEGRAM_MENU_MAX_COMMANDSint	TypeError
ValueErrorr   min_TELEGRAM_BOT_API_MAX_COMMANDSr   rV  r  _TELEGRAM_PRIORITY_MODESr[   )rB  raw_cfgmenu_cfgr  r  raw_priorityr  s          r$   _telegram_command_menu_configr    s   555555!/##)r   gw'' OG[*g~^^__H<<0STTL;<((z" ; ; ;:;q#<lKKLLL_55BCCIIKKQQSSM444!<<
++L,%% LL,LLL %&  s    $$:B
 
B%$B%r  c                 D    t          t                      d                   S )z@Return configured Telegram BotCommand menu cap with safe bounds.r  )r  r  r0   rD   r$   telegram_menu_max_commandsr    s    ,..~>???rD   	raw_nameslist[str] | tuple[str, ...]r1   c                    g }t                      }| D ]N}t          t          |                    }|r.||vr*|                    |           |                    |           Ot          |          S r+  )rE  rr  r   r   r_  tuple)r  rK  seenraw_namer-   s        r$   _dedupe_sanitized_namesr  $  sr    FUUD    &s8}}55 	 D$$HHTNNNMM$==rD   c                    t                      } t          t          | d                             }t          t          t                              }| d         dk    r|}n| d         dk    r||z   }n||z   }t          |          S )Nr  r  r^  r_  )r  r[   r  _TELEGRAM_MENU_PRIORITY)r  
configureddefaultsr  s       r$   _telegram_effective_priorityr  /  s    ,..H-hz.BCCDDJ+,CDDEEH I--!	/	"h	.	.*,!H,"<000rD   c                    d t          t                                D             d t          t          |           fd          D             S )Nc                    i | ]\  }}||	S r0   r0   )r,  indexr-   s      r$   
<dictcomp>z6_prioritize_telegram_menu_commands.<locals>.<dictcomp>A  s.       E4 	e  rD   c                    g | ]\  }}|S r0   r0   )r,  _indexcommands      r$   r@  z6_prioritize_telegram_menu_commands.<locals>.<listcomp>E  s,       FG 	  rD   c                r    | d         d         v rd| d         d                  | d         fn	d| d         fS )Nr   r   r0   )r  r  s    r$   <lambda>z4_prioritize_telegram_menu_commands.<locals>.<lambda>I  sT    
 AwqzX%%	 a$Q  Q rD   rM  )	enumerater  sorted)r   r  s    @r$   "_prioritize_telegram_menu_commandsr  >  s     $%A%C%CDD  H %h	 	 	 	 
  
  
   rD       z
[^a-z0-9_]z_{2,}rawc                    |                                                      dd          }t                              d|          }t                              d|          }|                    d          S )uR  Convert a command/skill/plugin name to a valid Telegram command name.

    Telegram requires: 1-32 chars, lowercase a-z, digits 0-9, underscores only.
    Steps: lowercase → replace hyphens with underscores → strip all other
    invalid characters → collapse consecutive underscores → strip leading/
    trailing underscores.
    r[  r\  r3   )r  r^  _TG_INVALID_CHARSsub_TG_MULTI_UNDERSCORErV  r  r-   s     r$   rr  rr  c  s[     99;;sC((D  T**D##C..D::c??rD   rn  list[tuple[str, ...]]reservedc                `   t          |          }g }| D ]}|^}}}t          |          t          k    rF|dt                   }||v r1|dt          dz
           }	t          d          D ]}
|	 |
 }||vr nc|}||v rj|                    |           |                    ||g|R            |S )a  Enforce 32-char command name limit with collision avoidance.

    Both Telegram and Discord cap slash command names at 32 characters.
    Names exceeding the limit are truncated.  If truncation creates a duplicate
    (against *reserved* names or earlier entries in the same batch), the name is
    shortened to 31 chars and a digit ``0``-``9`` is appended to differentiate.
    If all 10 digit slots are taken the entry is silently dropped.

    Accepts tuples of any length >= 2.  Extra elements beyond ``(name, desc)``
    (e.g. ``cmd_key``) are passed through unchanged, so callers can attach
    metadata that survives the rename.
    Nr   
   )rE  len_CMD_NAME_LIMITranger   r_  )rn  r  usedrK  entryr-   descr  	candidateprefixdigits              r$   _clamp_command_namesr  q  s      ]]DF , ,"dUt99&&-o-.ID  2223"2YY  E#) 25 2 2I ,, - D4<<tT*E**++++MrD   	max_slotsreserved_names
desc_limitsanitize_name'Callable[[str], str] | None'&tuple[list[tuple[str, str, str]], int]c                (    g }g }	 ddl m}  |            }t          |          D ]j}	|r ||	          n|	}
|
s||	                             dd          }t	          |          |k    r|d|dz
           dz   }|                    |
|f           kn# t          $ r Y nw xY wt          ||          }|                    d |D                        |D ]\  }}|                    ||d	f           t                      }	 dd
l
m}  ||           }n# t          $ r Y nw xY wg }	 ddlm} ddlm} ddl
m}m} t%          |                                          }t%          |dz                                                                d          dz   }|                    d          dz   g}|                    d  |            D                        |                    d  |            D                         |            }t          |          D ]}||         }|                    dd	            s#t-           fd|D                       s?                     |          rU|                    dd	          }||v rp|                    d          }|r ||          n|}
|
s|                    dd	          }t	          |          |k    r|d|dz
           dz   }|                    |
||f           n# t          $ r Y nw xY wt          ||          }t3          d|t	          |          z
            }t3          dt	          |          |z
            }|d|         D ]\  }}}|                    |||f           |d|         |fS )a  Collect plugin + skill entries for a gateway platform.

    Priority order:
      1. Plugin slash commands (take precedence over skills)
      2. Built-in skill commands (fill remaining slots, alphabetical)

    Only skills are trimmed when the cap is reached.
    Hub-installed skills are excluded.  Per-platform disabled skills are
    excluded.

    Args:
        platform: Platform identifier for per-platform skill filtering
            (``"telegram"``, ``"discord"``, etc.).
        max_slots: Maximum number of entries to return (remaining slots after
            built-in/core commands).
        reserved_names: Names already taken by built-in commands.  Mutated
            in-place as new names are added.
        desc_limit: Max description length (40 for Telegram, 100 for Discord).
        sanitize_name: Optional name transform applied before clamping, e.g.
            :func:`_sanitize_telegram_name` for Telegram.  May return an
            empty string to signal "skip this entry".

    Returns:
        ``(entries, hidden_count)`` where *entries* is a list of
        ``(name, description, cmd_key)`` triples and *hidden_count* is the
        number of skill entries dropped due to the cap.  ``cmd_key`` is the
        original ``/skill-name`` key from :func:`get_skill_commands`.
    r   ri  r.   Plugin commandN   ...c              3      K   | ]	\  }}|V  
d S r+  r0   r,  nr\  s      r$   r-  z1_collect_gateway_skill_entries.<locals>.<genexpr>  s&      551!555555rD   r3   get_disabled_skill_namesr  get_skill_commands
SKILLS_DIRget_external_skills_dirsget_project_skills_dirs.hubr  c              3  `   K   | ])}t          |                              d           d z   V  *dS r  Nr   rstripr,  ds     r$   r-  z1_collect_gateway_skill_entries.<locals>.<genexpr>  J       !
 !
)*CFFMM#$!
 !
 !
 !
 !
 !
rD   c              3  `   K   | ])}t          |                              d           d z   V  *dS r  r  r  s     r$   r-  z1_collect_gateway_skill_entries.<locals>.<genexpr>  r  rD   skill_md_pathc              3  B   K   | ]}                     |          V  d S r+  )rW  )r,  r  
skill_paths     r$   r-  z1_collect_gateway_skill_entries.<locals>.<genexpr>  s1      UUz,,V44UUUUUUrD   r-   )rl  rj  r  r  r  r_  r   r  r
  rE  agent.skill_utilsr  agent.skill_commandsr  tools.skills_toolr  r  r  r   resolver  extendanyrW  r  r   )!r  r  r  r  r  all_entriesplugin_pairsrj  plugin_cmdscmd_namer-   r  r  r  _platform_disabledr  skill_triplesr  r  r  r  _skills_dir_hub_dir_allowed_prefixes
skill_cmdscmd_keyinfo
skill_namer  	remaininghidden_countkr  s!                                   @r$   _collect_gateway_skill_entriesr    s   F /1K +-L::::::))++{++ 	. 	.H.;I==***D x(,,]<LMMD4yy:%%OZ!^O,u4t----	.     (nEEL55555555 ' '1Aq":&&&& $'55>>>>>>55xHHH    13M*;;;;;;000000WWWWWWWW*,,..//
V+446677>>sCCcI )//44s:;   !
 !
.F.F.H.H!
 !
 !
 	
 	
 	
 	   !
 !
.E.E.G.G!
 !
 !
 	
 	
 	
 ('))
j)) 	8 	8Gg&D/266J UUUUCTUUUUU $$X.. &"--J///~~c**H.;I==***D 88M2..D4yy:%%OZ!^O,u4  $g!67777'	8(    
 )GGM Ay3{#3#3344Iq#m,,y899L ), & &1aAq!9%%%%z	z"L00s7   B
B 
BB D 
D D &GK? ?
LLr  !tuple[list[tuple[str, str]], int]c                   t          t          t                                          }d |D             }t          |          }t          dt	          |          | z
            }t          d| t	          |          z
            }t          d||dt                    \  }}|                    d |D                        |d|          ||z   fS )u  Return Telegram menu commands capped to the Bot API limit.

    Priority order (higher priority = never bumped by overflow):
      1. Core CommandDef commands (always included)
      2. Plugin slash commands (take precedence over skills)
      3. Built-in skill commands (fill remaining slots, alphabetical)

    Skills are the only tier that gets trimmed when the cap is hit.
    User-installed hub skills are excluded — accessible via /skills.
    Skills disabled for the ``"telegram"`` platform (via ``hermes skills
    config``) are excluded from the menu entirely.

    Returns:
        (menu_commands, hidden_count) where hidden_count is the number of
        commands omitted due to the cap.
    c                    h | ]\  }}|S r0   r0   r  s      r$   	<setcomp>z)telegram_menu_commands.<locals>.<setcomp>3  s    222DAqa222rD   r   r  (   )r  r  r  r  r  c              3  &   K   | ]\  }}}||fV  d S r+  r0   )r,  r  r  _ks       r$   r-  z)telegram_menu_commands.<locals>.<genexpr>@  s,      7781aA777777rD   N)r  r[   rt  r   r  r  rr  r  )r  core_commandsr  all_commandshidden_core_countremaining_slotsrn  r  s           r$   telegram_menu_commandsr  !  s    " 7t<Q<S<S7T7TUUM22M222N&&LAs<00<?@@!\C,=,==>>O:!%-  G\ 77w777777&7H(HHHrD   c                B    t          d| t          |          d          S )u  Return skill entries for Discord slash command registration.

    Same priority and filtering logic as :func:`telegram_menu_commands`
    (plugins > skills, hub excluded, per-platform disabled excluded), but
    adapted for Discord's constraints:

    - Hyphens are allowed in names (no ``-`` → ``_`` sanitization)
    - Descriptions capped at 100 chars (Discord's per-field max)

    Args:
        max_slots: Available command slots (100 minus existing built-in count).
        reserved_names: Names of already-registered built-in commands.

    Returns:
        ``(entries, hidden_count)`` where *entries* is a list of
        ``(discord_name, description, cmd_key)`` triples.  ``cmd_key`` is
        the original ``/skill-name`` key needed for the slash handler callback.
    discordrv  )r  r  r  r  )r  rE  )r  r  s     r$   discord_skill_commandsr  D  s/    , *>**	   rD   Mtuple[dict[str, list[tuple[str, str, str]]], list[tuple[str, str, str]], int]c                   ddl m} t                      }	 ddlm}  |d          }n# t
          $ r Y nw xY wi }g }t                              | d          }d}	 ddlm	} ddlm
}	m}
 dd	lm} |                                }|d
z                                  }|g}	  |	            D ]C}	 |                     ||                                                     4# t
          $ r Y @w xY wn# t
          $ r Y nw xY w	  |
            D ]C}	 |                     ||                                                     4# t
          $ r Y @w xY wn# t
          $ r Y nw xY w |            }t!          |          D ]}||         }|                    dd          }|s$ ||                                          }t%          |                              t%          |                    rqd}|D ]+}	 |                    |           n# t*          $ r Y %w xY w|} ||                    dd          }||v r|                    d          }|dd         }||v rQ||         }|dk    rt.                              d|||           nt.                              d||||           |dz  }3|||<   |                    dd          }t3          |          dk    r|dd         dz   }|j                            |          }|j        }t3          |          dk    r6|d         }|                    |g                               |||f           |                    |||f           n# t
          $ r Y nw xY w|||fS )uI  Return skill entries organized by category for Discord ``/skill`` autocomplete.

    Skills whose directory is nested at least 2 levels under a scan root
    (e.g. ``creative/ascii-art/SKILL.md``) are grouped by their top-level
    category.  Root-level skills (e.g. ``some-skill/SKILL.md`` directly under a
    scan root) are returned as
    *uncategorized*.

    Scan roots include the local ``SKILLS_DIR`` **and** any configured
    ``skills.external_dirs`` — matching the widened filter applied to the
    flat ``discord_skill_commands()`` collector in #18741. Without this
    parity, external-dir skills are visible via ``hermes skills list`` and
    the agent's ``/skill-name`` dispatch but silently absent from Discord's
    ``/skill`` autocomplete.

    Filtering mirrors :func:`discord_skill_commands`: hub skills excluded,
    per-platform disabled excluded, names clamped to 32 chars, descriptions
    clamped to 100 chars.

    The legacy 25-group × 25-subcommand caps (from the old nested
    ``/skill <cat> <name>`` layout) are **not** applied — the live caller
    (``_register_skill_group`` in ``gateway/platforms/discord.py``, refactored
    in PR #11580) flattens these results and feeds them into a single
    autocomplete callback, which scales to thousands of entries without any
    per-command payload concerns. ``hidden_count`` is retained in the return
    tuple for backward compatibility and still reports skills dropped for
    other reasons (32-char clamp collision vs a reserved name).

    Returns:
        ``(categories, uncategorized, hidden_count)``

        - *categories*: ``{category_name: [(name, description, cmd_key), ...]}``
        - *uncategorized*: ``[(name, description, cmd_key), ...]``
        - *hidden_count*: skills dropped due to name clamp collisions
          against already-registered command names.
    r   )Pathr  r
  r  z
<reserved>r  r  r  r  r  r3   Nr-   r  r  u   Discord /skill: %r (from %r) collides on its 32-char clamp with a reserved gateway command name %r — the skill will not appear in the /skill autocomplete. Rename the skill's frontmatter ``name:`` to differ in its first 32 chars.u   Discord /skill: %r and %r both clamp to %r on Discord's 32-char command-name limit — only %r will appear in the /skill autocomplete. Rename one skill's frontmatter ``name:`` to differ in its first 32 chars.r   r.   rv  a   r     )pathlibr  rE  r  r  r   rH  fromkeysr  r  r  r  r  r  r  r_  r  r  r   rW  relative_tor  r  loggerwarningr  parentparts
setdefault) r  _Pr  r  
categoriesuncategorized_names_usedhiddenr  r  r  r  r  r  _scan_rootsextprojr  r  r  r  spmatched_rootrx  r  r  discord_namepriorr  relr  cats                                    r$   "discord_skill_commands_by_categoryr'  b  s   N #"""""#&55>>>>>>55yIII    9;J02M #'--"M"MKFl;;;;;;WWWWWWWW000000 ((**'0022 "-	//11  &&rr#ww'8'89999    H
  	 	 	D		//11  &&rr$xx'7'7'9'9::::    H
  	 	 	D	''))
j)) M	D M	DGg&D/266J J''))B 2ww!!#h--00  '+L#  NN4((((!   H##&"--J///~~c**H#CRC=L{** $L1L((NN1
 %g|    NN.
 we   !(/K%88M2..D4yy3CRCy5( )''55CIE5zzQAh%%c2..55|T76STTTT$$lD'%BCCCC[M	D\     }f,,s   ) 
66AM) C- +0CC- 
C)&C- (C))C- ,M) -
C:7M) 9C::M) >E 0D<;E <
E	E E		E M) 
EM) EBM) .HM) 
HM) HEM) )
M65M62   z[^a-z0-9_\-]>   medndmsgprowhoawayfeedr`  muteopenleaveshrugrL   expandremindr   ry   collapse	shortcuts)rk   rj   >   r~   r   r   r  rf   r  r   r{   r
  r   r  r  rw   c                    |                                  }t                              d|          }|                    d          }|dt                   S )zConvert a command name to a valid Slack slash command name.

    Slack allows lowercase a-z, digits, hyphens, and underscores. Max 32
    chars. Uppercase is lowercased; invalid chars are stripped.
    r3   z-_N)r  _SLACK_INVALID_CHARSr  rV  _SLACK_NAME_LIMITr  s     r$   _sanitize_slack_namer;  \  sI     99;;D##B--D::dD"""##rD   c            	       	 t                      g t                      	                    d           	                    d           d	fd	} fd
t          D             }t
          D ]=}|                    |          }|$ | |d|j         d|j         |j	        pd           >t          D ]1}t          |          s | |j        |j        |j	        pd           2t          D ]A}t          |          s|j        D ]&} | |d|j         d|j         |j	        pd           'Bt                      D ]\  }}} | |||pd           S )a  Return (slash_name, description, usage_hint) triples for Slack.

    Every gateway-available command in ``COMMAND_REGISTRY`` is surfaced as
    a standalone Slack slash command (e.g. ``/btw``, ``/stop``, ``/model``),
    matching Discord's and Telegram's model where every command is a
    first-class slash and not a ``/hermes <verb>`` subcommand.

    Both canonical names and aliases are included so users can type any
    documented form (e.g. ``/background``, ``/bg``, and ``/btw`` all work).
    Plugin-registered slash commands are included too.

    Commands whose sanitized name collides with a Slack built-in
    (e.g. ``/status``, ``/me``, ``/join``) are silently skipped.  Users
    can still reach them via ``/hermes <command>``.

    Results are clamped to Slack's 50-command limit with duplicate-name
    avoidance. ``/hermes`` is always reserved as the first entry so the
    legacy ``/hermes <subcommand>`` form keeps working for anything that
    gets dropped by the clamp or for free-form questions.
    )hermesz"Talk to Hermes or run a subcommandz[subcommand] [args]r=  r-   r   r  hintr   Nonec                   t          |           }|r|v rd S |t          v rd S |t          v rd S t                    t          k    rd S                     ||d d         |d d         f                               |           d S )N   rv  )r;  _SLACK_RESERVED_COMMANDS_SLACK_VIA_HERMES_ONLYr  _SLACK_MAX_SLASH_COMMANDSr_  r   )r-   r  r>  
slack_namern  r  s       r$   _addz"slack_native_slashes.<locals>._add  s    )$//
 	Z4//F111F///Fw<<444F
D#JTcT
;<<<rD   c                J    i | ]}t          |          |j        D ]}|| S r0   )rS  r2   )r,  r  r  rR  s      r$   r  z(slack_native_slashes.<locals>.<dictcomp>  sX        i00 [	   	s   rD   NzAlias for /u    — r3   )r-   r   r  r   r>  r   r   r?  )rN  rE  r_  r   r  _SLACK_PRIORITY_ALIASESr  r-   r.   r4   rS  r2   r0  )
rF  _alias_to_cmdr  r  r-   r.   r4   rn  rR  r  s
          @@@r$   slack_native_slashesrJ  h  s   * &''I*,GUUD NNZ[[[HHX      &   #  M ) ] ]&&?DFchFFS_FFH[Y[\\\   = =$S)44 	SXs(;<<<<   ] ]$S)44 	[ 	] 	]E DFchFFS_FFH[Y[\\\\	] )E(F(F 1 1$k9T;	R0000NrD   )https://hermes-agent.local/slack/commandsrequest_urlc                    g }t                      D ]1\  }}}d| |pd| d| d}|r||d<   |                    |           2dd|iiS )u  Generate a Slack app manifest with all gateway commands as slashes.

    ``request_url`` is required by Slack's manifest schema for every slash
    command, but in Socket Mode (which we use) Slack ignores it and routes
    the command event through the WebSocket. A placeholder URL is fine.

    The returned dict is the ``features.slash_commands`` portion only —
    callers compose it into a full manifest (or merge into an existing
    one). Keeping it narrow avoids coupling us to the rest of the manifest
    schema (display_information, oauth_config, settings, etc.) which users
    set up once in the Slack UI and rarely change.
    r  rk  F)r  r.   should_escapeurl
usage_hintfeaturesslash_commands)rJ  r_  )rL  slashesr-   r  r   r  s         r$   slack_app_manifestrT    s     G133 	 	dE!4zz1>4>>"	
 
  	("'E,u)7344rD   c                     t                      } i }t          D ]7}t          ||           sd|j         ||j        <   |j        D ]
}d| ||<   8t                      D ]\  }}}||vrd| ||<   |S )a0  Return subcommand -> /command mapping for Slack /hermes handler.

    Maps both canonical names and aliases so /hermes bg do stuff works
    the same as /hermes background do stuff.

    Plugin-registered slash commands are included so ``/hermes <plugin-cmd>``
    routes through the plugin handler.
    r  )rN  r  rS  r-   r2   r0  )rR  mappingr  r  r-   r2  r3  s          r$   slack_subcommand_maprW    s     &''I G ) )$S)44 	*NN[ 	) 	)E([[GENN	)*F*H*H ' '&lJw&JJGDMNrD   c                  x   e Zd ZdZ	 	 	 d1d2d
Zd3dZd4dZd4dZed5d            Z	d6dZ
d7dZ eh d          Zed8d            Zed9d            Zed:d;d             Zed9d!            Zd:d;d"Zd<d$Zed=d'            Zd>d?d)Zed@d,            Zed@d-            Zed@d.            Zed@d/            Zd0 ZdS )ASlashCommandCompleterzJAutocomplete for built-in slash commands, subcommands, and skill commands.Nskill_commands_provider1Callable[[], Mapping[str, dict[str, Any]]] | Nonecommand_filterCallable[[str], bool] | Noneskill_bundles_providerr   r?  c                Z    || _         || _        || _        g | _        d| _        d| _        d S )Ng        r3   )_skill_commands_provider_command_filter_skill_bundles_provider_file_cache_file_cache_time_file_cache_cwd)selfrZ  r\  r^  s       r$   __init__zSlashCommandCompleter.__init__  s;     )@%-'=$&('*$&rD   slash_commandr   r6   c                |    | j         dS 	 t          |                      |                    S # t          $ r Y dS w xY w)NT)ra  r6   r   )rf  rh  s     r$   _command_allowedz&SlashCommandCompleter._command_allowed  sS    '4	,,];;<<< 	 	 	44	s   !- 
;;Mapping[str, dict[str, Any]]c                f    | j         i S 	 |                                  pi S # t          $ r i cY S w xY wr+  )r`  r   rf  s    r$   _iter_skill_commandsz*SlashCommandCompleter._iter_skill_commands	  sP    (0I	00228b8 	 	 	III	   ! 00c                f    | j         i S 	 |                                  pi S # t          $ r i cY S w xY wr+  )rb  r   rm  s    r$   _iter_skill_bundlesz)SlashCommandCompleter._iter_skill_bundles  sP    '/I	//117R7 	 	 	III	ro  tokenc                ~    d|                      d                              dd                                          z   S )zCanonicalize a typed skill token to its hyphenated /slug form.

        Mirrors resolve_skill_command_key() in agent/skill_commands.py:
        underscores (Telegram bot-command form) are interchangeable with
        hyphens.
        r  r\  r[  )r  r^  r  )rr  s    r$   _normalize_skill_tokenz,SlashCommandCompleter._normalize_skill_token  s7     U\\#&&..sC88>>@@@@rD   c                T    |                      |          |                                 v S r+  )rt  rn  )rf  rr  s     r$   _is_skill_commandz'SlashCommandCompleter._is_skill_command%  s'    **511T5N5N5P5PPPrD   textc              #  p  K   	 ddl m} n# t          $ r d}Y nw xY w|                                }|                    d          r|d}}n|dd         |d         }}t                      }|D ]I}|                     |          }||                                 vs||v r dS |                    |           Jt          |          |k    rdS |
                    d          sdS |                     |          }	|                                                                 D ]\  }
}|
|v s|

                    |	          st          |                    d	d
                    }|dd         t          |          dk    rdndz   }|
|	k    r|
 dn|
}t          |t          |           |
d|           V  dS )ug  Offer skill-command completions for stacked invocations.

        After ``/skill-a `` the user may chain more leading skills
        (``/skill-a /skill-b do XYZ``). While every whitespace-delimited
        token so far resolves to a distinct skill command and the current
        word under the cursor starts with ``/``, keep offering the remaining
        skill commands. The moment the chain is broken (a non-skill token
        appears, the cap is reached, or the user is typing plain instruction
        text) we offer nothing — instruction text must never be polluted
        with skill suggestions.
        r   )_MAX_STACKED_SKILLS   r!  r3   Nr  r.   Skill commandr(  r     ⚡ start_positiondisplaydisplay_meta)r  ry  r   rF  endswithrE  rt  rn  r   r  rW  rm  r   r  r)   )rf  rw  _captokens	completedcurrent_wordr  rr  rM  word_keyr  r  r.   
short_descreplacements                  r$   _stacked_skill_completionsz0SlashCommandCompleter._stacked_skill_completions(  s%     	HHHHHHH 	 	 	DDD	 == 	>&,b|II&,SbSk6":|I  	 	E--e44C$335555HHSMMMMt99F &&s++ 	F..|<<2244::<< 	 	ICd{{#..":":{dhh}oFFGGK$SbS)c+6F6F6K6KUUQSTJ (+hS))))CK #L 1 110J00	      	 	s    >   r   r   r   r  wordc                <    | |k    r| S | t           j        v r| S |  dS )u  Return replacement text for a completion.

        When the user has already typed the full command exactly (``/help``),
        returning ``help`` would be a no-op and prompt_toolkit suppresses the
        menu. Appending a trailing space keeps the dropdown visible and makes
        backspacing retrigger it naturally.

        However, commands that open pickers (model, skin, personality) should
        NOT get a trailing space — the TUI would apply the completion on Enter
        and block the picker from opening.
        r!  )rY  _PICKER_COMMANDS)r  r  s     r$   _completion_textz&SlashCommandCompleter._completion_textf  s4     tO,===O~~~rD   r9   c                    | sdS t          |           dz
  }|dk    r#| |         dk    r|dz  }|dk    r| |         dk    | |dz   d         }|sdS d|v rdS |                    d          sd|v r|S dS )u  Extract the current word if it looks like a file path.

        Returns the path-like token under the cursor, or None if the
        current word doesn't look like a path.  A word is path-like when
        it starts with ``./``, ``../``, ``~/``, ``/``, or contains a
        ``/`` separator (e.g. ``src/main.py``).

        Tokens containing a ``://`` scheme separator (e.g. URLs like
        ``https://example.com/x``) are excluded even though they contain a
        ``/`` — they are never useful local-path completions.
        Nr   r   r!  z://)z./z../~/r  r  r  rW  rw  ir  s      r$   _extract_path_wordz(SlashCommandCompleter._extract_path_wordz  s      	4 IIM1ffaCFA 1ffaCAEFF| 	4
 D==4??344 	tKtrD      limitr  c              #  F  K   t           j                            |           }|                    d          r|}d}n@t           j                            |          pd}t           j                            |          }	 t          j        |          }n# t          $ r Y dS w xY wd}|                                }t          |          D ]W}|r(|                                
                    |          s-||k    r dS t           j                            ||          }	t           j                            |	          }
| 
                    d          rAdt           j                            |	t           j                            d                    z   }nAt           j                            |           r|	}nt           j                            |	          }|
r|dz  }|
rdnd}|
rdnt          |	          }t!          |t#          |            ||z   |	          V  |d
z  }YdS )z8Yield Completion objects for file paths matching *word*.r  r3   rC  Nr   ~r  dirr~  r   )osrz  
expanduserr  dirnamebasenamelistdirOSErrorr  r  rW  r`  isdirrelpathisabs_file_size_labelr)   r  )r  r  expanded
search_dirr  rn  countprefix_lowerr  	full_pathis_dirdisplay_pathsuffixro  s                 r$   _path_completionsz'SlashCommandCompleter._path_completions  s)      7%%d++S!! 	0!JFF229cJW%%h//F	j,,GG 	 	 	FF	 ||~~G__ 	 	E ekkmm66|DD ~~Z77IW]]9--F s## :#bgooiASASTWAXAX&Y&YYt$$ :(  "wy99 $#"*SSF"C55(8(C(CD #D		z!	      QJEE=	 	s   =B 
B B c                    | sdS t          |           dz
  }|dk    r#| |         dk    r|dz  }|dk    r| |         dk    | |dz   d         }|                    d          sdS |S )z=Extract a bare ``@`` token for context reference completions.Nr   r   r!  @r  r  s      r$   _extract_context_wordz+SlashCommandCompleter._extract_context_word  s      	4IIM1ffaCFA 1ffaCAEFF|s## 	4rD   c              #  v  K   |                                 }d}|D ]g\  }}|                                                     |          r;|                                 |k    r#t          |t          |           ||          V  hdD ]}|dd         }||k    s|                    |          r|dk    }	||k    rdn|t          |          d         }
t          j                            |
          }|r|dk    rd	\  }}nZ|                    d
          r|d}}n@t          j                            |          pd}t          j        	                    |          }	 t	          j
        |          }n# t          $ r Y  dS w xY wd}|                                 }t          |          D ]}|r(|                                                     |          s,t          j                            ||          }t          j                            |          }|	|k    rr||k    r nlt          j                            |          }|rd
nd}|rdnt!          |          }| | | }t          |t          |           ||z   |          V  |dz  } dS |dd         }|                     |||          E d{V  dS )zYield Claude Code-style @ context completions.

        Bare ``@`` or ``@partial`` shows static references and matching
        files/folders.  ``@file:path`` and ``@folder:path`` are handled
        by the existing path completion path.
        ))z@diffzGit working tree diff)z@stagedzGit staged diff)@file:zAttach a file)@folder:zAttach a folder)z@git:z Git log with diffs (e.g. @git:5))z@url:zFetch web contentr~  )r  r  Nr{  r  r3   rC  )rC  r3   r  r   r  r   )r  rW  r)   r  r  rz  r  r  r  r  r  r  r  r`  r  r  r  _fuzzy_file_completions)rf  r  r  lowered_STATIC_REFSr  ro  r  barewant_dir	path_partr  r  match_prefixrn  r  r  r  r  r  r  r  
completionquerys                           r$   _context_completionsz*SlashCommandCompleter._context_completions  s0      **,,
  , 	 	OIt  ++G44 9J9Jg9U9U $'II:%!%	      - 0	 0	F#2#;Dt||tv66|!Z/"&$,,BBDV4F	7--i88 >8s??/6,J&&s++ >/7JJ!#!:!:!AcJ#%7#3#3H#=#=L j44GG   FFF +1133#G__  E# !EKKMM,D,D\,R,R !  "Z ? ?IW]]955F  6)) ~~#%7??9#=#=L$*2SSF$*K550@0K0KD$*!BL!B&!B!BJ$"(+D		z %%)	      QJEE[ ` QRR//eUCCCCCCCCCCCs   E00
E?>E?rY  c           
     B   t          j                    }t          j                    }| j        r | j        |k    r|| j        z
  dk     r| j        S g }ddd|gdd|gdddd|gfD ]'}|d	         }t          j        |          s 	 t          j
        |d
d
d|dd          }|j        d	k    r|j        r|j                                        r|j                                                            d          }|dd         D ]j}	 t           j                            |          r t           j                            ||          n|}	n# t$          $ r Y Qw xY w|                    |	           k n# t          j        t*          f$ r Y %w xY w|| _        || _        || _        |S )z9Return cached list of project files (refreshed every 5s).g      @rgz--filesz--sortr=modifiedfdz--typefz--base-directoryr   Tr  zutf-8r^  )capture_outputrw  timeoutcwdencodingerrors
Ni  )r  getcwdtime	monotonicrc  re  rd  shutilwhich
subprocessr   
returncodestdoutrV  rF  rz  r  r  r  r_  TimeoutExpiredr  )
rf  r  nowfilesr  toolprocr  pr%  s
             r$   _get_project_filesz(SlashCommandCompleter._get_project_files3  s   ikkn	$$++d++c11## 90#69c"8S"4c:
 	 	C
 q6D<%% !~4gi   ?a''DK'DK<M<M<O<O'+++--33D99C $Z 	* 	*%=?W]]1=M=M"T"'//!S"9"9"9STCC) % % %
 %H% S))))E-w7    ! #"s8   A>E-AEE-
EE-EE--FFfilepathr  c                >   |sdS t           j                            |           }|                                }|                                 }|                                }||k    rdS |                    |          rdS ||v rdS ||v rdS d}|D ]&}|t          |          k     r|||         k    r|dz  }'|t          |          k    rTd}d}d}	|D ]1}|t          |          k     r|||         k    r|	dv r|dz  }|dz  }|}	2|t          |          d	z  k    rd
S dS dS )z?Score a file path against a fuzzy query. Higher = better match.r   rv  P   ru  r  r   r\  z_-./g      ?#      )r  rz  r  r  rW  r  )
r  r  filename
lower_file
lower_pathlower_qqir?  boundary_hitsprevs
             r$   _score_pathz!SlashCommandCompleter._score_pathc  ss     	17##H--^^%%
^^%%
++--   3  )) 	2j  2j  2  	 	ACLL  Q'"+%5%5aWMBD  G$$gbk)9)9v~~%*!GBGs 222r2qrD      c           	   #    K   |                                  }|s|d|         D ]}|                    d          }t          j                            |          }|rdnd}|rdn=t          t          j                            t          j                    |                    }	t          d| d| t          |           ||	          V  dS g }
|D ]5}| 
                    ||          }|d	k    r|
                    ||f           6|
                    d
            |
d|         D ]\  }}|                    d          }t          j                            |          }|rdnd}|rdn=t          t          j                            t          j                    |                    }	t          d| d| t          |           ||	r| d|	 n|          V  dS )z-Yield fuzzy file completions for bare @query.Nr  folderfiler  r  :r~  r   c                $    | d          | d         fS )Nr   r   r0   )xs    r$   r  z?SlashCommandCompleter._fuzzy_file_completions.<locals>.<lambda>  s    AaD5!A$- rD   r  z  )r  r  r  rz  r  r  r`  r  r)   r  r  r_  sort)rf  r  r  r  r  fpr  r  kindro  scoredsr\  s                r$   r  z-SlashCommandCompleter._fuzzy_file_completions  s8     '')) 	FUFm  S))7++B//#)5xxv & uu,<GLLb11- - !#OOrOO$'II:$!%	       F  	' 	'B  U++A1uuq"g&&&//000FUF^ 	 	EAr[[%%Fw''++H%1886D" 55(8RY[["--) )D D2 #D		z 04<__d___"	      	 	rD   sub_text	sub_lowerc           
   #  4  K   	 ddl m}  |            D ]r}|d         }|                    |          rS||k    rMt          |t	          |            ||                    dd          p|                    dd                    V  sdS # t          $ r Y dS w xY w)	z1Yield completions for /skin from available skins.r   )
list_skinsr-   r.   r3   sourcer~  N)hermes_cli.skin_enginer  rW  r)   r  r  r   )r  r  r  r  r-   s        r$   _skin_completionsz'SlashCommandCompleter._skin_completions  s      	999999Z\\  y??9-- $)2C2C$(+H~ $%&UU="%=%=%TxQSATAT	        	 	 	DD	s   BB	 	
BBc           	   #  d  K   d}|                                  }|                     d          }t          |          dk    st          |          dk    rp|sn|s| nd}|D ]c}|                    |                                          r:||                                k    r"t          |t          |           |          V  ddS |d                                         }|dvrdS |rdn|d	         }|                                }t          |r
|dd         n	|dd	                   }		 dd
lm}
 ddl	m
}m}m}  |
            } ||dd          }|D ]Y\  }}}||	v s|                    |          s ||v }|dk    r|r-|dk    r|s6t          |t          |           ||          V  Zt           |                      D ]U}||	v s|                    |          s||v }|dk    r|r)|dk    r|s2t          |t          |           |d          V  V|                    d          pi }t          |t                     rXt          |          D ]J}| d}||	v s|                    |          s!t          |t          |           |d| d          V  IdS dS # t"          $ r Y dS w xY w)uh  Yield completions for /tools — subcommand + toolset/MCP-server name.

        Handles both ``/tools <tab>`` (suggesting ``list|disable|enable``) and
        ``/tools enable <tab>`` / ``/tools disable <tab>`` (suggesting toolset
        keys and MCP server prefixes, filtered by current enable state so the
        user only sees actionable options).
        )r[   disableenabler!  r   r   r3   r  r  N)r  r  r{  )load_config_readonly)CONFIGURABLE_TOOLSETS_get_platform_tools_get_plugin_toolset_keysr   F)include_default_mcp_serversr  r  r~  zplugin toolsetmcp_serversr  zMCP server '')rF  r  r  rW  r  r)   rE  r   r  hermes_cli.tools_configr  r  r  r  r  rG  rH  r   )r  r  SUBSr  trailing_spacepartialr  
subcommandpartial_loweralreadyr  r  r  r  r   enabledts_keylabel_descis_onr  serverr  s                          r$   _tools_completionsz(SlashCommandCompleter._tools_completions  s      -  !**3// u::??s5zzQ~&4<hh"G U U>>'--//22 Usgmmoo7M7M$S#g,,PSTTTTTTF1X^^%%
222F&5""E"I>BeABBiiuQrT{CC;	>>>>>>          *)++F))&%UZ[[[G(=  $uW$$F,=,=m,L,L$')))e)**5* $'LL="!&	       !!9!9!;!;<<  W$$F,=,=m,L,L$')))e)**5* $'LL="!1	       !**]339rK+t,, 
$[11 	 	F &\\\F((0A0A-0P0P( $(+G} &%=F%=%=%=	      
 
	 	  	 	 	FF	s   (E5J! !
J/.J/c              #  |  K   |                                  }|                     d          }t          |          dk    st          |          dk    r|rdS |r|rdn|d         }|                                }	 ddlm}  |            }|                                }n# t          $ r Y dS w xY w|D ]}	|	j        }
|
	                    |          s	 |
                    |	          }n# t          $ r d}Y nw xY w|rt          |dd          r
d	|j         nd
}t          |
t          |           |
|          V  dS )u_  Yield platform completions for /handoff.

        Offers connected (enabled + configured) gateway platforms. A recorded
        home channel is NOT required to list a platform — it's often learned at
        runtime — so the meta hints whether one is set yet. Completes only the
        first arg (the platform); once one is chosen, stop.
        r!  r   Nr3   r{  r   )load_gateway_configr-   u   → zsend this session herer~  )rF  r  r  r  gateway.configr  get_connected_platformsr   valuerW  get_home_channelgetattrr-   r)   )r  r  r  r  r  r  r  gwr  r  r-   homero  s                r$   _handoff_completionsz*SlashCommandCompleter._handoff_completions&  s        !**3//u::>>c%jjAoo.oF"DnD""59	::::::$$&&B2244II 	 	 	FF	! 	 	H>D??=11 **844   )-k'$2M2Mk%$)%%%SkD #G}!	      	 	s$   9$B 
B,+B,C''C65C6c           	   #    K   	 ddl m} ddlm}m} t                      }d                    |          r)d|k    r#t          dt          |            dd          V  |	                                D ]L\  }}|                    |          r2||k    r,t          |t          |            | ||                    V  MdS # t          $ r Y dS w xY w)z>Yield completions for /personality via hermes_cli.personality.r   r   )r   describe_personalityr   zclear personality overlayr~  N)r   r   r   r   r  r%   rW  r)   r  rm  r   )r  r  r   r   r  r#   r-   rS   s           r$   _personality_completionsz.SlashCommandCompleter._personality_completionsL  sU     	++++++        ;<<M  ++ )0C0C $'MM>"!<	      !. 3 3 5 5  f??9-- $)2C2C$(+H~ $%9%9&%A%A	        	 	 	DD	s   B;C 
CCc              #  
  K   |j         }|                    d          sh|                     |          }||                     |          E d {V  d S |                     |          }||                     |          E d {V  d S |                    d          }|d                                         }t          |          dk    s*t          |          dk    r~|	                    d          rht          |          dk    r|d         nd}|                                }	| 
                    |          r|                     |          E d {V  d S d|vrH|dk    r|                     ||	          E d {V  d S |dk    r|                     ||	          E d {V  d S |d	k    r|                     ||	          E d {V  d S |d
k    r|                     ||	          E d {V  d S d|vrk|t           v rb|                     |          rMt           |         D ]?}
|
                    |	          r(|
|	k    r"t%          |
t          |           |
          V  @d S |dd          }t&                                          D ]q\  }}|                     |          s|dd          }|                    |          r7t%          |                     ||          t          |           ||          V  r|                                                                 D ]\  }}|dd          }|                    |          rt/          |                    dd                    }|d d         t          |          dk    rdndz   }t          |                    dg                     }t%          |                     ||          t          |           |d| d| d          V  |                                                                 D ]\  }}|dd          }|                    |          rt/          |                    dd                    }|d d         t          |          dk    rdndz   }t%          |                     ||          t          |           |d|           V  	 ddlm}  |                                            D ]\  }}|                    |          rt/          |                    dd                    }|d d         t          |          dk    rdndz   }t%          |                     ||          t          |           d| d|           V  d S # t8          $ r Y d S w xY w)Nr  r   maxsplitr   r!  r3   z/skinz/personalityz/toolsz/handoffr  r~  r.   zSkill bundler(  r  r   u   ▣ z (z skills)r|  r}  ri  r  u   🔌 )text_before_cursorrW  r  r  r  r  rF  r  r  r  rv  r  r  r  r  r  r'  rj  r)   r%  rm  r  rq  r   r  rn  rl  rj  r   )rf  documentcomplete_eventrw  ctx_word	path_wordr  base_cmdr  r  r  r  r  r  r  r  r.   r  skill_countrj  cmd_infos                        r$   get_completionsz%SlashCommandCompleter.get_completionsp  s     *s## 
	11$77H#44X>>>>>>>>>//55I$11)<<<<<<<<<F 

A
&&8>>##u::>>c%jjAoo$--2D2Do#&u::>>uQxxrH ((I %%h// ::4@@@@@@@@@ (""w&&#55h	JJJJJJJJJF~--#<<XyQQQQQQQQQF
 8##228YGGGGGGGGG:%%44XyIIIIIIIII (""x;'>'>4CXCXYaCbCb'>&x0  C~~i00 SI5E5E(,/MM>$'     
 FABBx!)) 
	 
	IC((-- 122wH""4((  ))(D99$'II:!%	      113399;; 	 	IC122wH""4(( 	!$((=."I"IJJ("-#k:J:JR:O:OUWX
!$((8R"8"899 ))(D99$'II:!K
!K!Kk!K!K!K	      2244::<< 
	 
	IC122wH""4(( !$((=/"J"JKK("-#k:J:JR:O:OUWX
 ))(D99$'II:!4
!4!4	     	>>>>>>&9&9&;&;&A&A&C&C 	 	"(&&t,, x||M;KLLMMD!%crcs4yy2~~ee2!NJ$--h==(+D		z .H%9Z%9%9	     		 	  	 	 	DD	s   -B?U. .
U<;U<r   )rZ  r[  r\  r]  r^  r[  r   r?  )rh  r   r   r6   )r   rk  )rr  r   r   r   )rr  r   r   r6   )rw  r   )r  r   r  r   r   r   )rw  r   r   r9   )r  )r  r   r  r  r   rY  )r  r   r  r   r   r  )r  )r  r   r  r   r  r  )r  r   r  r   )r?   r@   rA   rB   rg  rj  rn  rq  staticmethodrt  rv  r  	frozensetr  r  r  r  r  r  r  r  r  r  r  r  r  r'  r0   rD   r$   rY  rY    sz       TT VZ7;TX	' ' ' ' '          A A A \AQ Q Q Q6 6 6 6x !y!A!A!ABB   \&    \B 0 0 0 0 \0d    \TD TD TD TD TDl. . . .` * * * \*X) ) ) ) )V    \  W W W \Wr # # # \#J ! ! ! \!Fr r r r rrD   rY  c                  &    e Zd ZdZ	 	 ddd	Zd
 ZdS )SlashCommandAutoSuggestzInline ghost-text suggestions for slash commands and their subcommands.

    Shows the rest of a command or subcommand in dim text as you type.
    Falls back to history-based suggestions for non-slash input.
    Nhistory_suggestAutoSuggest | None	completerSlashCommandCompleter | Noner   r?  c                "    || _         || _        d S r+  )_history
_completer)rf  r-  r/  s      r$   rg  z SlashCommandAutoSuggest.__init__  s    
 (#rD   c                V   |j         }|                    d          s$| j        r| j                            ||          S d S |                    d          }|d                                         }t          |          dk    r|                    d          s|dd                                          }t          t          t                    D ]o}| j
        | j
                            |          s$|dd          }|                    |          r,||k    r&t          |t          |          d                    c S pd S t          |          dk    r|d         nd}	|	                                }
| j
        | j
                            |          re| j
                            |          D ]J}|j        r|j        |j         d          n|j        }|                                rt          |          c S K| j
        | j
                            |          sd S |t$          v rbt$          |         rUd|	vrQt$          |         D ]C}|                    |
          r,||
k    r&t          |t          |	          d                    c S D| j        r| j                            ||          S d S )Nr  r   r  r   r!  r  r3   )r  rW  r2  get_suggestionrF  r  r  r  r  r%  r3  rj  r'   rv  r  r  rw  rV  r'  )rf  bufferr   rw  r  r$  r  r  r  r  r  r  	remainderr  s                 r$   r5  z&SlashCommandAutoSuggest.get_suggestion  s   * s## 	} F}33FHEEE4

A
&&8>>##u::??4==#5#5? 8>>##DhC000 < <?.t7W7WX[7\7\.qrr7&&t,, <T1A1A%hs4yyzz&:;;;;;4  #5zzA~~5882NN$$	 O'11(;; ( #oHHNN 1 1
!0FJOZ-F,F,G,GHH6@o ??$$ 1%i000001 ?&t/O/OPX/Y/Y&4{""{8'<"(""&x0 ? ?C~~i00 ?SI5E5E)#c(mmnn*=>>>>> = 	B=//AAAtrD   )NN)r-  r.  r/  r0  r   r?  )r?   r@   rA   rB   rg  r5  r0   rD   r$   r,  r,    sN          /326$ $ $ $ $: : : : :rD   r,  c                    	 t           j                            |           }n# t          $ r Y dS w xY w|dk     r| dS |dk     r	|dz  ddS |dk     r	|dz  dd	S |dz  dd
S )z:Return a compact human-readable file size, or '' on error.r3   i   Bi   z.0fKi   @z.1fMG)r  rz  getsizer  )rz  sizes     r$   r  r  5	  s    wt$$   rrd{{zzzk+$$$$$   +&-----()00000s   " 
00)r   r   )r   r  )r-   r   r   r  )r  r,   r   r   )r-   r9   r   r6   )r7  r9   r   r6   )r   r<  r+  )r  r,   rO  rP  r   r6   )r4   r   r   r6   r(  )r   rg  )r   rp  )rx  ry  rz  r   r   ry  )r   r~  )r   r  )r  r  r   r1   )r   r1   )r   rp  r   rp  )r  r   r   r   )rn  r  r  r<  r   r  )rv  N)r  r   r  r  r  r<  r  r  r  r  r   r  )rv  )r  r  r   r  )r  r  r  r<  r   r  )r  r<  r   r  )rK  )rL  r   r   r~  )r   r$  )rz  r   r   r   )srB   
__future__r   loggingr  rer  r  r  collections.abcr   r   dataclassesr   r   typingr   r	   r
   r   utilsr   hermes_constantsr   r   rC   r%   	getLoggerr?   r  prompt_toolkit.auto_suggestr&   r'   prompt_toolkit.completionr(   r)   ImportErrorobjectr,   r*  rG   r`  r  r  r  r  r#  r%  _cmdr8   r-   r2   _aliasr.   r&  r  r/   _catr'  r5   r[   r)  compile_PIPE_SUBS_RErM  r4   r   mgrouprF  r.  r4  r6  r9  r;  rN  rS  rX  rf  r0  rt  r  r  r  r  r}  r  r  r  r  r  r  _TG_NAME_LIMITr  r  rr  r  _clamp_telegram_namesr  r  r  r'  rD  r:  r9  rB  rH  rC  r;  rJ  rT  rW  rY  r,  r  r0   rD   r$   <module>rU     s     # " " " " "  				 				       - - - - - - - - ( ( ( ( ( ( ( ( - - - - - - - - - - - - ! ! ! ! ! ! - - - - - - 	  	 	 	 	
   8 
	8	$	$CCCCCCCC?????????   KIJJJJ	 $* * * * * * * *\ '0i555' '     |&JwJI jwP P P|& JuH)!X45J J J	|& JwF	 ,CE E E|& Jw>	  |& JxQS\  |& Jy5y  |& JvQS\=? ? ?|&" JwBINN#|&$ JxWYb(8,P P P%|&( JvG     )|&, Jw=y!# # #-|&0 Jycen%6 6 61|&4 JxPR[ H6 6 65|&8 JzPR[(M35 5 59|&> Jz  F  HQ#/_a a a?|&B Jztv+- - -C|&F JzUW`i;XZ Z ZG|&J JxZ\k(FH H HK|&N JxK_(JL L LO|&R Jv>	46K K KS|&V JwXZc ,<%' ' 'W|&\ Jy? ,>JX X X]|&` JvTV_ ,<*V V Va|&d J|=y$

T T Te|&h Jx?!z; ; ;i|&l Jy>">757 7 7m|&t JwNPY%G= = =u|&z JwXZc#'S S S{|&~ JvXZc A%F< < <|&D J{Z\e*iA%' ' 'E|&L JxY[d/1 1 1M|&P JvPR[%q%F< < <Q|&X Julnw#O O OY|&\ JyKY4*N N N]|&` JxG%' ' 'a|&d Jx:I#%H! ! !e|&l Jy  F  HQ7%' ' 'm|&r JxH&QQs|&t JyG%y: : :u|&x Jy=y -9 9 9y|&| Jx<i!# # #}|&D Jz@)LLE|&J Jx5  K|&N JwLoU#'; ; ;O|&T J Y(:2#/C C CU|&^ J}<o!# # #_|&b J{A?g/ / /c|&f JyT9J24 4 4g|&l J|QSb(92GE E Em|&r JvBFB79 9 9s|&x JyU#B%' ' 'y|&@ Jw\9J24 4 4A|&F JxR*;2
L L LG|&L JvPJ8 8 8M|&P J{X*>57 7 7Q|&V J{A?B [\ \ \W|&\ Jvln}:PR R R]|&b Jv>2 2 2c|&f J{?(ICHH5E,F,F(I(I(I+- - -g|&l Jw+_.<Z\ \ \m|&p JvC_(924 4 4q|&v JvH/(HDF F Fw|&@ JwNP`:TK K KA|&D Jz46F  E|&H JxE$#:PQ Q QI|&R JxRHGI I IS|&Z JyT4 4 4[|&^ JuVXh(HVxz z z_|&b JwF$8IUdf f fc|&f Jwj+AC C Cg|&j Jv[96 6 6k|&n Jv/1A`b b bo|&t J}MA_DF F Fu|&z J{L<UW W W{|&~ Jyc>km m m|&D JxU>R &' ' 'E|&V JxIK[  W|&Z J|=?O&( ( ([|&^ J a);= = =_|&b Jy}  @P(IEG G Gc|&h JyC$0 0 0i|&p JzG H*)+ + +q|&v Jvjlr  AK%1DF F Fw|&z JyH&*6 6 6{|&~ JyUW` j: : :|&B Jwfhn,. . .C|&F J~QSYl4 4 4G|&J JwQSYZZK|&L Jz>!# # #M|&P J{Dfl4 4 4Q|&T JzNPV ,HJ J JU|&X JvF
4 4 4Y|&\ JwDf  ]|&` JwH&2 2 2a|&d JxDf%' ' 'e|&h Jy5vv%y: : :i|&l JwZ\b') ) )m|&t JvSU[i<I I Iu|&  | | | |F    *?)>)@)@ @ @ @ @9 9 9 9         T TD T$6$6t$<$<TY!l 	T 	TF(,(8%S%Sty%S%S%SH\\\"" 35  4 4 4 4 8 8D 8#..t}bAA (TY 9___l 	8 	8F!),f,,!7DV %' & & & & > >D >'+tD,<'='=O	OO$ 		6 	6  	 	 	 	 
122 1 1D
di//C
kT^,,A 1771::++C00C *3 3 33 3 3 * *        4 2; ; ;(; ; ; 2 2     
L L L LP P P P.   :     - - - -
   &   @   L ') #!$ ;;;  <5 5 5 5% % % %P@ @ @ @
   1 1 1 1   2  = ! BJ}-- !rz(++    $ $ $ $P -  37z1 z1 z1 z1 z1B I  I  I  I  IF   <i- i- i- i-f   !rz/22 $9 & & &   & ( \ #  $b  $b  $b  c  c 	$ 	$ 	$ 	$N N N Nb5 5 5 5 56   8r r r r rI r r rrI I I I Ik I I IX1 1 1 1 1 1s   'A8 8BB