
    Pmj                         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 ddl	m
Z
  ej        e          Z ee          j        dz  ZdZddZeZddZdddZdS )u  
Resolve where the Photon sidecar runs from and where its Node deps live.

The sidecar source ships inside the installed plugin tree
(``plugins/platforms/photon/sidecar/``). On dev/source installs that tree is
writable and everything — ``npm ci``, the spectrum patch, the sidecar itself —
happens in place. Hosted/managed images instead keep the whole install tree
under an immutable ``/opt/hermes`` (read-only for the hermes user), which
broke every install/self-heal path with EROFS (NS-606).

Resolution order (mirrors ``resolve_whatsapp_bridge_dir`` for the Baileys
bridge, which hit the same wall):

1. ``PHOTON_SIDECAR_DIR`` env override — operator escape hatch, used as-is.
2. Source dir writable → run in place (dev installs, unchanged behavior).
3. Source dir read-only but ``node_modules`` is baked and current → run in
   place. This is the managed-image happy path: the Dockerfile bakes the
   sidecar deps with ``npm ci`` at build time (deterministic installs,
   NS-559), so no runtime install is ever needed.
4. Source dir read-only and deps missing or stale → mirror the sidecar
   source files to ``$HERMES_HOME/photon/sidecar`` (the durable data volume,
   e.g. ``/opt/data`` on hosted) and return that. The caller's normal
   install/self-heal machinery then works there because it is writable.

The mirror is refreshed on every resolve: when an image update changes a
sidecar source file, the changed file is re-copied (content compare, not
mtime) while ``node_modules`` is left in place — the adapter's existing
lockfile-vs-install-marker staleness check then triggers the ``npm ci``
self-heal inside the mirror.

This module is import-light on purpose: both ``adapter.py`` (gateway) and
``cli.py`` (``hermes photon ...``) use it.
    )annotationsN)Path)Optionalsidecar)z	index.mjszpackage.jsonpackage-lock.jsonz$patch-spectrum-mixed-attachments.mjspathr   returnboolc                    | dz  }	 |                                  |                                 dS # t          $ r Y dS w xY w)zTrue when we can create files in ``path`` (probe-based, not stat).

    A stat-mode check lies on containers (root-squash, read-only bind
    mounts), so probe with a real create+unlink like the WhatsApp bridge
    resolver does.
    z.hermes-write-probeTF)touchunlinkOSError)r   probes     L/home/thesage/.hermes/hermes-agent/plugins/platforms/photon/sidecar_paths.pydir_writabler   ;   sU     ((Et   uus   (1 
??sidecar_dirc                    | dz  }| dz  dz  }	 |                                 j        |                                 j        k    S # t          $ r Y dS w xY w)u@  True when the committed lockfile postdates npm's install marker.

    Same signal as ``adapter._sidecar_deps_stale`` — duplicated here (three
    lines) rather than imported so this module stays import-light for the
    CLI. Returns False on any stat failure so an odd filesystem never forces
    the mirror path.
    r   node_modulesz.package-lock.jsonF)statst_mtimer   )r   lockfilemarkers      r   _lock_newer_than_installr   O   sg     00H>),@@F}}'&++--*@@@   uus   3A 
AA
source_dirOptional[Path]c                   | t          |           nt          }t          j        d          }|rt          |          S t	          |          r|S |dz                                  rt          |          s|S ddlm}  |            dz  dz  }	 |	                    dd	           t          D ]}||z  }|                                s||z  }|                                r1t          j        t          |          t          |          d
          s/t          j        t          |          t          |                     |S # t           $ r(}t"                              d||           |cY d}~S d}~ww xY w)zReturn the directory the sidecar should run from (see module doc).

    ``source_dir`` defaults to the installed plugin tree; tests and callers
    that monkeypatch the adapter's ``_SIDECAR_DIR`` pass it through so the
    override keeps working.
    NPHOTON_SIDECAR_DIRr   r   )get_hermes_homephotonr   T)parentsexist_okF)shallowu   [photon] install tree is read-only and mirroring the sidecar to %s failed (%s) — falling back to the read-only source dir; dependency installs will not be possible)r   SOURCE_SIDECAR_DIRosgetenv_dir_writableexistsr   hermes_constantsr   mkdir_MIRROR_FILESfilecmpcmpstrshutilcopy2r   loggerwarning)	r   sourceoverrider   mirrornamesrcdstexcs	            r   resolve_sidecar_dirr9   _   s    ",!7T*=OFy-..H H~~V 
 	'')) 2J62R2R 
 100000_)I5FTD111! 	1 	1D4-C::<< 4-C::<< 1w{3s88SXXu'U'U'U 1SXXs3xx000   7 	
 	
 	
 s   B5E 
E6E1+E61E6)r   r   r	   r
   )r   r   r	   r
   )N)r   r   r	   r   )__doc__
__future__r   r+   loggingr$   r.   pathlibr   typingr   	getLogger__name__r0   __file__parentr#   r*   r   r&   r   r9        r   <module>rE      s      D # " " " " "   				             		8	$	$T(^^*Y6 
   "     . . . . . . .rD   