§
    ÷žyj�¤  ã                  óz  — 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mZm	Z	 ddl
mZ ddlmZmZmZmZmZmZmZ ddlmZmZ ddlmZ dd	lmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$  ej%        d
¦  «        Z&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.d'd„Z/d(d„Z0d)d„Z1e G d„ d¦  «        ¦   «         Z2 G d„ d¦  «        Z3d*d"„Z4d+d%„Z5g d&¢Z6dS ),uü  Async LSP client over stdin/stdout.

One :class:`LSPClient` corresponds to one ``(language_server, workspace_root)``
pair â€” exactly what OpenCode keys clients on, and the same shape Claude
Code uses.  The client owns a child process, drives the JSON-RPC
exchange, and exposes:

- :meth:`open_file` / :meth:`change_file` â€” text document sync
- :meth:`wait_for_diagnostics` â€” block until the server emits fresh
  diagnostics for a specific file (or a timeout fires)
- :meth:`diagnostics_for` â€” read the current per-file diagnostic store
- :meth:`shutdown` â€” graceful close + SIGTERM/SIGKILL fallback

The class is designed for async use from a single asyncio event loop.
The :class:`agent.lsp.manager.LSPService` runs an event loop in a
background thread so the synchronous file_operations layer can call
into it via :func:`agent.lsp.manager.LSPService.touch_file`.

Implementation notes:

- All per-document state lives in one :class:`_DocState` keyed by
  absolute path.  Freshness is tracked with **document versions**,
  not timestamps: every didChange bumps ``version``, and each stored
  push/pull result is tagged with the version it describes.  A
  result is fresh iff its tag >= the version being waited on, so a
  didChange implicitly invalidates everything older â€” no clearing,
  no clock comparisons, no race windows.  This is what prevents
  "ghost diagnostics": a slow server's leftovers from the previous
  edit can never masquerade as a verdict on the current content.

- Whole-document sync.  Even when the server advertises incremental
  sync, we send a single ``contentChanges`` entry replacing the
  entire document.  Pretending to be incremental while sending a
  full replacement is well-tolerated by every major server and saves
  range bookkeeping.  See OpenCode's ``client.ts:584-659`` for the
  same trick.

- The "touch-file dance": every ``open_file`` call also fires a
  ``workspace/didChangeWatchedFiles`` notification (CREATED on the
  first open, CHANGED thereafter).  Some servers (clangd, eslint)
  only re-scan when this notification fires, even though the LSP spec
  doesn't strictly require it.

- ``ContentModified`` (-32801) errors get retried with exponential
  backoff up to 3 times.  This matches Claude Code's
  ``LSPServerInstance.sendRequest``.
é    )ÚannotationsN)Ú	dataclassÚfield)ÚPath)ÚAnyÚ	AwaitableÚCallableÚDictÚListÚOptionalÚSet)ÚquoteÚunquote)Úwindows_hide_flags)ÚERROR_CONTENT_MODIFIEDÚERROR_METHOD_NOT_FOUNDÚLSPProtocolErrorÚLSPRequestErrorÚclassify_messageÚencode_messageÚmake_error_responseÚmake_notificationÚmake_requestÚmake_responseÚread_messagezagent.lsp.clientg     €F@g      @g      $@g      @g333333Ã?g      ð?é   ç      à?ÚpathÚstrÚreturnc                óè   — t           j                             | ¦  «        }t           j        dk    r0|                     dd¦  «        }|                     d¦  «        sd|z   }dt          |d¬¦  «        z   S )uÂ   Return ``file://`` URI for an absolute filesystem path.

    Mirrors Node's ``pathToFileURL`` â€” handles spaces, unicode, and
    Windows drive letters (``C:\foo`` â†’ ``file:///C:/foo``).
    Úntú\ú/úfile://z/:)Úsafe)Úosr   ÚabspathÚnameÚreplaceÚ
startswithr   )r   Úabs_paths     ú6/home/ragecks/.hermes/hermes-agent/agent/lsp/client.pyÚfile_urir.   Z   sp   € õ Œw�Š˜tÑ$Ô$€HÝ	„w�$‚€ð ×#Ò# D¨#Ñ.Ô.ˆØ×"Ò" 3Ñ'Ô'ð 	&Ø˜X‘~ˆHØ•u˜X¨DÐ1Ñ1Ô1Ñ1Ð1ó    Úuric                óR  — |                       d¦  «        s| S | t          d¦  «        d…         }t          j        dk    r>|                      d¦  «        r)t          |¦  «        dk    r|d         dk    r
|dd…         }t          j                             t          |¦  «        ¦  «        S )zInverse of :func:`file_uri`.r%   Nr"   r$   é   ú:é   )r+   Úlenr'   r)   r   Únormpathr   )r0   Úraws     r-   Úuri_to_pathr8   j   s�   € à�>Š>˜)Ñ$Ô$ð Øˆ
Ø
�c�)‰nŒnˆoˆoÔ
€CÝ	„w�$‚€˜3Ÿ>š>¨#Ñ.Ô.€µ3°s±8´8¸a²<°<ÀCÈÄFÈcÂMÀMØ�!�"�"ŒgˆÝŒ7×Ò�G C™LœLÑ)Ô)Ð)r/   ÚtextúDict[str, int]c                óÖ   — | sdddœS |                       d¬¦  «        }t          |¦  «        dz
  }|rt          |d         ¦  «        nd}|                      d¦  «        r|dz   ddœS ||dœS )zÐReturn the LSP Position at the end of ``text``.

    Used to construct a single-range "replace whole document" change
    for ``textDocument/didChange`` regardless of the server's declared
    sync mode.
    r   ©ÚlineÚ	characterF)Úkeependsr4   éÿÿÿÿ)Ú
ú)Ú
splitlinesr5   Úendswith)r9   ÚlinesÚ	last_lineÚlast_cols       r-   Ú_end_positionrH   t   sŠ   € ð ð +Ø¨Ð*Ð*Ð*Ø�OŠO UˆOÑ+Ô+€EÝ�E‘
”
˜Q‘€IØ!&Ð-�s�5˜”9‰~Œ~ˆ~¨A€Hð ‡}‚}�\Ñ"Ô"ð 7Ø! A™°AÐ6Ð6Ð6Ø¨HÐ5Ð5Ð5r/   c                  ó²   — e Zd ZU dZdZded<   dZded<    ee¬¦  «        Z	d	ed
<    ee¬¦  «        Z
d	ed<   dZded<   dZded<   dZded<   ddd„Zddd„ZdS )Ú	_DocStateu1  Everything the client tracks for one open document.

    ``version`` is the LSP document version we last sent (didOpen=0,
    each didChange +1).  It doubles as the freshness token: stored
    push/pull results are tagged with the version they describe
    (``push_version`` / ``pull_version``), and a result is *fresh*
    iff its tag has caught up to ``version``.  Bumping the version on
    didChange therefore invalidates all older results implicitly â€”
    no store-clearing, no timestamps.

    ``push_version``/``pull_version`` start at -1 = "no data yet".
    Servers that echo a document version in publishDiagnostics get
    exact tagging; those that don't are credited with the current
    version at receipt time (a push observed after we sent the
    change describes the changed content or newer).
    r   ÚintÚversionÚ r   r9   )Údefault_factoryúList[Dict[str, Any]]ÚpushÚpullr@   Úpush_versionÚpull_versionFÚboolÚ	seed_seenNúOptional[int]r    c                ó*   — | j         |€| j        n|k    S ©N)rR   rL   ©ÚselfrL   s     r-   Ú
fresh_pushz_DocState.fresh_push£   ó   € ØÔ °W°_ T¤\ \È'ÒRÐRr/   c                ó*   — | j         |€| j        n|k    S rX   )rS   rL   rY   s     r-   Ú
fresh_pullz_DocState.fresh_pull¦   r\   r/   rX   )rL   rV   r    rT   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rL   Ú__annotations__r9   r   ÚlistrP   rQ   rR   rS   rU   r[   r^   © r/   r-   rJ   rJ   ˆ   sí   € € € € € € ðð ð" €GÐÐÐÑØ€D€N€N€N�NØ!& °tÐ!<Ñ!<Ô!<€DÐ<Ð<Ð<Ñ<Ø!& °tÐ!<Ñ!<Ô!<€DÐ<Ð<Ð<Ñ<Ø€LÐÐÐÑØ€LÐÐÐÑØ€IÐÐÐÑðSð Sð Sð Sð SðSð Sð Sð Sð Sð Sð Sr/   rJ   c                  óz  — e Zd ZdZdddddœdOd„ZedPd„¦   «         ZedQd„¦   «         ZdRd„Ze	dSd„¦   «         Z
dRd„ZdRd„ZdRd„ZdRd„Ze	dTd!„¦   «         ZdRd"„ZdRd#„ZdUd'„ZdVd*„ZdWd+„ZdXd.„ZdYd1„ZdZd3„Zd[d4„Zd\d5„Zd]d6„Zd]d7„Zd]d8„Zd]d9„Zd]d:„Zd]d;„Zd^d<„Z d=d>œd_dA„Z!d`dB„Z"d`dC„Z#dDddEœdadI„Z$dbdJ„Z%ddKœdcdN„Z&dS )dÚ	LSPClientaš  Async LSP client tied to one server process and one workspace root.

    Lifecycle:

        c = LSPClient(server_id, workspace_root, command, args, init_options)
        await c.start()       # spawn + initialize
        ver = await c.open_file("/path/to/foo.py")
        await c.wait_for_diagnostics("/path/to/foo.py", ver)
        diags = c.diagnostics_for("/path/to/foo.py")
        await c.shutdown()
    NF)ÚenvÚcwdÚinitialization_optionsÚseed_diagnostics_on_first_pushÚ	server_idr   Úworkspace_rootÚcommandú	List[str]rh   úOptional[Dict[str, str]]ri   úOptional[str]rj   úOptional[Dict[str, Any]]rk   rT   r    ÚNonec               ó  — || _         || _        t          |¦  «        | _        || _        |p|| _        |pi | _        || _        d | _        d | _	        d | _
        d| _        i | _        | j        | j        | j        | j        | j        | j        dœ| _        d| j        i| _        i | _        i | _        d| _        d | _        d| _        d| _        t9          j        ¦   «         | _        d| _        t9          j        ¦   «         | _         d S )Nr   )zwindow/workDoneProgress/createzworkspace/configurationzclient/registerCapabilityzclient/unregisterCapabilityzworkspace/workspaceFolderszworkspace/diagnostic/refreshztextDocument/publishDiagnosticsÚstoppedr4   F)!rl   rm   rd   Ú_commandÚ_envÚ_cwdÚ_init_optionsÚ_seed_first_pushÚ_procÚ_stderr_taskÚ_reader_taskÚ_next_idÚ_pendingÚ_handle_work_done_createÚ_handle_workspace_configurationÚ_handle_register_capabilityÚ_handle_unregister_capabilityÚ_handle_workspace_foldersÚ_handle_diagnostic_refreshÚ_request_handlersÚ_handle_publish_diagnosticsÚ_notification_handlersÚ_docsÚ_diagnostic_registrationsÚ_stateÚ_initialize_resultÚ
_sync_kindÚ	_stoppingÚasyncioÚEventÚ_push_eventÚ_push_counterÚ_registration_event)rZ   rl   rm   rn   rh   ri   rj   rk   s           r-   Ú__init__zLSPClient.__init__»   s  € ð #ˆŒØ,ˆÔÝ˜W™œˆŒØˆŒ	ØÐ)˜>ˆŒ	Ø3Ð9°rˆÔØ >ˆÔð <@ˆŒ
Ø48ˆÔØ48ˆÔð ˆŒØ35ˆŒð
 /3Ô.KØ'+Ô'KØ)-Ô)IØ+/Ô+MØ*.Ô*HØ,0Ô,KðN
ð N
ˆÔð .¨tÔ/OðI
ˆÔ#ð ,.ˆŒ
àDFˆÔ&ð %ˆŒØ<@ˆÔØ ˆŒØ$ˆŒõ #œ=™?œ?ˆÔð
 ˆÔõ $+¤=¡?¤?ˆÔ Ð Ð r/   c                óF   — | j         dk    o| j        d uo| j        j        d u S )NÚrunning)r‹   r{   Ú
returncode©rZ   s    r-   Ú
is_runningzLSPClient.is_running   s+   € àŒ{˜iÒ'Ðd¨D¬J¸dÐ,BÐdÀtÄzÔG\Ð`dÐGdÐdr/   c                ó   — | j         S rX   )r‹   r˜   s    r-   ÚstatezLSPClient.state  s
   € àŒ{Ðr/   c              ƒ  ó  K  — | j         dv rdS d| _         	 |                      ¦   «         ƒ d{V —† |                      ¦   «         ƒ d{V —† d| _         dS # t          $ r# d| _         |                      ¦   «         ƒ d{V —† ‚ w xY w)uý   Spawn the server and complete the initialize handshake.

        Raises any exception encountered during spawn/init.  On failure
        the process is killed and the client is left in state
        ``"error"`` â€” re-call ``start()`` to retry.
        >   r–   ÚstartingNr�   r–   Úerror)r‹   Ú_spawnÚ_initializeÚ	ExceptionÚ_cleanup_processr˜   s    r-   ÚstartzLSPClient.start  s¿   è è € ð Œ;Ð1Ð1Ð1ØˆFØ ˆŒð	Ø—+’+‘-”-ÐÐÐÐÐÐÐØ×"Ò"Ñ$Ô$Ð$Ð$Ð$Ð$Ð$Ð$Ð$Ø#ˆDŒKˆKˆKøÝð 	ð 	ð 	Ø!ˆDŒKØ×'Ò'Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Øð	øøøs   –;A Á-B Úcmdc                óp   — | d         }|                      ¦   «                              d¦  «        rddg| ¢S | S )z?On Windows, wrap .cmd/.bat shims so CreateProcess can run them.r   )z.cmdz.batzcmd.exez/c)ÚlowerrD   )r¤   Úexes     r-   Ú_win_wrap_cmdzLSPClient._win_wrap_cmd  sA   € ð �!ŒfˆØ�9Š9‰;Œ;×ÒÐ 0Ñ1Ô1ð 	+Ø˜tÐ* cÐ*Ð*Øˆ
r/   c              ƒ  óÌ  K  — t          t          j        ¦  «        }| j        r|                     | j        ¦  «         | j        }t          j        dk    r|                      |¦  «        }t          ¦   «         }	 t          j        |d         g|dd …         ¢R t          j        j        t          j        j        t          j        j        || j        d|dœŽƒ d {V —†| _        n/# t           $ r"}t#          d|d         › d|› d�¦  «        |‚d }~ww xY wt          j        |                      ¦   «         ¦  «        | _        t          j        |                      ¦   «         ¦  «        | _        d S )	NÚwin32r   r4   T)ÚstdinÚstdoutÚstderrrh   ri   Ústart_new_sessionÚcreationflagszLSP server binary not found: z (ú))Údictr'   Úenvironrw   Úupdaterv   ÚsysÚplatformr¨   r   r�   Úcreate_subprocess_execÚ
subprocessÚPIPErx   r{   ÚFileNotFoundErrorr   Úcreate_taskÚ_drain_stderrr|   Ú_reader_loopr}   )rZ   rh   r¤   r¯   Úes        r-   rŸ   zLSPClient._spawn#  s‰  è è € Ý•2”:ÑÔˆØŒ9ð 	"Ø�JŠJ�t”yÑ!Ô!Ð!àŒmˆÝŒ<˜7Ò"Ð"Ø×$Ò$ SÑ)Ô)ˆCõ +Ñ,Ô,ˆð	õ  'Ô=Ø�A”ð
 à�Q�R�R”ð
 ð 
 õ Ô(Ô-ÝÔ)Ô.ÝÔ)Ô.ØØ”IØ"&Ø+ð
 ð 
 ð 
 ð 
ð 
ð 
ð 
ð 
ð 
ˆDŒJˆJøõ !ð 	ð 	ð 	Ý"Ø>°°A´Ð>Ð>¸!Ð>Ð>Ð>ñô àðøøøøð	øøøõ $Ô/°×0BÒ0BÑ0DÔ0DÑEÔEˆÔå#Ô/°×0AÒ0AÑ0CÔ0CÑDÔDˆÔÐÐs   Á8A&C Ã
DÃ)DÄDc              ƒ  óh  K  — | j         �| j         j        €d S 	 	 | j         j                             ¦   «         ƒ d {V —†}|sd S |                     dd¬¦  «                             ¦   «         }|r)t
                               d| j        |d d…         ¦  «         Œ}# t          j	        t          f$ r Y d S w xY w)NTúutf-8r*   )Úerrorsz[%s] stderr: %siè  )r{   r­   ÚreadlineÚdecodeÚrstripÚloggerÚdebugrl   r�   ÚCancelledErrorÚOSError)rZ   r=   r9   s      r-   r»   zLSPClient._drain_stderrP  sÚ   è è € ØŒ:Ð ¤Ô!2Ð!:ØˆFð		ðQØ!œZÔ.×7Ò7Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9�Øð Ø�EØ—{’{ 7°9�{Ñ=Ô=×DÒDÑFÔF�Øð QÝ—L’LÐ!2°D´NÀDÈÈ$ÈÄKÑPÔPÐPðQøõ Ô&­Ð0ð 	ð 	ð 	ØˆDˆDð	øøøs   ™'B ÁAB ÂB1Â0B1c              ƒ  ó€  K  — | j         �| j         j        €d S 	 	 t          | j         j        ¦  «        ƒ d {V —†}|€!t                               d| j        ¦  «         n�t          |¦  «        \  }}|dk    r|                      ||¦  «         nm|dk    r)t          j	        |  
                    ||¦  «        ¦  «         n>|dk    r|                      ||¦  «         n!t                               d| j        |¦  «         ŒßnO# t          $ r+}t                               d| j        |¦  «         Y d }~nd }~wt          j        t          f$ r Y nw xY wt!          | j                             ¦   «         ¦  «        D ]8}|                     ¦   «         s"|                     t          d¦  «        ¦  «         Œ9| j                             ¦   «          d S # t!          | j                             ¦   «         ¦  «        D ]8}|                     ¦   «         s"|                     t          d¦  «        ¦  «         Œ9| j                             ¦   «          w xY w)	NTz![%s] server closed stdout cleanlyÚresponseÚrequestÚnotificationz![%s] dropping invalid message: %rz&[%s] protocol error in reader loop: %szserver connection closed)r{   r¬   r   rÄ   rÅ   rl   r   Ú_dispatch_responser�   rº   Ú_dispatch_requestÚ_dispatch_notificationÚwarningr   rÆ   rÇ   rd   r   ÚvaluesÚdoneÚset_exceptionÚclear)rZ   ÚmsgÚkindÚkeyr½   Úfuts         r-   r¼   zLSPClient._reader_loop^  sk  è è € ØŒ:Ð ¤Ô!2Ð!:ØˆFð	"ð]Ý(¨¬Ô):Ñ;Ô;Ð;Ð;Ð;Ð;Ð;Ð;�Ø�;Ý—L’LÐ!DÀdÄnÑUÔUÐUØÝ,¨SÑ1Ô1‘	��cØ˜:Ò%Ð%Ø×+Ò+¨C°Ñ5Ô5Ð5Ð5Ø˜YÒ&Ð&ÝÔ'¨×(>Ò(>¸sÀCÑ(HÔ(HÑIÔIÐIÐIØ˜^Ò+Ð+Ø×/Ò/°°SÑ9Ô9Ð9Ð9å—N’NÐ#FÈÌÐX[Ñ\Ô\Ð\ð]ð øõ  ð 	Xð 	Xð 	XÝ�NŠNÐCÀTÄ^ÐUVÑWÔWÐWÐWÐWÐWÐWÐWøøøøÝÔ&­Ð0ð 	ð 	ð 	ØˆDð	øøøõ ˜DœM×0Ò0Ñ2Ô2Ñ3Ô3ð Tð T�Ø—x’x‘z”zð TØ×%Ò%Õ&6Ð7QÑ&RÔ&RÑSÔSÐSøØŒM×ÒÑ!Ô!Ð!Ð!Ð!øõ ˜DœM×0Ò0Ñ2Ô2Ñ3Ô3ð Tð T�Ø—x’x‘z”zð TØ×%Ò%Õ&6Ð7QÑ&RÔ&RÑSÔSÐSøØŒM×ÒÑ!Ô!Ð!Ð!øøøs=   ™C C: Ã9G Ã:
EÄ!D*Ä%G Ä*EÅG ÅEÅG ÇA:H=c              ƒ  óv  K  — t          | j        ¦  «        | j        t          j        ¦   «         dt          | j        ¦  «        dœg| j        ddiddddiddidœddddddd	œddd
œddddgiddddœdddgiddii ddidœddgidœdœ}t          j        |                      d|¦  «        t          ¬¦  «        ƒ d {V —†}|| _	        |  
                    |                     d¦  «        pi ¦  «        | _        |                      di ¦  «        ƒ d {V —† | j        r%|                      dd| j        i¦  «        ƒ d {V —† d S d S )NÚ	workspace©r)   r0   ÚworkDoneProgressTÚdynamicRegistrationÚrefreshSupportF)ÚconfigurationÚworkspaceFoldersÚdidChangeWatchedFilesÚdiagnostics)rÜ   ÚdidOpenÚ	didChangeÚdidSaveÚwillSaveÚwillSaveWaitUntil)rÜ   ÚrelatedDocumentSupportÚvalueSetr4   r2   )ÚrelatedInformationÚ
tagSupportÚversionSupportÚcodeDescriptionSupportÚdataSupportÚcontentFormatÚmarkdownÚ	plaintextÚlinkSupportÚ!hierarchicalDocumentSymbolSupport)ÚsynchronizationÚ
diagnosticÚpublishDiagnosticsÚhoverÚ
definitionÚ
referencesÚdocumentSymbolÚpositionEncodingszutf-16)ÚwindowrÙ   ÚtextDocumentÚgeneral)ÚrootUriÚrootPathÚ	processIdrß   ÚinitializationOptionsÚcapabilitiesÚ
initialize©Útimeoutr  Úinitializedz workspace/didChangeConfigurationÚsettings)r.   rm   r'   Úgetpidry   r�   Úwait_forÚ_send_requestÚINITIALIZE_TIMEOUTrŒ   Ú_extract_sync_kindÚgetr�   Ú_send_notification)rZ   ÚparamsÚresults      r-   r    zLSPClient._initialize{  s  è è € å Ô 3Ñ4Ô4ØÔ+Ýœ™œà$­X°dÔ6IÑ-JÔ-JÐKÐKð!ð &*Ô%7à-¨tÐ4à%)Ø(,Ø.CÀTÐ-JØ$4°eÐ#<ð	ð ð 05Ø#'Ø%)Ø#'Ø$)Ø-2ð(ð (ð 04Ø26ð#ð #ð
 /3Ø'1°A°q°6Ð&:Ø*.Ø26Ø',ð+ð +ð .°
¸KÐ/HÐIØ#0°$Ð"7Ø"$Ø'JÈDÐ&Qð/!ð !ð2 0°(°Ð<ðC"ð "ð+
ð +
ˆõZ Ô'Ø×Ò˜|¨VÑ4Ô4Ý&ð
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ˆð #)ˆÔØ×1Ò1°&·*²*¸^Ñ2LÔ2LÐ2RÐPRÑSÔSˆŒà×%Ò% m°RÑ8Ô8Ð8Ð8Ð8Ð8Ð8Ð8Ð8ØÔð 	ð ×)Ò)Ø2Ø˜TÔ/Ð0ñô ð ð ð ð ð ð ð ð ð ð		ð 	r/   r  r±   rK   c                óà   — |                       d¦  «        }t          |t          ¦  «        r|S t          |t          ¦  «        r,|                      d¦  «        }t          |t          ¦  «        r|S dS )NÚtextDocumentSyncÚchanger4   )r  Ú
isinstancerK   r±   )r  Úsyncr  s      r-   r  zLSPClient._extract_sync_kindº  sl   € à×ÒÐ 2Ñ3Ô3ˆÝ�d�CÑ Ô ð 	ØˆKÝ�d�DÑ!Ô!ð 	Ø—X’X˜hÑ'Ô'ˆFÝ˜&¥#Ñ&Ô&ð Ø�Øˆqr/   c              ƒ  óÌ  K  — | j         rdS d| _         	 | j        r‚	 t          j        |                      dd¦  «        d¬¦  «        ƒ d{V —† n"# t          j        t          t          f$ r Y nw xY w	 |                      dd¦  «        ƒ d{V —† n# t          $ r Y nw xY wd| _
        |                      ¦   «         ƒ d{V —† dS # d| _
        |                      ¦   «         ƒ d{V —† w xY w)z£Best-effort graceful shutdown.

        Sends ``shutdown`` + ``exit``, then SIGTERMs/SIGKILLs the
        process if it doesn't exit cleanly.  Idempotent.
        NTÚshutdowng       @r  Úexitru   )rŽ   r™   r�   r	  r
  ÚTimeoutErrorr   r   r  r¡   r‹   r¢   r˜   s    r-   r  zLSPClient.shutdownÅ  sP  è è € ð Œ>ð 	ØˆFØˆŒð	*ØŒð ðÝ!Ô*¨4×+=Ò+=¸jÈ$Ñ+OÔ+OÐY\Ð]Ñ]Ô]Ð]Ð]Ð]Ð]Ð]Ð]Ð]Ð]øÝÔ,­oÕ?OÐPð ð ð Ø�DðøøøðØ×1Ò1°&¸$Ñ?Ô?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ð?øÝ ð ð ð Ø�Dðøøøð $ˆDŒKØ×'Ò'Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Ð)øð $ˆDŒKØ×'Ò'Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Ð)øøøsR   ”C  œ0A ÁC  ÁA,Á)C  Á+A,Á,C  Á0B ÂC  Â
BÂC  ÂBÂC  Ã #C#c              ƒ  ó6  K  — | j         �]| j                              ¦   «         sD| j                              ¦   «          	 | j         ƒ d {V —† n# t          j        t
          f$ r Y nw xY w| j        �]| j                             ¦   «         sD| j                             ¦   «          	 | j        ƒ d {V —† n# t          j        t
          f$ r Y nw xY w| j        }d | _        |€d S |j        €µ	 | 	                    ¦   «          	 t          j
        |                     ¦   «         t          ¬¦  «        ƒ d {V —† d S # t          j        $ rG 	 |                     ¦   «          |                     ¦   «         ƒ d {V —† n# t          $ r Y nw xY wY d S Y d S w xY w# t          $ r Y d S w xY wd S )Nr  )r}   rÑ   Úcancelr�   rÆ   r¡   r|   r{   r—   Ú	terminater	  ÚwaitÚSHUTDOWN_GRACEr  ÚkillÚProcessLookupError)rZ   Úprocs     r-   r¢   zLSPClient._cleanup_processÜ  s!  è è € ØÔÐ(°Ô1B×1GÒ1GÑ1IÔ1IÐ(ØÔ×$Ò$Ñ&Ô&Ð&ðØÔ'Ð'Ð'Ð'Ð'Ð'Ð'Ð'Ð'øÝÔ*­IÐ6ð ð ð Ø�ðøøøàÔÐ(°Ô1B×1GÒ1GÑ1IÔ1IÐ(ØÔ×$Ò$Ñ&Ô&Ð&ðØÔ'Ð'Ð'Ð'Ð'Ð'Ð'Ð'Ð'øÝÔ*­IÐ6ð ð ð Ø�ðøøøàŒzˆØˆŒ
Øˆ<ØˆFØŒ?Ð"ðØ—’Ñ Ô Ð ðÝ!Ô*¨4¯9ª9©;¬;ÅÐOÑOÔOÐOÐOÐOÐOÐOÐOÐOÐOÐOøÝÔ+ð ð ð ðØŸ	š	™œ˜Ø"Ÿiši™kœkÐ)Ð)Ð)Ð)Ð)Ð)Ð)Ð)øÝ-ð ð ð Ø˜ðøøøð *Ð)Ð)à˜˜ðøøøøõ &ð ð ð Ø��ðøøøð #Ð"s}   ½A ÁA$Á#A$Â!B/ Â/CÃCÃ%F Ã:3D/ Ä/FÄ?.E.Å-FÅ.
E;Å8FÅ:E;Å;FÅ>F ÆF ÆFÆF Æ
FÆFÚmethodr  r   c           	   ƒ  ó
  K  — | j         �*| j         j        �| j         j                             ¦   «         rt          d|›d�¦  «        ‚t	          j        ¦   «         }| j        }| xj        dz  c_        |                     ¦   «         }|| j        |<   	 | j         j         	                    t          t          |||¦  «        ¦  «        ¦  «         | j         j                             ¦   «         ƒ d {V —† nP# t          t          t          f$ r6}| j                             |d ¦  «         t          d|›d|› �¦  «        |‚d }~ww xY w	 |ƒ d {V —†	 | j                             |d ¦  «         S # | j                             |d ¦  «         w xY w)Nzcannot send z: stdin closedr4   zsend failed for ú: )r{   r«   Ú
is_closingr   r�   Úget_running_loopr~   Úcreate_futurer   Úwriter   r   ÚdrainÚBrokenPipeErrorÚConnectionResetErrorrÇ   Úpop)rZ   r"  r  ÚloopÚreq_idr×   r½   s          r-   r
  zLSPClient._send_requestÿ  s�  è è € ØŒ:Ð ¤Ô!1Ð!9¸T¼ZÔ=M×=XÒ=XÑ=ZÔ=ZÐ!9Ý"Ð#J°&Ð#JÐ#JÐ#JÑKÔKÐKÝÔ'Ñ)Ô)ˆØ”ˆØˆŒ˜ÑˆŒØ"×0Ò0Ñ2Ô2ˆØ #ˆŒ�fÑð	NØŒJÔ×"Ò"¥>µ,¸vÀvÈvÑ2VÔ2VÑ#WÔ#WÑXÔXÐXØ”*Ô"×(Ò(Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*øÝÕ!5µwÐ?ð 	Nð 	Nð 	NØŒM×Ò˜f dÑ+Ô+Ð+Ý"Ð#E°fÐ#EÐ#EÀ!Ð#EÐ#EÑFÔFÈAÐMøøøøð	Nøøøð	,Ø�9�9�9�9�9�9ÐàŒM×Ò˜f dÑ+Ô+Ð+Ð+øˆDŒM×Ò˜f dÑ+Ô+Ð+Ð+øøøs%   ÂAC0 Ã0D=Ä1D8Ä8D=ÅE% Å%Fr  Úfloatc             ƒ  óR  K  — t          t          dz   ¦  «        D ]Œ}	 t          j        |                      ||¦  «        |¬¦  «        ƒ d{V —†c S # t
          $ rK}|j        t          k    r5|t          k     r*t          j        t          d|z  z  ¦  «        ƒ d{V —† Y d}~Œ„‚ d}~ww xY wdS )uê   Send a request, retrying on ``ContentModified`` (-32801).

        Other errors propagate.  The retry policy matches Claude Code's
        ``LSPServerInstance.sendRequest`` â€” 3 attempts with delays
        0.5s, 1.0s, 2.0s.
        r4   r  Nr2   )
ÚrangeÚMAX_CONTENT_MODIFIED_RETRIESr�   r	  r
  r   Úcoder   ÚsleepÚRETRY_BASE_DELAY)rZ   r"  r  r  Úattemptr½   s         r-   Ú_send_request_with_retryz"LSPClient._send_request_with_retry  så   è è € õ Õ9¸AÑ=Ñ>Ô>ð 	ð 	ˆGðÝ$Ô-¨d×.@Ò.@ÀÈÑ.PÔ.PÐZaÐbÑbÔbÐbÐbÐbÐbÐbÐbÐbÐbÐbøÝ"ð ð ð Ø”6Õ3Ò3Ð3¸ÕB^Ò8^Ð8^Ý!œ-Õ(8¸AÀ¹LÑ(IÑJÔJÐJÐJÐJÐJÐJÐJÐJØ�H�H�H�HØøøøøð	øøøð	ð 	s   �/AÁ
B$ÁA BÂBÂB$c              ƒ  ó¼  K  — | j         �*| j         j        �| j         j                             ¦   «         rd S 	 | j         j                             t	          t          ||¦  «        ¦  «        ¦  «         | j         j                             ¦   «         ƒ d {V —† d S # t          t          t          f$ r-}t                               d| j        ||¦  «         Y d }~d S d }~ww xY w)Nz[%s] notify %s failed: %s)r{   r«   r%  r(  r   r   r)  r*  r+  rÇ   rÄ   rÅ   rl   )rZ   r"  r  r½   s       r-   r  zLSPClient._send_notification"  sì   è è € ØŒ:Ð ¤Ô!1Ð!9¸T¼ZÔ=M×=XÒ=XÑ=ZÔ=ZÐ!9ØˆFð	QØŒJÔ×"Ò"¥>Õ2CÀFÈFÑ2SÔ2SÑ#TÔ#TÑUÔUÐUØ”*Ô"×(Ò(Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*øÝÕ!5µwÐ?ð 	Qð 	Qð 	QÝ�LŠLÐ4°d´nÀfÈaÑPÔPÐPÐPÐPÐPÐPÐPÐPøøøøð	Qøøøs   ·AB ÂCÂ."CÃCr.  r  c              ƒ  ój  K  — | j         �*| j         j        �| j         j                             ¦   «         rd S 	 | j         j                             t	          t          ||¦  «        ¦  «        ¦  «         | j         j                             ¦   «         ƒ d {V —† d S # t          t          t          f$ r Y d S w xY wrX   )
r{   r«   r%  r(  r   r   r)  r*  r+  rÇ   )rZ   r.  r  s      r-   Ú_send_responsezLSPClient._send_response+  s¼   è è € ØŒ:Ð ¤Ô!1Ð!9¸T¼ZÔ=M×=XÒ=XÑ=ZÔ=ZÐ!9ØˆFð	ØŒJÔ×"Ò"¥>µ-ÀÈÑ2OÔ2OÑ#PÔ#PÑQÔQÐQØ”*Ô"×(Ò(Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*øÝÕ!5µwÐ?ð 	ð 	ð 	ØˆDˆDð	øøøs   ·AB ÂB2Â1B2r3  Úmessagec           	   ƒ  ól  K  — | j         �*| j         j        �| j         j                             ¦   «         rd S 	 | j         j                             t	          t          |||¦  «        ¦  «        ¦  «         | j         j                             ¦   «         ƒ d {V —† d S # t          t          t          f$ r Y d S w xY wrX   )
r{   r«   r%  r(  r   r   r)  r*  r+  rÇ   )rZ   r.  r3  r;  s       r-   Ú_send_error_responsezLSPClient._send_error_response4  sÀ   è è € ØŒ:Ð ¤Ô!1Ð!9¸T¼ZÔ=M×=XÒ=XÑ=ZÔ=ZÐ!9ØˆFð	ØŒJÔ×"Ò"¥>Õ2EÀfÈdÐT[Ñ2\Ô2\Ñ#]Ô#]Ñ^Ô^Ð^Ø”*Ô"×(Ò(Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ð*øÝÕ!5µwÐ?ð 	ð 	ð 	ØˆDˆDð	øøøs   ·AB ÂB3Â2B3rÔ   c                óÎ  — | j                              |¦  «        }|�|                     ¦   «         rd S d|v r†|d         pi }|                     t	          t          |                     dd¦  «        ¦  «        t          |                     dd¦  «        ¦  «        |                     d¦  «        ¬¦  «        ¦  «         d S |                     |                     d¦  «        ¦  «         d S )	Nrž   r3  é ƒÿÿr;  ÚunknownÚdata)r3  r;  rA  r  )r   r  rÑ   rÒ   r   rK   r   Ú
set_result)rZ   r.  rÔ   r×   Úerrs        r-   rÌ   zLSPClient._dispatch_response=  sÝ   € ØŒm×Ò Ñ'Ô'ˆØˆ;˜#Ÿ(š(™*œ*ˆ;ØˆFØ�cˆ>ˆ>Ø�g”,Ð$ "ˆCØ×ÒÝÝ˜SŸWšW V¨VÑ4Ô4Ñ5Ô5Ý §¢¨	°9Ñ =Ô =Ñ>Ô>ØŸš ™œðñ ô ñô ð ð ð ð �NŠN˜3Ÿ7š7 8Ñ,Ô,Ñ-Ô-Ð-Ð-Ð-r/   c              ƒ  óø  K  — |                      dd¦  «        }|                      d¦  «        }| j                              |¦  «        }|€'|                      |t          d|› �¦  «        ƒ d {V —† d S 	  ||¦  «        ƒ d {V —†}nZ# t          $ rM}t
                               d| j        ||¦  «         |                      |dd|› �¦  «        ƒ d {V —† Y d }~d S d }~ww xY w|                      ||¦  «        ƒ d {V —† d S )Nr"  rM   r  zmethod not found: z"[%s] request handler %s failed: %sr?  zhandler failed: )	r  r†   r=  r   r¡   rÄ   rÏ   rl   r:  )rZ   r.  rÔ   r"  r  Úhandlerr  r½   s           r-   rÍ   zLSPClient._dispatch_requestM  sQ  è è € Ø—’˜ 2Ñ&Ô&ˆØ—’˜Ñ"Ô"ˆØÔ(×,Ò,¨VÑ4Ô4ˆØˆ?Ø×+Ò+¨FÕ4JÐLiÐagÐLiÐLiÑjÔjÐjÐjÐjÐjÐjÐjÐjØˆFð	Ø"˜7 6™?œ?Ð*Ð*Ð*Ð*Ð*Ð*ˆFˆFøÝð 	ð 	ð 	Ý�NŠNÐ?ÀÄÐQWÐYZÑ[Ô[Ð[Ø×+Ò+¨F°FÐ<RÈqÐ<RÐ<RÑSÔSÐSÐSÐSÐSÐSÐSÐSØˆFˆFˆFˆFˆFøøøøð	øøøð ×!Ò! &¨&Ñ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1Ð1Ð1Ð1s   Á2B Â
CÂACÃCc                óô   — | j                              |¦  «        }|€d S 	  ||                     d¦  «        ¦  «         d S # t          $ r-}t                               d| j        ||¦  «         Y d }~d S d }~ww xY w)Nr  z'[%s] notification handler %s failed: %s)rˆ   r  r¡   rÄ   rÅ   rl   )rZ   r"  rÔ   rE  r½   s        r-   rÎ   z LSPClient._dispatch_notification\  sœ   € ØÔ-×1Ò1°&Ñ9Ô9ˆØˆ?ØˆFð	_ØˆG�C—G’G˜HÑ%Ô%Ñ&Ô&Ð&Ð&Ð&øÝð 	_ð 	_ð 	_Ý�LŠLÐBÀDÄNÐTZÐ\]Ñ^Ô^Ð^Ð^Ð^Ð^Ð^Ð^Ð^øøøøð	_øøøs    A  Á 
A7Á
"A2Á2A7c              ƒ  ó
   K  — d S rX   re   ©rZ   r  s     r-   r€   z"LSPClient._handle_work_done_createi  ó   è è € àˆtr/   c              ƒ  ó  K  — t          |t          ¦  «        sd gS |                     d¦  «        pg }g }|D ]Í}t          |t          ¦  «        s|                     d ¦  «         Œ-|                     d¦  «        }|r| j        s|                     | j        pd ¦  «         Œh| j        }t          |¦  «                             d¦  «        D ]&}t          |t          ¦  «        r||v r	||         }Œ$d } |                     |¦  «         ŒÎ|S )NÚitemsÚsectionú.)r  r±   r  Úappendry   r   Úsplit)rZ   r  rK  ÚoutÚitemrL  ÚcurÚparts           r-   r�   z)LSPClient._handle_workspace_configurationm  s   è è € õ ˜&¥$Ñ'Ô'ð 	Ø�6ˆMØ—
’
˜7Ñ#Ô#Ð) rˆØˆØð 	ð 	ˆDÝ˜d¥DÑ)Ô)ð Ø—
’
˜4Ñ Ô Ð ØØ—h’h˜yÑ)Ô)ˆGØð  $Ô"4ð Ø—
’
˜4Ô-Ð5°Ñ6Ô6Ð6ØØÔ)ˆCÝ˜G™œ×*Ò*¨3Ñ/Ô/ð ð �Ý˜c¥4Ñ(Ô(ð ¨T°S¨[¨[Ø˜dœ)�C�Cà�CØØ�JŠJ�s‰OŒOˆOˆOØˆ
r/   c              ƒ  ó\  K  — t          |t          ¦  «        sd S |                     d¦  «        pg D ]z}t          |t          ¦  «        sŒ|                     d¦  «        }|                     d¦  «        }|dk    r2|r0|| j        t	          |¦  «        <   | j                             ¦   «          Œ{d S )NÚregistrationsr"  ÚidútextDocument/diagnostic)r  r±   r  rŠ   r   r“   Úset)rZ   r  Úregr"  Úreg_ids        r-   r‚   z%LSPClient._handle_register_capability†  s±   è è € Ý˜&¥$Ñ'Ô'ð 	Ø�4Ø—:’:˜oÑ.Ô.Ð4°"ð 	/ð 	/ˆCÝ˜c¥4Ñ(Ô(ð ØØ—W’W˜XÑ&Ô&ˆFØ—W’W˜T‘]”]ˆFØÐ2Ò2Ð2°vÐ2Ø>A�Ô.­s°6©{¬{Ñ;ØÔ(×,Ò,Ñ.Ô.Ð.øØˆtr/   c              ƒ  ó  K  — t          |t          ¦  «        sd S |                     d¦  «        pg D ]W}t          |t          ¦  «        sŒ|                     d¦  «        }|r(| j                             t          |¦  «        d ¦  «         ŒXd S )NÚunregisterationsrV  )r  r±   r  rŠ   r,  r   )rZ   r  ÚunregrZ  s       r-   rƒ   z'LSPClient._handle_unregister_capability“  s’   è è € Ý˜&¥$Ñ'Ô'ð 	Ø�4Ø—Z’ZÐ 2Ñ3Ô3Ð9°rð 	Fð 	FˆEÝ˜e¥TÑ*Ô*ð ØØ—Y’Y˜t‘_”_ˆFØð FØÔ.×2Ò2µ3°v±;´;ÀÑEÔEÐEøØˆtr/   c              ƒ  ó6   K  — dt          | j        ¦  «        dœgS )NrÙ   rÚ   )r.   rm   rH  s     r-   r„   z#LSPClient._handle_workspace_foldersž  s"   è è € Ø$­X°dÔ6IÑ-JÔ-JÐKÐKÐLÐLr/   c              ƒ  ó
   K  — d S rX   re   rH  s     r-   r…   z$LSPClient._handle_diagnostic_refresh¡  rI  r/   c                ór  — t          |t          ¦  «        sd S |                     d¦  «        }t          |t          ¦  «        sd S t	          |¦  «        }|                     d¦  «        pg }t          |t
          ¦  «        sg }|                     d¦  «        }| j                             |t          d¬¦  «        ¦  «        }| j	        r|j
        sd|_
        ||_        d S d|_
        ||_        t          |t          ¦  «        r|n|j        |_        | xj        dz  c_        | j                             ¦   «          d S )Nr0   rá   rL   r@   ©rL   Tr4   )r  r±   r  r   r8   rd   r‰   Ú
setdefaultrJ   rz   rU   rP   rK   rL   rR   r’   r‘   rX  )rZ   r  r0   r   rá   rL   Údocs          r-   r‡   z%LSPClient._handle_publish_diagnostics©  s5  € Ý˜&¥$Ñ'Ô'ð 	ØˆFØ�jŠj˜ÑÔˆÝ˜#�sÑ#Ô#ð 	ØˆFÝ˜3ÑÔˆØ—j’j Ñ/Ô/Ð5°2ˆÝ˜+¥tÑ,Ô,ð 	ØˆKØ—*’*˜YÑ'Ô'ˆàŒj×#Ò# D­)¸BÐ*?Ñ*?Ô*?Ñ@Ô@ˆØÔ ð 	¨¬ð 	ð
 !ˆCŒMØ"ˆCŒHØˆFàˆŒØˆŒõ '1°½#Ñ&>Ô&>ÐO˜7˜7ÀCÄKˆÔð 	ÐÔ˜aÑÐÔØÔ×ÒÑÔÐÐÐr/   rð   )Úlanguage_idr   rd  c          	   ƒ  óV  K  — | j         st          d¦  «        ‚t          j                             |¦  «        }	 t          |¦  «                             dd¬¦  «        }n(# t          $ r}t          d|› d|› �¦  «        |‚d}~ww xY wt          |¦  «        }| j	         
                    |¦  «        }|�š|j        dk    r�|                      d	d
|ddœgi¦  «        ƒ d{V —† |j        dz   }|j        }	| j        dk    rdddœt          |	¦  «        dœ|dœg}
nd|ig}
|                      d||dœ|
dœ¦  «        ƒ d{V —† ||_        ||_        |S |                      d	d
|ddœgi¦  «        ƒ d{V —† t!          d|¬¦  «        | j	        |<   |                      dd||d|dœi¦  «        ƒ d{V —† dS )zÃSend didOpen (first time) or didChange (subsequent) for ``path``.

        Returns the new document version number that the agent's
        ``wait_for_diagnostics`` should match against.
        zclient not runningr¿   r*   )ÚencodingrÀ   zcannot read r$  Nr   zworkspace/didChangeWatchedFilesÚchangesr2   )r0   Útyper4   r<   )r£   Úend)r1  r9   r9   ztextDocument/didChange)r0   rL   )rü   ÚcontentChanges)rL   r9   ztextDocument/didOpenrü   )r0   Ú
languageIdrL   r9   )r™   r   r'   r   r(   r   Ú	read_textrÇ   r.   r‰   r  rL   r  r9   r�   rH   rJ   )rZ   r   rd  r,   r9   r½   r0   rc  Únew_versionÚold_textÚcontent_changess              r-   Ú	open_filezLSPClient.open_fileÓ  s´  è è € ð Œð 	9Ý"Ð#7Ñ8Ô8Ð8å”7—?’? 4Ñ(Ô(ˆð	JÝ˜‘>”>×+Ò+°WÀYÐ+ÑOÔOˆDˆDøÝð 	Jð 	Jð 	JÝ"Ð#A°(Ð#AÐ#A¸aÐ#AÐ#AÑBÔBÈÐIøøøøð	Jøøøõ �xÑ Ô ˆØŒj�nŠn˜XÑ&Ô&ˆàˆ?˜sœ{¨aÒ/Ð/à×)Ò)Ø1Ø S°!Ð4Ð4Ð5Ð6ñô ð ð ð ð ð ð ð ð œ+¨™/ˆKØ”xˆHàŒ !Ò#Ð#ð /0¸aÐ%@Ð%@Ý#0°Ñ#:Ô#:ð"ð "ð !%ðð ð#��ð %+¨D >Ð"2�Ø×)Ò)Ø(à,/¸KÐ$HÐ$HØ&5ðð ñô ð ð ð ð ð ð ð ð &ˆCŒKØˆCŒHØÐð ×%Ò%Ø-Ø ¨aÐ0Ð0Ð1Ð2ñ
ô 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
õ  )°¸Ð>Ñ>Ô>ˆŒ
�8ÑØ×%Ò%Ø"àØØ"-Ø Ø ð	!ð !ðñ

ô 

ð 
	
ð 
	
ð 
	
ð 
	
ð 
	
ð 
	
ð 
	
ð ˆqs   ¹$A Á
BÁ(A>Á>Bc              ƒ  ó´   K  — | j         sdS t          j                             |¦  «        }|                      dddt          |¦  «        ii¦  «        ƒ d{V —† dS )z>Send didSave for ``path``.  Some linters re-scan only on save.NztextDocument/didSaverü   r0   )r™   r'   r   r(   r  r.   )rZ   r   r,   s      r-   Ú	save_filezLSPClient.save_file  s€   è è € àŒð 	ØˆFÝ”7—?’? 4Ñ(Ô(ˆØ×%Ò%Ø"Ø˜e¥X¨hÑ%7Ô%7Ð8Ð9ñ
ô 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
r/   c              ƒ  ó&  K  — t           j                             |¦  «        }| j                             |¦  «        }|r|j        nd}	 ddt          |¦  «        ii}|                      d|t          ¬¦  «        ƒ d{V —†}nK# t          t          t          j        f$ r,}t                               d| j        |¦  «         Y d}~dS d}~ww xY wt!          |t"          ¦  «        sdS |                     d¦  «        }t!          |t$          ¦  «        r7| j                             |t)          d¬	¦  «        ¦  «        }||_        ||_        |                     d
¦  «        }	t!          |	t"          ¦  «        r£|	                     ¦   «         D ]�\  }
}t!          |t"          ¦  «        sŒ|                     d¦  «        }t!          |t$          ¦  «        rI| j                             t1          |
¦  «        t)          d¬	¦  «        ¦  «        }||_        |j        |_        Œ�dS dS )u¥  Send ``textDocument/diagnostic`` for one file.

        Stores results into the doc's pull store, tagged with the
        document version captured at request send time.  If a didChange
        races past the in-flight request, the version bump makes the
        stored result stale automatically â€” no explicit invalidation.
        Silently no-ops on errors (server may not support the pull
        endpoint).
        r@   rü   r0   rW  r  Nz([%s] document diagnostic pull failed: %srK  ra  ÚrelatedDocuments)r'   r   r(   r‰   r  rL   r.   r7  ÚDIAGNOSTICS_REQUEST_TIMEOUTr   r   r�   r  rÄ   rÅ   rl   r  r±   rd   rb  rJ   rQ   rS   rK  r8   )rZ   r   r,   rc  Úsent_versionr  r  r½   rK  Úrelatedr0   ÚsubÚ	sub_itemsÚrels                 r-   Ú_pull_document_diagnosticsz$LSPClient._pull_document_diagnostics+  s+  è è € õ ”7—?’? 4Ñ(Ô(ˆØŒj�nŠn˜XÑ&Ô&ˆØ&)Ð1�s”{�{¨rˆð	à ­°Ñ(:Ô(:Ð ;ð&ˆFð  ×8Ò8Ø)ØÝ3ð 9ñ ô ð ð ð ð ð ð ˆFˆFøõ
  Õ!1µ7Ô3GÐHð 	ð 	ð 	Ý�LŠLÐCÀTÄ^ÐUVÑWÔWÐWØˆFˆFˆFˆFˆFøøøøð	øøøõ ˜&¥$Ñ'Ô'ð 	ØˆFØ—
’
˜7Ñ#Ô#ˆÝ�e�TÑ"Ô"ð 	,Ø”*×'Ò'¨µ)ÀBÐ2GÑ2GÔ2GÑHÔHˆCØˆCŒHØ+ˆCÔØ—*’*Ð/Ñ0Ô0ˆÝ�g�tÑ$Ô$ð 
	3Ø#ŸMšM™OœOð 	3ð 	3‘��SÝ! #¥tÑ,Ô,ð ØØŸGšG GÑ,Ô,�	Ý˜i­Ñ.Ô.ð 3Øœ*×/Ò/µ¸CÑ0@Ô0@Å)ÐTVÐBWÑBWÔBWÑXÔX�CØ(�C”Hð (+¤{�CÔ$øð
	3ð 
	3ð	3ð 	3s   Á6A? Á?CÂ!CÃCÚdocument)Úmoder  rL   r}  úOptional[float]c             ƒ  óN  K  — |�	|dk    r|}n|dk    rt           nt          }t          j        ¦   «                              ¦   «         |z   }t
          j                             |¦  «        }	 |t          j        ¦   «                              ¦   «         z
  }|dk    rdS t          j        |  	                    |¦  «        ¦  «        }	t          j        |  
                    |||¦  «        ¦  «        }
t          j        |	|
h|t          j        ¬¦  «        ƒ d{V —†\  }}|D ]}|                     ¦   «          Œ|D ]'}	 |ƒ d{V —† Œ# t          j        t          f$ r Y Œ$w xY w| j                             |¦  «        }|r|                     |¦  «        rdS |r|                     |¦  «        rdS �Œ=)uŒ  Wait for the server to publish diagnostics for ``path`` at ``version``.

        ``mode`` is ``"document"`` (5s budget, document pulls) or
        ``"full"`` (10s budget, also workspace pulls).  ``timeout``
        overrides the mode's default budget when provided â€” this is
        how the user's ``lsp.wait_timeout`` config reaches the wait
        loop (slow servers like tsserver on big projects need more
        than the 5s default).

        Returns ``True`` when *fresh* diagnostics arrived (a push at
        or after our didChange, or a pull answered after it) and
        ``False`` on timeout.  Callers must treat ``False`` as "no
        data", NOT as "no errors" â€” the diagnostic stores may still
        hold stale entries from the previous edit at that point.
        Best-effort â€” never throws if the server doesn't support pull
        diagnostics; we still get the push side.
        Nr   ÚfullTF)r  Úreturn_when)ÚDIAGNOSTICS_FULL_WAITÚDIAGNOSTICS_DOCUMENT_WAITr�   Úget_event_loopÚtimer'   r   r(   rº   r{  Ú_wait_for_fresh_pushr  ÚFIRST_COMPLETEDr  rÆ   r¡   r‰   r  r[   r^   )rZ   r   rL   r}  r  ÚbudgetÚdeadliner,   Ú	remainingÚ	pull_taskÚ	push_taskrÑ   ÚpendingÚtrc  s                  r-   Úwait_for_diagnosticszLSPClient.wait_for_diagnosticsX  sí  è è € ð2 Ð 7¨Q¢; ;ØˆFˆFà.2°fªn¨nÕ*Ð*ÕB[ˆFÝÔ)Ñ+Ô+×0Ò0Ñ2Ô2°VÑ;ˆÝ”7—?’? 4Ñ(Ô(ˆð	Ø ¥7Ô#9Ñ#;Ô#;×#@Ò#@Ñ#BÔ#BÑBˆIØ˜AŠ~ˆ~Ø�uõ  Ô+¨D×,KÒ,KÈHÑ,UÔ,UÑVÔVˆIÝÔ+¨D×,EÒ,EÀhÐPWÐYbÑ,cÔ,cÑdÔdˆIÝ")¤,Ø˜IÐ&Ø!Ý#Ô3ð#ñ #ô #ð ð ð ð ð ð ‰MˆD�'ð
 ð ð �Ø—’‘
”
�
�
Øð ð �ðØ�G�G�G�G�G�G�G�GøÝÔ.µ	Ð:ð ð ð Ø�Dðøøøð ”*—.’. Ñ*Ô*ˆCØð �s—~’~ gÑ.Ô.ð Ø�tð ð �s—~’~ gÑ.Ô.ð Ø�tñ;	s   Ä4D=Ä=EÅEc              ƒ  óô  K  — t          j        ¦   «                              ¦   «         |z   }| j        }	 | j                             |¦  «        }|ró|                     |¦  «        rÞ| j        }t          j        ¦   «                              ¦   «         t          z   }| j        |k    r�|t          j        ¦   «                              ¦   «         z
  }	|	dk    rnn| j         	                    ¦   «          	 t          j
        | j                             ¦   «         |	¬¦  «        ƒ d{V —† n# t           j        $ r Y nw xY w| j        |k    °�dS |t          j        ¦   «                              ¦   «         z
  }	|	dk    rdS | j        |k    r	| j        }�ŒT| j         	                    ¦   «          	 t          j
        | j                             ¦   «         t          |	d¦  «        ¬¦  «        ƒ d{V —† n# t           j        $ r Y �ŒÂw xY w�ŒÇ)zKWait until a fresh publishDiagnostics arrives for ``path`` at ``version``+.Tr   r  Nr   )r�   r„  r…  r’   r‰   r  r[   ÚPUSH_DEBOUNCEr‘   rÓ   r	  r  r  Úmin)
rZ   r   rL   r  r‰  Úbaselinerc  Údebounce_baselineÚdebounce_deadlinerŠ  s
             r-   r†  zLSPClient._wait_for_fresh_push™  s$  è è € åÔ)Ñ+Ô+×0Ò0Ñ2Ô2°WÑ<ˆØÔ%ˆð	Ø”*—.’. Ñ&Ô&ˆCØð �s—~’~ gÑ.Ô.ð ð
 %)Ô$6Ð!Ý$+Ô$:Ñ$<Ô$<×$AÒ$AÑ$CÔ$CÅmÑ$SÐ!ØÔ(Ð,=Ò=Ð=Ø 1µGÔ4JÑ4LÔ4L×4QÒ4QÑ4SÔ4SÑ S�IØ  A’~�~ØØÔ$×*Ò*Ñ,Ô,Ð,ðÝ%Ô.¨tÔ/?×/DÒ/DÑ/FÔ/FÐPYÐZÑZÔZÐZÐZÐZÐZÐZÐZÐZÐZøÝ"Ô/ð ð ð Ø˜ðøøøð Ô(Ð,=Ò=Ð=ð �Ø ¥7Ô#9Ñ#;Ô#;×#@Ò#@Ñ#BÔ#BÑBˆIØ˜AŠ~ˆ~Ø�ØÔ! HÒ,Ð,ð  Ô-�ÙØÔ×"Ò"Ñ$Ô$Ð$ðÝÔ& tÔ'7×'<Ò'<Ñ'>Ô'>ÍÈIÐWZÑH[ÔH[Ð\Ñ\Ô\Ð\Ð\Ð\Ð\Ð\Ð\Ð\Ð\øÝÔ'ð ð ð Ø‘ðøøøñ=	s%   Ã,3D  Ä D2Ä1D2Æ AG" Ç"G5Ç4G5)Ú
fresh_onlyr–  rO   c               ó<  — | j                              t          j                             |¦  «        ¦  «        }|€g S |rFt          |                     ¦   «         r|j        ng |                     ¦   «         r|j	        ng ¦  «        S t          |j        |j	        ¦  «        S )uX  Return current merged + deduped diagnostics for one file.

        Diagnostics from push and pull stores are concatenated and
        deduplicated by ``(severity, code, message, range)`` content
        key.  Empty list if the server hasn't published anything.

        With ``fresh_only=True``, a store only contributes when its
        version tag has caught up to the document's current version â€”
        stale leftovers from the previous edit cycle are excluded.
        This is what report paths should use: after an edit, "stale
        errors" and "no errors" must not be conflated.
        )
r‰   r  r'   r   r(   Ú_deduper[   rP   r^   rQ   )rZ   r   r–  rc  s       r-   Údiagnostics_forzLSPClient.diagnostics_for¾  s�   € ð Œj�nŠn�RœWŸ_š_¨TÑ2Ô2Ñ3Ô3ˆØˆ;ØˆIØð 	ÝØŸNšNÑ,Ô,Ð4�”�°"ØŸNšNÑ,Ô,Ð4�”�°"ñô ð õ �s”x ¤Ñ*Ô*Ð*r/   )rl   r   rm   r   rn   ro   rh   rp   ri   rq   rj   rr   rk   rT   r    rs   )r    rT   )r    r   )r    rs   )r¤   ro   r    ro   )r  r±   r    rK   )r"  r   r  r   r    r   )r"  r   r  r   r  r/  r    r   )r"  r   r  r   r    rs   )r.  r   r  r   r    rs   )r.  r   r3  rK   r;  r   r    rs   )r.  rK   rÔ   r±   r    rs   )r.  r   rÔ   r±   r    rs   )r"  r   rÔ   r±   r    rs   )r  r   r    r   )r  r   r    rs   )r   r   rd  r   r    rK   )r   r   r    rs   )
r   r   rL   rK   r}  r   r  r~  r    rT   )r   r   rL   rK   r  r/  r    rs   )r   r   r–  rT   r    rO   )'r_   r`   ra   rb   r”   Úpropertyr™   r›   r£   Ústaticmethodr¨   rŸ   r»   r¼   r    r  r  r¢   r
  r7  r  r:  r=  rÌ   rÍ   rÎ   r€   r�   r‚   rƒ   r„   r…   r‡   rp  rr  r{  r�  r†  r™  re   r/   r-   rg   rg   ª   sW  € € € € € ð
ð 
ð, )-Ø!Ø;?Ø/4ðC3ð C3ð C3ð C3ð C3ð C3ðJ ðeð eð eñ „Xðeð ðð ð ñ „Xððð ð ð ð& ðð ð ñ „\ðð+Eð +Eð +Eð +EðZð ð ð ð"ð "ð "ð "ð:=ð =ð =ð =ð~ ðð ð ñ „\ðð*ð *ð *ð *ð.ð ð ð ðF,ð ,ð ,ð ,ð&ð ð ð ð Qð Qð Qð Qðð ð ð ðð ð ð ð.ð .ð .ð .ð 2ð 2ð 2ð 2ð_ð _ð _ð _ðð ð ð ðð ð ð ð2ð ð ð ð	ð 	ð 	ð 	ðMð Mð Mð Mðð ð ð ð$ð $ð $ð $ðT @Kð Hð Hð Hð Hð Hð HðT
ð 
ð 
ð 
ð+3ð +3ð +3ð +3ðd Ø#'ð=ð =ð =ð =ð =ð =ðB#ð #ð #ð #ðJ @Eð +ð +ð +ð +ð +ð +ð +ð +r/   rg   ÚlistsrO   c                 óâ   — t          ¦   «         }g }| D ][}|D ]V}t          |t          ¦  «        sŒt          |¦  «        }||v rŒ,|                     |¦  «         |                     |¦  «         ŒWŒ\|S rX   )rX  r  r±   Ú_diagnostic_keyÚaddrN  )rœ  ÚseenrP  ÚlstÚdrÖ   s         r-   r˜  r˜  Ö  sˆ   € Ý‘U”U€DØ "€CØð ð ˆØð 	ð 	ˆAÝ˜a¥Ñ&Ô&ð ØÝ! !Ñ$Ô$ˆCØ�dˆ{ˆ{ØØ�HŠH�S‰MŒMˆMØ�JŠJ�q‰MŒMˆMˆMð	ð €Jr/   r¢  úDict[str, Any]c                óú  — |                       d¦  «        pi }|                      d¦  «        pi }|                      d¦  «        pi }|                       d¦  «        }|�$t          |t          ¦  «        st          |¦  «        }d                     t          |                       d¦  «        pd¦  «        t          |pd	¦  «        t          |                       d
¦  «        pd	¦  «        t          |                       d¦  «        pd	¦  «                             ¦   «         |                      dd¦  «        › d|                      dd¦  «        › d|                      dd¦  «        › d|                      dd¦  «        › �g¦  «        S )u  Content-equality key for a diagnostic.

    Matches the structural-equality used in claude-code's
    ``areDiagnosticsEqual`` â€” message + severity + source + code +
    range coords.  The range is reduced to a tuple to keep the key
    stable across dict orderings.
    r1  r£   ri  r3  Nú Úseverityr4   rM   Úsourcer;  r=   r   r3   r>   ú-)r  r  r   ÚjoinÚstrip)r¢  Úrngr£   ri  r3  s        r-   rž  rž  å  sV  € ð �%Š%�‰.Œ.Ð
˜B€CØ�GŠG�GÑÔÐ" €EØ
�'Š'�%‰.Œ.Ð
˜B€CØ�5Š5�‰=Œ=€DØÐ¥
¨4µÑ 5Ô 5ÐÝ�4‰yŒyˆØ�;Š;å�—’�jÑ!Ô!Ð& QÑ'Ô'Ý��
˜‰OŒOÝ�—’�h‘”Ð% 2Ñ&Ô&Ý�—’�iÑ Ô Ð& BÑ'Ô'×-Ò-Ñ/Ô/Ø�yŠy˜ Ñ#Ô#ÐpÐp e§i¢i°¸QÑ&?Ô&?ÐpÐpÀ#Ç'Â'È&ÐRSÑBTÔBTÐpÐpÐWZ×W^ÒW^Ð_jÐlmÑWnÔWnÐpÐpð	
ñô ð r/   )rg   r.   r8   r  rƒ  r‚  )r   r   r    r   )r0   r   r    r   )r9   r   r    r:   )rœ  rO   r    rO   )r¢  r£  r    r   )7rb   Ú
__future__r   r�   Úloggingr'   r´   Údataclassesr   r   Úpathlibr   Útypingr   r   r	   r
   r   r   r   Úurllib.parser   r   Úhermes_cli._subprocess_compatr   Úagent.lsp.protocolr   r   r   r   r   r   r   r   r   r   r   Ú	getLoggerrÄ   r  rƒ  r‚  ru  r‘  r  r2  r5  r.   r8   rH   rJ   rg   r˜  rž  Ú__all__re   r/   r-   ú<module>r¶     s‚  ðð.ð .ð^ #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø 
€
€
€
Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø Ð Ð Ð Ð Ð Ø FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FÐ FØ 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'à <Ð <Ð <Ð <Ð <Ð <ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð 
ˆÔ	Ð-Ñ	.Ô	.€ð Ð ØÐ ØÐ Ø!Ð Ø€Ø€ð  !Ð ØÐ ð2ð 2ð 2ð 2ð *ð *ð *ð *ð6ð 6ð 6ð 6ð( ðSð Sð Sð Sð Sñ Sô Sñ „ðSðBi+ð i+ð i+ð i+ð i+ñ i+ô i+ð i+ðXð ð ð ðð ð ð ð2ð ð €€€r/   