feat: companion.py 다운로드 링크 + 시작 시 의존성 점검

- claude-app/code 에디터의 companion 상태 표시 옆에 companion.py 다운로드
  링크(⬇) 추가 — 업데이트될 때마다 재다운로드해야 함을 쉽게 안내
- companion.py를 직접 실행하면 시작 배너 다음에 tkinter(폴더 선택창)/
  pywinpty(Windows 터미널)/pystray+Pillow(트레이) 의존성 상태를 요약해서
  보여주고, 없는 항목은 설치 명령까지 안내

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
kim
2026-07-04 00:27:37 +09:00
co-authored by Claude Sonnet 5
parent 830ae12bac
commit 9f683bd637
3 changed files with 44 additions and 0 deletions
+1
View File
@@ -154,6 +154,7 @@
<div class="field" title="companion.py 연결 상태">
<span id="companion-dot" class="dot"></span>
<span style="color:var(--text-muted);font-size:10px">companion</span>
<a href="/companion.py" download title="companion.py 다운로드 (Bash 실행용 로컬 클라이언트, Windows/macOS/Linux 공용 — 업데이트 후에는 재다운로드 필요)" style="color:var(--text-muted);font-size:11px;text-decoration:none;margin-left:2px">⬇</a>
</div>
<div class="field">
+1
View File
@@ -319,6 +319,7 @@
<button id="code-term-toggle-btn" class="csb-term-btn" onclick="toggleCodeTerminal()" title="터미널 토글 (Ctrl+`)">⌨ 터미널</button>
<span id="companion-dot" onclick="companionConnect()" title="Python companion 미연결 — 클릭해서 재연결"
style="width:10px;height:10px;border-radius:50%;background:#6b7280;display:inline-block;cursor:pointer;flex-shrink:0"></span>
<a href="/companion.py" download title="companion.py 다운로드 (Bash 실행용 로컬 클라이언트, Windows/macOS/Linux 공용 — 업데이트 후에는 재다운로드 필요)" style="color:var(--muted);font-size:12px;text-decoration:none;flex-shrink:0">⬇</a>
</div>
<!-- 미리보기 -->
<div class="csb-term-row">
+42
View File
@@ -671,6 +671,45 @@ async def main():
await asyncio.Future()
def _check_dependencies():
"""선택적 의존성 상태를 확인해 시작 시 한눈에 보여준다.
websockets는 필수라 파일 최상단에서 이미 체크됨(없으면 여기까지 못 옴)."""
checks = [('websockets (필수)', True, '')]
try:
import tkinter # noqa: F401
checks.append(('tkinter — 폴더 선택창', True, ''))
except ImportError:
hint = 'python.org 설치본은 기본 포함, 커스텀/최소 설치라면 재설치 필요' if IS_WINDOWS else 'sudo apt install python3-tk (또는 배포판에 맞는 tk 패키지)'
checks.append(('tkinter — 폴더 선택창', False, hint))
if IS_WINDOWS:
has_pty = False
for mod in ('pywinpty', 'winpty'):
try:
__import__(mod)
has_pty = True
break
except ImportError:
continue
checks.append(('pywinpty — 터미널 색상/크기 지원', has_pty, '' if has_pty else 'pip install pywinpty'))
try:
import pystray # noqa: F401
from PIL import Image # noqa: F401
checks.append(('pystray+Pillow — 시스템 트레이 실행', True, ''))
except ImportError:
checks.append(('pystray+Pillow — 시스템 트레이 실행', False, 'pip install pystray Pillow'))
print('의존성 상태:', flush=True)
for name, ok, hint in checks:
line = f' {"✅" if ok else "⚠️ "} {name}'
if not ok and hint:
line += f' → {hint}'
print(line, flush=True)
print(flush=True)
if __name__ == '__main__':
try:
print('━' * 40)
@@ -678,9 +717,12 @@ if __name__ == '__main__':
print(f'플랫폼: {"Windows" if IS_WINDOWS else "Unix/Linux"}')
print('━' * 40)
print(f'Python: {sys.executable}')
print()
except Exception:
pass
_check_dependencies()
try:
import pystray
from PIL import Image