+
    jHàj¸   ã                   ón  a € RS tB0 t R t^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RI	H
t
 ^ RIHtHtHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHtHtHt ^ R
IHtHtHtHtHtH t H!t! ]! 4       t"R t#R R lt$]"PK                  R4      R R l4       t&Rt'Rs(] ^ k Rs)] ^k Rs*R R lt+R R lt,]"PK                  R4      RTR R ll4       t-]"PK                  R4      R R l4       t.]"PK                  R4      R R l4       t/]"PK                  R 4      R! R" l4       t0]"PK                  R#4      RUR$ R% ll4       t1]"PK                  R&4      RVR' R( ll4       t2]"PK                  R)4      R* R+ l4       t3]"PK                  R,4      R- R. l4       t4]"PK                  R/4      RWR0 R1 ll4       t5]"PK                  R24      R3 R4 l4       t6]"Po                  R54      R6 R7 l4       t8]"Po                  R84      R9 R: l4       t9]"Po                  R;4      R< R= l4       t:]"Po                  R>4      R? R@ l4       t;]"Po                  RA4      RB RC l4       t<]"Po                  RD4      RE RF l4       t=]"Po                  RG4      RH RI l4       t>]"Po                  RJ4      RK RL l4       t?]"Po                  RM4      RN RO l4       t@]"Po                  RP4      RQ RR l4       tAR# )Xuj  Git dashboard routes â€” the remote half of the desktop coding rail + review pane.

The desktop runs these as Electron-local git; over a remote gateway that's the wrong
filesystem, so they are mirrored here with the same auth gate + path hardening as
/api/fs. Logic lives in ``hermes_cli.web_git``; these are thin executor-offloaded
wrappers (git/gh can block).
N)Úpartial)ÚPath)ÚOptional)Ú	APIRouterÚHTTPExceptionÚRequest)Úweb_git)Úbounded_probe_run)Úlate)Ú_fs_pathÚ_hosted_fs_path_allowedÚ_hosted_fs_read_guard)ÚGitBranchSwitchBodyÚGitCommitBodyÚGitFileBodyÚGitPathBodyÚGitPrListBodyÚGitWorktreeAddBodyÚGitWorktreeRemoveBodyc              ‡  óÚ   "  € \         P                  ! 4       p VP                  ! RV .VO5!  G Rj  x€L
 #  L  \         d&   p\	        R\        T4      ;'       g    RR7      hRp?ii ; i5i)zIRun a (blocking) git op off the event loop; map a failed mutation to 400.Ni�  zgit operation failed)Ústatus_codeÚdetail)ÚasyncioÚget_running_loopÚrun_in_executorÚRuntimeErrorr   Ústr)ÚfnÚargsÚloopÚexcs   &*  Ú?/home/ubuntu/.hermes/hermes-agent/hermes_cli/web_routers/git.pyÚ_git_opr"   %   sb   é € ä×#Ò#Ó%€DðXØ×)Ò)¨$°Ð:°TÓ:×:Ð:Ñ:øÜô XÜ¨´C¸³H×4VÐ4VÐ@VÔWÐWûðXüs1   ‚A+™8 ±6²8 µA+¶8 ¸A(Á A#Á#A(Á(A+c                ó0   € V ^8„  d   QhR\         R\         /# )é   ÚpathÚreturn©r   )Úformats   "r!   Ú__annotate__r)   .   s   € ÷ ñ ”Cð œCñ ó    c                 ó*   € \        \        V 4      4      # ©N)r   r   ©r%   s   &r!   Ú	_git_pathr.   .   s   € ÜŒx˜‹~ÓÐr*   z/api/git/statusc                ó$   € V ^8„  d   QhR\         /# ©r$   r%   r'   )r(   s   "r!   r)   r)   3   s   € ÷ @ñ @¤ñ @r*   c              ƒ   ód   "  € \        \        P                  \        V 4      4      G R j  x€L
 #  L5ir,   )r"   Ú_web_gitÚrepo_statusr.   r-   s   &r!   Úgit_status_router4   2   s"   é € äœ×-Ñ-¬y¸«Ó?×?Ð?Ñ?ùó   ‚'0©.ª0g     Àr@g        c                ó$   € V ^8„  d   QhR\         /# )r$   r&   )Údict)r(   s   "r!   r)   r)   A   s   € ÷ 	;ñ 	;œñ 	;r*   c                  óæ   € \         P                  ! R 4      p V '       g   RRRR/#  \        V RR.^
R7      pRRR\        T;'       d    VP                  ^ 8H  4      /#   \
         d
    RRRR/u # i ; i)ÚghÚ	availableFÚauthenticatedÚauthÚstatus)ÚtimeoutT)ÚshutilÚwhichr	   ÚboolÚ
returncodeÚ	Exception)r9   Úprocs     r!   Ú_probe_gh_authrE   A   s~   € Ü	�Š�dÓ	€BßØ˜U O°UÐ;Ð;ð;ä  " f¨hÐ!7ÀÔDˆØ˜T ?´D¸×9VÐ9VÀ$Ç/Á/ÐUVÑBVÓ4WÐXÐXøÜô ;Ø˜T ?°EÐ:Ò:ð;ús   ¦ A ÁA ÁA0Á/A0c                ó<   € V ^8„  d   QhR\         P                  RR/# )r$   Úcompleted_taskr&   N)r   ÚTask)r(   s   "r!   r)   r)   M   s   € ÷ #ñ #¬g¯l©lð #¸tñ #r*   c                ó"   € \         V J d   Rs R# R# )zERelease a completed shared probe even if all requesters disconnected.N)Ú_gh_auth_probe_task)rG   s   &r!   Ú_clear_gh_auth_probe_taskrK   M   s   € ô ˜nÓ,Ø"Òñ -r*   z/api/git/gh-authc                ó$   € V ^8„  d   QhR\         /# )r$   Úrefresh)rA   )r(   s   "r!   r)   r)   U   s   € ÷ ñ ¬ñ r*   c              ƒ  óX  "  € \         P                  ! 4       pV '       g7   \        '       d+   V\        ^ ,          ,
          \        8  d   \        ^,          #  \        e   \        P                  4       '       d]   \        P                  ! \        P                  ! \        4      4      s\         P                  ! 4       s
\        P                  \        4       \        \        r2\        P                  ! V4      G Rj  x€L
 pV '       d	   W18¼  g   K¸   \         P                  ! 4       T3sT#  L.5i)zˆ``{"available", "authenticated"}`` for the `gh` CLI; cached 5 min
(``refresh=true`` bypasses so the pill withdraws right after a login).N)ÚtimeÚ	monotonicÚ_gh_auth_cacheÚ_GH_AUTH_TTL_SrJ   Údoner   Úcreate_taskÚ	to_threadrE   Ú_gh_auth_probe_startedÚadd_done_callbackrK   Úshield)rM   ÚaskedÚ
probe_taskÚstartedÚpayloads   &    r!   Úgh_auth_status_router]   T   sÉ   é € ô
 �NŠNÓ€Eß—~“~¨%´.ÀÕ2CÕ*CÄnÔ*TÜ˜aÕ Ð Ø
ÜÒ&Ô*=×*BÑ*B×*DÒ*DÜ")×"5Ò"5´g×6GÒ6GÌÓ6WÓ"XÐÜ%)§^¢^Ó%5Ð"Ü×1Ñ1Ô2KÔLÜ1Ô3I�Gô  Ÿš zÓ2×2ˆ÷ ˜'Ö*ØÜ—n’nÓ&¨Ð0€NØ€Nñ 3ùs*   ‚)D*¬AD*Á9B D*Ã9D(Ã:D*ÄD*ÄD*z/api/git/worktreesc                ó$   € V ^8„  d   QhR\         /# r0   r'   )r(   s   "r!   r)   r)   o   s   € ÷ Qñ Q¤Cñ Qr*   c              ƒ   óh   "  € R \        \        P                  \        V 4      4      G Rj  x€L
 /#  L5i)Ú	worktreesN)r"   r2   Úworktree_listr.   r-   s   &r!   Úgit_worktrees_routerb   n   s'   é € àœw¤x×'=Ñ'=¼yÈ»ÓO×OÐPÐPÑOùó   ‚(2ª0«2z/api/git/branchesc                ó$   € V ^8„  d   QhR\         /# r0   r'   )r(   s   "r!   r)   r)   t   s   € ÷ Nñ N¤3ñ Nr*   c              ƒ   óh   "  € R \        \        P                  \        V 4      4      G Rj  x€L
 /#  L5i©ÚbranchesN)r"   r2   Úbranch_listr.   r-   s   &r!   Úgit_branches_routeri   s   s'   é € àœg¤h×&:Ñ&:¼IÀd»OÓL×LÐMÐMÑLùrc   z/api/git/base-branchesc                ó$   € V ^8„  d   QhR\         /# r0   r'   )r(   s   "r!   r)   r)   y   s   € ÷ Sñ S¬ñ Sr*   c              ƒ   óh   "  € R \        \        P                  \        V 4      4      G Rj  x€L
 /#  L5irf   )r"   r2   Úbase_branch_listr.   r-   s   &r!   Úgit_base_branches_routerm   x   s'   é € àœg¤h×&?Ñ&?ÄÈ4ÃÓQ×QÐRÐRÑQùrc   z/api/git/review/listc                óR   € V ^8„  d   QhR\         R\         R\        \         ,          /# )r$   r%   ÚscopeÚbase©r   r   )r(   s   "r!   r)   r)   ~   s+   € ÷ Mñ M¤cð M´#ð MÌXÔVYÍ]ñ Mr*   c              ƒ   óf   "  € \        \        P                  \        V 4      W4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_listr.   )r%   ro   rp   s   &&&r!   Úgit_review_list_routert   }   s$   é € äœ×-Ñ-¬y¸«ÀÓL×LÐLÑLùs   ‚(1ª/«1z/api/git/review/diffc                óv   € V ^8„  d   QhR\         R\         R\        R\         R\        \         ,          R\        /# )r$   r%   ÚfileÚrequestro   rp   Ústaged)r   r   r   rA   )r(   s   "r!   r)   r)   ƒ   sH   € ÷ `ñ `Ü
ð`Üð`Ü#*ð`äð`ä&.¬s¥mð`äDHñ`r*   c           	   ƒ   ó²   "  € \        V 4      p\        WR 7      p\        Wr4       R\        \        P
                  V\        V4      W4V4      G Rj  x€L
 /#  L5i©)ÚcwdÚdiffN)r.   r   r   r"   r2   Úreview_diffr   )r%   rv   rw   ro   rp   rx   r{   Útargets   &&&&&&  r!   Úgit_review_diff_router   ‚   sK   é € ô
 �D‹/€CÜ�dÔ$€FÜ˜&Ô*Øœ'¤(×"6Ñ"6¸¼SÀ»[È%ÐW]Ó^×^Ð_Ð_Ñ^ùs   ‚AAÁAÁAz/api/git/file-diffc                ó<   € V ^8„  d   QhR\         R\         R\        /# )r$   r%   rv   rw   ©r   r   )r(   s   "r!   r)   r)   Ž   s&   € ÷ Qñ Q¤Cð Q¬sð Q¼Wñ Qr*   c              ƒ   ó®   "  € \        V 4      p\        WR 7      p\        WB4       R\        \        P
                  V\        V4      4      G Rj  x€L
 /#  L5irz   )r.   r   r   r"   r2   Úfile_diff_vs_headr   )r%   rv   rw   r{   r~   s   &&&  r!   Úgit_file_diff_router„   �   sD   é € ä
�D‹/€CÜ�dÔ$€FÜ˜&Ô*Øœ'¤(×"<Ñ"<¸cÄ3ÀvÃ;ÓO×OÐPÐPÑOùs   ‚AAÁAÁAz/api/git/review/commit-contextc                ó0   € V ^8„  d   QhR\         R\        /# )r$   r%   rw   r�   )r(   s   "r!   r)   r)   –   s   € ÷ Gñ G¬ð G´wñ Gr*   c              ƒ   ó¾   "  € \        V 4      p\        \        V4      V4      pVe   \        \        V4      MR p\        \        P                  W$4      G R j  x€L
 #  L5ir,   )r.   r   r   r   r   r"   r2   Úreview_commit_context)r%   rw   r{   ÚrootÚalloweds   &&   r!   Úgit_commit_context_routerŠ   •   sK   é € ä
�D‹/€CÜ ¤ c£¨GÓ4€DØ8<Ò8HŒgÔ-¨tÔ4Èd€GÜœ×7Ñ7¸ÓF×FÐFÑFùs   ‚AAÁAÁAz/api/git/review/rev-parsec                óF   € V ^8„  d   QhR\         R\        \         ,          /# )r$   r%   Úrefrq   )r(   s   "r!   r)   r)   ž   s"   € ÷ Sñ S¤Cð S¬h´s­mñ Sr*   c              ƒ   ój   "  € R \        \        P                  \        V 4      V4      G Rj  x€L
 /#  L5i)ÚshaN)r"   r2   Úreview_rev_parser.   )r%   rŒ   s   &&r!   Úgit_rev_parse_router�   �   s)   é € àœ¤×!:Ñ!:¼IÀd»OÈSÓQ×QÐRÐRÑQùs   ‚)3«1¬3z/api/git/review/ship-infoc                ó$   € V ^8„  d   QhR\         /# r0   r'   )r(   s   "r!   r)   r)   £   s   € ÷ Eñ E¤Cñ Er*   c              ƒ   ód   "  € \        \        P                  \        V 4      4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_ship_infor.   r-   s   &r!   Úgit_ship_info_router”   ¢   s"   é € äœ×2Ñ2´I¸d³OÓD×DÐDÑDùr5   z/api/git/review/pr-listc                ó$   € V ^8„  d   QhR\         /# ©r$   Úbody)r   )r(   s   "r!   r)   r)   ¨   s   € ÷ eñ e¤-ñ er*   c              ƒ   ó¤   "  € \        \        P                  \        V P                  4      V P
                  V P                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_pr_listr.   r%   rg   Únumbers©r—   s   &r!   Úgit_pr_list_routerœ   §   s6   é € äœ×0Ñ0´)¸D¿I¹IÓ2FÈÏÉÐW[×WcÑWcÓd×dÐdÑdùó   ‚AAÁ	AÁ
Az/api/git/review/stagec                ó$   € V ^8„  d   QhR\         /# r–   ©r   )r(   s   "r!   r)   r)   ­   s   € ÷ Qñ Q¤ñ Qr*   c              ƒ   óŽ   "  € \        \        P                  \        V P                  4      V P
                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_stager.   r%   rv   r›   s   &r!   Úgit_stage_router¢   ¬   s-   é € äœ×.Ñ.´	¸$¿)¹)Ó0DÀdÇiÁiÓP×PÐPÑPùó   ‚<A¾A¿Az/api/git/review/unstagec                ó$   € V ^8„  d   QhR\         /# r–   rŸ   )r(   s   "r!   r)   r)   ²   s   € ÷ Sñ S¤+ñ Sr*   c              ƒ   óŽ   "  € \        \        P                  \        V P                  4      V P
                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_unstager.   r%   rv   r›   s   &r!   Úgit_unstage_router§   ±   s-   é € äœ×0Ñ0´)¸D¿I¹IÓ2FÈÏ	É	ÓR×RÐRÑRùr£   z/api/git/review/revertc                ó$   € V ^8„  d   QhR\         /# r–   rŸ   )r(   s   "r!   r)   r)   ·   s   € ÷ Rñ R¤ñ Rr*   c              ƒ   óŽ   "  € \        \        P                  \        V P                  4      V P
                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_revertr.   r%   rv   r›   s   &r!   Úgit_revert_router«   ¶   s-   é € äœ×/Ñ/´¸4¿9¹9Ó1EÀtÇyÁyÓQ×QÐQÑQùr£   z/api/git/review/commitc                ó$   € V ^8„  d   QhR\         /# r–   )r   )r(   s   "r!   r)   r)   ¼   s   € ÷ `ñ `¤ñ `r*   c              ƒ   ó¤   "  € \        \        P                  \        V P                  4      V P
                  V P                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_commitr.   r%   ÚmessageÚpushr›   s   &r!   Úgit_commit_router±   »   s6   é € äœ×/Ñ/´¸4¿9¹9Ó1EÀtÇ|Á|ÐUY×U^ÑU^Ó_×_Ð_Ñ_ùr�   z/api/git/review/pushc                ó$   € V ^8„  d   QhR\         /# r–   ©r   )r(   s   "r!   r)   r)   Á   s   € ÷ Eñ Eœ{ñ Er*   c              ƒ   óx   "  € \        \        P                  \        V P                  4      4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_pushr.   r%   r›   s   &r!   Úgit_push_router¶   À   s'   é € äœ×-Ñ-¬y¸¿¹Ó/CÓD×DÐDÑDùó   ‚1:³8´:z/api/git/review/create-prc                ó$   € V ^8„  d   QhR\         /# r–   r³   )r(   s   "r!   r)   r)   Æ   s   € ÷ Jñ J¤Kñ Jr*   c              ƒ   óx   "  € \        \        P                  \        V P                  4      4      G R j  x€L
 #  L5ir,   )r"   r2   Úreview_create_prr.   r%   r›   s   &r!   Úgit_create_pr_router»   Å   s'   é € äœ×2Ñ2´I¸d¿i¹iÓ4HÓI×IÐIÑIùr·   z/api/git/worktree/addc                ó$   € V ^8„  d   QhR\         /# r–   )r   )r(   s   "r!   r)   r)   Ë   s   € ÷ Oñ OÔ'9ñ Or*   c              ƒ   ó  "  € V P                  0 RmR7      P                  4        UUu/ uF  w  rV'       g   K  WbK  	  ppp\        \        P                  \        V P                  4      V4      G Rj  x€L
 # u uppi  L
5i)Úname)ÚincludeN>   rp   r¾   ÚbranchÚexistingBranch)Ú
model_dumpÚitemsr"   r2   Úworktree_addr.   r%   )r—   ÚkeyÚvalueÚoptionss   &   r!   Úgit_worktree_add_routerÈ   Ê   ss   é € ð Ÿ/™/Ò2^˜/Ó_×eÑeÔgôág‰JˆCÜô 	ˆŠ
Ùgð ñ ô
 œ×.Ñ.´	¸$¿)¹)Ó0DÀgÓN×NÐNùóñ
 Oùs    ‚&B ¨A8¹A8¿4B Á3A>Á4B z/api/git/worktree/removec                ó$   € V ^8„  d   QhR\         /# r–   )r   )r(   s   "r!   r)   r)   Õ   s   € ÷ ñ Ô*?ñ r*   c              ƒ   ó¶   "  € \        \        P                  \        V P                  4      \        V P
                  4      V P                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úworktree_remover.   r%   ÚworktreePathÚforcer›   s   &r!   Úgit_worktree_remove_routerÎ   Ô   sF   é € äÜ× Ñ ¤)¨D¯I©IÓ"6¼	À$×BSÑBSÓ8TÐVZ×V`ÑV`ó÷ ð ñ ùs   ‚AAÁAÁAz/api/git/branch/switchc                ó$   € V ^8„  d   QhR\         /# r–   )r   )r(   s   "r!   r)   r)   Ü   s   € ÷ Tñ TÔ(;ñ Tr*   c              ƒ   óŽ   "  € \        \        P                  \        V P                  4      V P
                  4      G R j  x€L
 #  L5ir,   )r"   r2   Úbranch_switchr.   r%   rÀ   r›   s   &r!   Úgit_branch_switch_routerÒ   Û   s-   é € äœ×/Ñ/´¸4¿9¹9Ó1EÀtÇ{Á{ÓS×SÐSÑSùr£   c                ó¨   € V ^8„  d   Qh/ ^ \         9   d   \        \        ,          ;R&   ^\         9   d   \        \        P                  ,          ;R&   # )r$   rQ   rJ   )Ú__conditional_annotations__r   Útupler   rH   )r(   s   "r!   r)   r)      sA   € ÷ ñ ÷v 'Ò &”œ•Ñ &ñw÷x 3Ò 2”XœgŸl™lÕ+Ñ 2òyr*   )F)ÚuncommittedN)rÖ   NFr,   )CrÔ   Ú__doc__r   r?   rO   Ú	functoolsr   Úpathlibr   Útypingr   Úfastapir   r   r   Ú
hermes_clir   r2   Úhermes_cli._subprocess_compatr	   Úhermes_cli.web_depsr
   Úhermes_cli.web_server_filesr   r   r   Úhermes_cli.web_modelsr   r   r   r   r   r   r   Úrouterr"   r.   Úgetr4   rR   rQ   rJ   rV   rE   rK   r]   rb   ri   rm   rt   r   r„   rŠ   r�   r”   Úpostrœ   r¢   r§   r«   r±   r¶   r»   rÈ   rÎ   rÒ   r)   )rÔ   s   @r!   Ú<module>rä      s  øðöó Û Û Ý Ý Ý ç 5Ñ 5å *Ý ;Ý $ß `Ñ `÷÷ ñ ñ 
‹€ò
Xõð ‡�ÐÓô@ó ð@ð €Ø"&€Ó &Ø.2Ð Ó 2ØÐ õ	;õ#ð ‡�ÐÓöó  ðð2 ‡�Ð Ó!ôQó "ðQð ‡�ÐÓ ôNó !ðNð ‡�Ð$Ó%ôSó &ðSð ‡�Ð"Ó#öMó $ðMð ‡�Ð"Ó#ö`ó $ð`ð ‡�Ð Ó!ôQó "ðQð ‡�Ð,Ó-ôGó .ðGð ‡�Ð'Ó(öSó )ðSð ‡�Ð'Ó(ôEó )ðEð ‡�Ð&Ó'ôeó (ðeð ‡�Ð$Ó%ôQó &ðQð ‡�Ð&Ó'ôSó (ðSð ‡�Ð%Ó&ôRó 'ðRð ‡�Ð%Ó&ô`ó 'ð`ð ‡�Ð#Ó$ôEó %ðEð ‡�Ð(Ó)ôJó *ðJð ‡�Ð$Ó%ôOó &ðOð ‡�Ð'Ó(ôó )ðð ‡�Ð%Ó&ôTó 'òTr*   