Communitygithub.com

shenmituzi/img-share

DSH 스킬: 브라우저 스크린샷/로컬 이미지를 채팅에 썸네일+원본 이미지로 공유하며, 모바일에서도 접근 가능합니다.

img-share란 무엇인가요?

이 스킬은 AI 에이전트가 브라우저 스크린샷이나 로컬 이미지를 채팅 인터페이스 내에서 클릭 가능한 큰 이미지(썸네일 + 원본)로 변환하여 공유할 수 있게 해줍니다. 특히 모바일 기기나 다른 장치에서도 접근할 수 있도록 설계되었습니다. 주요 기능으로는 `web-access` 스킬을 통한 CDP 기반 브라우저 스크린샷, `cloudflared`를 활용한 퍼블릭 터널링, 그리고 다중 이미지 그리드 합성을 위한 선택적 `ffmpeg` 지원이 포함됩니다. 가장 중요한 점은 이미지 URL이 호스트 주소를 따라야 한다는 것입니다. 에이전트는 먼저 호스트가 이미 공용 인터넷에 노출되어 있고 정적 이미지 경로를 제공하는지 확인한 후, 그렇지 않은 경우에만 명시적인 터널을 열어야 합니다. 이 스킬은 Linux, macOS, WSL, Windows 네이티브 환경에서 모두 동작하며, 공유 직후 터널을 자동으로 정리하여 보안을 강화합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add shenmituzi/img-share

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

img-share Skill

브라우저 스크린샷 또는 로컬 이미지를 채팅창 내에서 클릭 가능한 큰 이미지(썸네일 + 원본 보기)로 만들고, 휴대폰/다른 기기에서도 접근할 수 있게 합니다. Linux, macOS, WSL, Windows 네이티브 등 모든 플랫폼에서 사용 가능합니다.

whenToUse (언제 트리거되는가)

  • 사용자가 "어떤 웹사이트/페이지를 캡처해서 보여달라"고 요청할 때;
  • 어떤 이미지를 채팅창에 붙여넣고 "휴대폰에서도 보고 확대해서 세부 내용을 볼 수 있게" 하고 싶을 때;
  • 작업 공간의 이미지를 클릭 가능한 큰 이미지가 포함된 채팅 내장 이미지로 만들고 싶을 때.

의존성

의존성용도설치 방법
web-access skill스크린샷 (CDP 기반 브라우저 제어)설치 필요: https://github.com/eze-is/web-access
python3/python오케스트레이터 (serve.py)시스템 기본 제공
cloudflared공용 터널 폴백mac: brew install cloudflared; win: winget install Cloudflare.cloudflared; linux: 공식 README 참조; 또는 CLOUDFLARED=/경로 설정
ffmpeg (선택 사항)여러 이미지를 그리드로 합성시스템 설치 (scripts/montage.sh에서 사용)

실행 단계

  1. 호스트 접근성 판단 (필수, 가장 먼저 수행) — 이미지 URL의 기준 주소와 공용 터널 추가 개설 여부를 결정합니다. 이미지 주소는 호스트 주소를 따라야 하며, 단순히 "동작하게" 하려고 호스트와 다른 출처의 터널을 임의로 열지 마십시오:

    판단결론 (조치)
    호스트가 이미 터널링/공용 접근 가능(사용자 휴대폰이 이 주소로 세션에 접속 중)이고, 정적 이미지 경로(예: /img/*)를 노출함이미지를 호스트 정적 디렉토리에 넣고 호스트 공용 주소를 삽입하며, 새 터널을 열지 않음
    호스트가 공용 접근 가능하지만 정적 이미지 경로를 노출하지 않음자동으로 폴백하지 않음: 먼저 사용자에게 "호스트에 정적 이미지 매핑을 구성해야 함"을 알림; 사용자가 동의한 경우에만 "명시적 독립 터널 폴백"을 진행
    호스트가 localhost 전용 (예: DSH_WEB_URL=http://127.0.0.1:*, 공용 아님)이미지는 로컬/로컬 네트워크 주소만 가지며, 휴대폰은 원래 이 세션에 접근할 수 없음 — 먼저 사용자에게 DSH를 공용으로 열도록 요청하거나, 사용자 동의 하에 명시적 폴백을 진행; localhost/127.0.0.1 주소를 삽입하고 휴대폰에서 볼 수 있다고 주장하지 마십시오
    감지 불가 / 불확실추측하지 말고 사용자에게 먼저 물어보십시오: "휴대폰으로 이 세션에 접속할 때 어떤 주소(공용 도메인 또는 localhost)를 사용하시나요?" 그런 다음 위 표에 따라 실행

    감지 방법: 환경 변수 읽기 (DSH_WEB_URL, DSH_PUBLIC_BASE, DSH_IMG_BASE 등), 호스트 정적 라우팅 설정 확인; 값을 얻을 수 없으면 "호스트가 제공하지 않음"으로 간주하고 위 표에 따라 "사용자에게 물어보기/알리기"를 진행하며, 조용히 다른 터널을 열지 마십시오.

    호스트 계약 (사전 약속, 현재 DSH 호스트는 아직 제공하지 않음): 호스트가 DSH_PUBLIC_BASE / DSH_IMG_BASE 또는 이에 상응하는 정적 경로 선언을 노출하는 경우, agent는 반드시 이미지를 호스트 도메인 아래에 우선 배치해야 합니다; 제공되지 않을 때는 존재한다고 가정하지 마십시오.

  2. 스크린샷 (필요한 경우): web-access skill을 사용하여 /screenshot으로 페이지를 PNG로 렌더링합니다.

    • CDP/Chromium이 제한된 환경(네트워크 차단/프로세스 충돌)에서 실행되지 않는 경우, 클라우드 스크린샷으로 폴백: thum.io / mshots / microlink 등을 사용하며 ?wait=N&width=W 매개변수를 포함하고, 반환된 이미지에서 "흰 픽셀이 아닌 비율이 임계값 초과, 색상 클러스터 수 > N"을 검증하여 빈 화면이 아닌 경우에만 사용합니다.
  3. 이미지 저장: 작업 공간에 저장합니다 (예: img/x.png, 파일명은 ASCII/공백 없음).

  4. 공유 (0단계 판단 결과에 따라 둘 중 하나 선택):

    • 호스트 경로 (0단계에서 호스트 재사용 가능으로 판단된 경우): 이미지를 호스트가 노출한 정적 디렉토리에 넣고 https://<호스트 도메인>/img/x.png를 삽입합니다; 독립 터널을 열지 마십시오.
    • 명시적 폴백 (0단계에서 폴백이 필요하고 사용자가 동의한 경우): 이 파일 하나만 공유하고 전체 디렉토리는 열지 않습니다; 이미지 서버[루프백 전용]+공용 터널을 시작하고, 종단 간 검증을 수행한 후 PUBLIC_BASE를 출력합니다:
      bash <skill>/scripts/setup.sh <img>/x.png        # Unix/WSL
      python <skill>/scripts/serve.py --share <img>/x.png   # Windows 네이티브
      
  5. 응답에 삽입 (썸네일=원본 이미지 URL, 클릭 시 원본 전체 화면):

    [![설명](https://<기준 주소>/x.png)](https://<기준 주소>/x.png)
    

    기준 주소는 반드시 0단계에서 판단된 결과(호스트 공용 주소 또는 사용자가 동의한 명시적 터널 주소)여야 합니다; localhost/127.0.0.1을 삽입하고 휴대폰에서 볼 수 있다고 주장하지 마십시오. 사용자에게 알림: 채팅창에 썸네일이 표시되고, 클릭하면 원본 이미지가 열립니다; 휴대폰에서도 동일한 공용 주소로 접근 가능합니다(DSH가 공용 마크다운 이미지를 렌더링할 수 있음이 확인됨).

  6. 공유 완료 → 터널 제거 (명시적 폴백 시나리오, 장기간 노출 방지):

    bash <skill>/scripts/teardown.sh                  # 이미지 서버+터널 중지 및 정리
    

실패 처리

  • 호스트 접근성 판단 불가: 추측하지 말고 조용히 다른 터널을 열지 마십시오; 먼저 사용자에게 휴대폰으로 이 세션에 접속할 때 사용하는 주소를 물어보십시오 (0단계 참조).
  • 호스트가 공용이지만 정적 이미지 경로 없음: 사용자에게 정적 매핑을 구성하도록 요청하거나, 동의를 얻은 후 명시적 폴백을 진행하고 해당 터널이 호스트와 다른 출처임을 설명하십시오.
  • 의존성 누락: serve.py가 "cloudflared/python 누락" 오류를 보고하면 지침에 따라 설치하거나 CLOUDFLARED를 설정하십시오; 스크린샷에 web-access가 없으면 클라우드 스크린샷으로 폴백(위 참조)하거나 사용자에게 이미지를 업로드하도록 요청하십시오.
  • 포트 점유: serve.py가 자동으로 사용 가능한 포트를 선택합니다.
  • 터널 도메인을 가져올 수 없음 (네트워크 느림/Cloudflare 연결 끊김): serve.py가 폴링하여 재시도합니다; 그래도 실패하면 "네트워크에서 터널을 생성할 수 없음"을 알리고 로컬/로컬 네트워크 전용으로 폴백합니다(로컬 주소 제공, 휴대폰 시나리오의 경우 먼저 호스트/서비스를 공용으로 접근 가능하게 해야 한다고 설명).
  • 종단 간 검증 실패: serve.py가 실제 파일명을 curl로 검증합니다(200이어야 성공); 실패 시 즉시 중단하여 "작동하는 것처럼 보이지만 실제로는 404"인 상황을 방지합니다.
  • 도메인 변경: 빠른 터널은 재시작 시 도메인이 변경되어 이전에 삽입된 URL이 작동하지 않습니다; 호스트 경로에는 이 문제가 없습니다; 폴백 시나리오의 장기 안정성을 위해서는 명명된 터널/고정 도메인을 사용하십시오.

환경 자체 점검 (Agent가 먼저 수행)

시작하기 전에 탐지: 외부 네트워크 접근 가능 여부 (curl로 공용 주소), 브라우저 프로세스 생성 가능 여부 (CDP), 호스트가 공용 접근 가능한지 여부 (0단계 참조). 외부 네트워크 접근과 CDP가 모두 불가능 → 클라우드 스크린샷 + 더 높은 권한 필요 알림을 진행하고, 사용자에게 "작동하는 것처럼 보이지만 실제로는 깨진" 이미지를 제공하지 마십시오.

보안 (기본 동작, 알림이 아님)

  • 지정된 파일만 공유: serve.py는 공유할 파일을 임의의 이름을 가진 하위 디렉토리로 복사한 후 서비스를 시작하며, 절대 전체 img/ 디렉토리를 열지 않습니다 (그렇지 않으면 터널 URL로 해당 디렉토리의 모든 파일을 나열/다운로드할 수 있음); 호스트 정적 디렉토리에도 공유할 파일만 배치합니다.
  • 이미지 서버는 127.0.0.1에만 바인딩됩니다 (로컬 네트워크에서 직접 접근 불가); 공용 터널 URL에는 인증이 없습니다 — 공유 직후 teardown하십시오.
  • 더 엄격하게 하려면: URL에 임의 토큰을 추가하거나 단기 터널을 사용하십시오; 민감한 이미지를 넣지 마십시오.
  • 모든 이미지를 공용에 노출하지 마십시오: "이번에 공유할 한/몇 개의 이미지"만 공개적으로 접근 가능한 디렉토리/터널에 나타나도록 하십시오.

호스트 터널 우선 (판단은 실행 단계 0단계 참조)

  • 이미지 주소는 호스트 주소를 따라야 함: 호스트가 이미 터널링/공용화된 경우, 이미지는 호스트와 동일한 도메인(예: 정적 /img/* 경로) 아래에 있어야 합니다 — 사용자 휴대폰에서 세션에 접속하면 즉시 로드되며, 호스트와 다른 출처의 임시 터널을 추가로 열 필요가 없으며 열어서도 안 됩니다.
  • 호스트가 dsh-trust-proxy 등을 통해 /img/ 정적 규칙을 노출하는 경우, 이미지 URL 형식은 https://<DSH 도메인>/img/x.png이며, 여러 장치에서 사용 가능하고 추가 터널이 필요 없습니다.
  • serve.py의 독립 cloudflared 터널은 이식 가능한 폴백(모든 머신에서 실행 가능)일 뿐입니다: 0단계에서 "호스트를 공용으로 재사용할 수 없음"으로 판단되고 사용자가 동의한 경우에만 사용하며, 그 한계(호스트와 다른 출처, 빠른 터널 재시작 시 도메인 변경)를 명확히 알립니다.

경계 조건

  • 프로세스는 상주/제거 가능해야 함: serve.py는 teardown을 위해 PID를 기록합니다; DSH 세션 내 서비스는 세션을 넘어 지속되어야 합니다(관리형 백그라운드 + teardown으로 명시적 정리 사용).
  • 파일명: ASCII 사용, 공백 없음; 스크립트는 파일 존재 여부를 검증하며, 한글/공백은 URL 인코딩으로 처리되지만 사용하지 않는 것이 좋습니다.
  • 작업 공간 차이: 서로 다른 세션은 서로 다른 작업 공간을 가지므로, 해당 세션 경로에 따라 공유합니다; serve.py는 시스템 임시 디렉토리를 사용하며 작업 공간에 의존하지 않습니다.

관련 스킬