# dsh-capability-panel [![npm](https://img.shields.io/npm/v/dsh-capability-panel)](https://www.npmjs.com/package/dsh-capability-panel) [![CI](https://github.com/pure-craft/dsh-capability-panel/actions/workflows/check.yml/badge.svg)](https://github.com/pure-craft/dsh-capability-panel/actions/workflows/check.yml) [![license](https://img.shields.io/npm/l/dsh-capability-panel)](LICENSE) [English](README.md) | [中文](README.zh.md) | [日本語](README.ja.md) | 한국어 **DeepSeek Harness 에이전트가 지금 실제로 도달할 수 있는 것을 확인하고, 세션 단위 또는 프리셋 단위로 전환하세요.** 현재 대화의 capability 표면을 보여주는 패널: 모든 스킬, MCP 서버, 시스템 도구의 실제 인컨텍스트 상태와, 다음 모델 스텝부터 바로 적용되는 스위치를 제공합니다. ![라이브 세션의 capability 패널: 로드 상태 필이 붙은 스킬, 서버별 MCP, 행별 스위치](docs/images/panel-session.png) --- ## 한눈에 보기 (에이전트 빠른 참조) | | | |---|---| | 무엇 | [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`) 웹 플러그인: 현재 세션의 스킬·MCP 서버·시스템 도구와 그 실제 인컨텍스트 상태를 나열하고 개별 전환하는 패널 | | 용도 | "왜 에이전트가 이 스킬을 모르지?" 해결. 로드된 스킬이 프루닝/컴팩션에서 살아남았는지 확인. 특정 도구나 MCP 서버를 이 세션에서만 끄기. 프리셋별 기본 capability 세트 설정. 비활성화 후 차단된 호출 횟수 계측 | | 설치 | `dsh plugin --profile web add dsh-capability-panel`(설치 후 dsh 재시작) | | 요구 사항 | dsh web 프로필, dsh ≥ 0.1.2-alpha.4(이전 버전에서도 실행되지만 로드 상태는 degraded 로 표시). `@deepseek-ai/*` peer는 모두 호스트가 제공 | | 데이터 | `$DSH_HOME/settings.yaml`의 `capability-panel` 네임스페이스. 통계는 `$DSH_HOME/capability-panel/stats.jsonl`. loopback API `/api/capability-panel` | | 패키지 | npm의 `dsh-capability-panel`. bundle id는 `capability-panel` | ## 왜 스킬이 *설치되어 있다*는 것과 *지금 모델의 컨텍스트에 있다*는 것은 서로 다른 사실입니다. 그리고 "왜 에이전트가 이것을 모를까?"에 답하는 것은 후자뿐입니다. 그 사이에는 컨텍스트 관리가 있습니다: 도구 결과 프루너는 긴 페이로드를 잘라내고, 컴팩션은 히스토리 구간을 요약으로 대체합니다. 5분 전에 로드된 스킬은 모델의 시야에서 부분적으로 또는 완전히 사라졌을 수 있습니다. 또는 그저 이 대화에서 모델이 특정 도구를 사용하지 않았으면 할 때도 있습니다——플러그인을 제거하거나 설정 파일을 수정하고 재시작하는 것이 아니라, 그냥 이 세션에서, 다음 스텝부터요. ## 기능 - **정확한 로드 상태.** 각 스킬은 다음 요청에서 모델이 실제로 보는 것을 보고합니다: `loaded`(전체 지시문이 컨텍스트에 있음) / `truncated`(프루너가 앞뒤를 남기고 중간을 잘라냄) / `evicted`(컴팩션이 완전히 제거) / `not loaded`. 누적 로드 횟수 포함——제거 후 다시 로드된 스킬은 `loaded ×2`로 읽힙니다. - **재시작해도 유지되는 세션 단위 스위치.** 현재 대화에서 스킬·도구·MCP 서버 전체를 끕니다. 다음 프롬프트 조립부터 적용되며, dsh 재시작 후에도 해당 세션에 바인딩된 채 복원됩니다. 다른 세션이나 대화 히스토리는 건드리지 않습니다. - **프리셋 기본값.** 설정 → capability 패널에서 에이전트 프리셋별 기본 capability 세트를 저장합니다. 이후 생성되거나 복원되는 세션이 이를 상속합니다. 프리셋 기본값은 시작점일 뿐, 세션에서 언제든 재정의할 수 있습니다. - **서버별 MCP 그룹화.** 두 서버에 200개의 도구가 있어도 한눈에 볼 수 있습니다. 서버당 한 행으로 접고, 한 번의 쓰기로 전체를 전환합니다. - **오프라인 서버도 목록에 남습니다.** 호스트 구성에 선언되어 있지만 현재 도구를 하나도 등록하지 않은 MCP 서버(실행 중이지 않은 로컬 온디맨드 서비스 등)도 행이 유지됩니다——「등록된 도구 없음」으로 정직하게 표시하고, 이미 꺼둔 항목을 나열하며, 지금 즉시 연결을 다시 시도하는 **리로드** 버튼이 붙습니다. 세션 도중에 등록된 도구에도 저장된 기본값이 자동으로 적용됩니다. - **출처별 그룹화.** 스킬과 MCP 서버가 라벨이 붙은 구분선 아래로 모입니다: 프리셋에 포함된 항목은 출처 프리셋 이름을 표시하고, 나머지는 실제 디렉터리(`~/.dsh/skills`, 프로젝트 상대 경로, 길면 중간 생략)를 표시합니다——"이 스킬은 어디서 왔지?"에 한눈에 답할 수 있습니다. - **원클릭으로 소스 폴더 열기.** 그룹 구분선에 호버하면 폴더 아이콘이 나타나고, 클릭하면 해당 소스 디렉터리가 시스템 파일 관리자에서 열립니다(macOS, Windows, freedesktop Linux). - **차단 횟수.** 끈 후에도 모델이 해당 capability를 계속 호출하면 패널이 카운트합니다——모델이 기억에서 행동하고 있다는 신호입니다. - **원클릭 명령 입력.** 스킬 행의 종이비행기 버튼이 `/skill-name`을 입력창에 넣습니다. Enter만 누르면 됩니다. - **빠른 필터링.** 이름, 설명 또는 상태 라벨로 검색("truncated" / "已截断" 모두 가능). 일치하는 설명은 자동으로 펼쳐집니다. - **경량.** 런타임 의존성 제로, 제로카피 읽기, 백그라운드 작업 없음——패널은 열릴 때만 읽습니다. - **UI 언어 추종.** 패널 문구는 호스트에 따라 중국어와 영어로 전환됩니다. ## 프로덕션 등급 - **철저한 테스트**: 390+ 테스트. typecheck, 타입 인식 lint, 100% 커버리지 게이트(문/분기/함수/행)를 CI에서 모든 push와 PR에 강제합니다. - **정직한 실패**: 읽기(스킬 레지스트리, 세션 뷰, 설정 저장소) 중 하나라도 실패하면 패널은 부분 데이터와 명시적인 degraded 안내를 표시합니다——읽기 실패를 빈 목록으로 위장하지 않습니다. - **쓰기 경합 없음**: 프리셋 기본값과 세션 스위치는 하나의 직렬화된 쓰기 큐를 공유하므로, 두 패널이 동시에 써도 서로를 덮어쓰지 않습니다. - **호스트에 부담 없음**: agent 생성 리스너는 실패를 완전히 격리——플러그인의 어떤 예외도 세션 시작을 막지 못합니다. - **로컬 퍼스트, 네트워크 제로**: 데이터 라우트는 loopback 호출만 허용하고, 플러그인은 외부 호출·텔레메트리·서드파티 서비스를 전혀 사용하지 않습니다——모든 상태는 로컬 settings.yaml과 하나의 JSONL에만 남습니다. - **거대한 세션에서도 즉시 열림**: 6만 이벤트, 수십 MB 로그의 세션에서도 패널은 바로 열립니다——제로카피 surface 읽기, 열릴 때 한 번만 읽고, 폴이나 백그라운드 작업 없음. - **히스토리를 보존하는 스위치**: 스위치는 대화 히스토리를 절대 다시 쓰지 않습니다——비활성화된 capability는 로그에 그대로 남고, "이것들은 꺼짐" 노트는 조립할 때마다 재계산됩니다. 모든 스위치는 되돌릴 수 있는 결정이지, 돌이킬 수 없는 수술이 아닙니다. - **공식 확장 포인트만 사용**: 모든 capability는 dsh의 공식 이음새(`tools.restrict`, `system-prompt/assemble`, settings 네임스페이스, UI slots)에서 옵니다——몽키 패칭이 없어 호스트 업그레이드에 훨씬 강합니다. - **테마는 공짜**: 모든 색상은 호스트 design token이고 모든 아이콘은 호스트 아이콘 세트——라이트/다크와 언어 전환이 호스트를 자동으로 따르며, 유지할 테마 코드가 없습니다. - **i18n 친화**: 패널 문구는 호스트 UI 언어(中文/English)를 따르고, 문서는 4개 언어로 섹션을 맞춰 유지합니다. ## 설치 ```bash dsh plugin --profile web add dsh-capability-panel # 또는 dsh plugin --profile web add github:pure-craft/dsh-capability-panel ``` 설치 후 dsh를 재시작해야 적용됩니다. DeepSeek Harness의 web 프로필(`dsh web`), dsh ≥ 0.1.2-alpha.4가 필요합니다(로드 상태는 해당 버전에서 도입된 `session.snapshotEvents`로 읽습니다. 이전 버전에서도 패널은 실행되지만 로드 상태는 degraded 로 표시되고 payload 에 명기됩니다). `@deepseek-ai/*` peer는 모두 호스트가 제공하므로 추가로 설치할 것은 없습니다. **설정 불필요**——이 플러그인에는 설정 항목이 없습니다. 재시작 후 두 곳에서 찾을 수 있습니다: - 대화 입력창 오른쪽의 **컨텍스트 아이콘**——세션 패널을 엽니다 - **설정 → capability 패널**——프리셋별 기본 capability `--profile web`은 `dsh web` GUI가 사용하는 프로필이므로 명령을 그대로 실행하면 됩니다. 마켓플레이스에서 "capability panel"을 검색해 원클릭으로 설치할 수도 있습니다. 제거는 `dsh plugin --profile web remove dsh-capability-panel`. 설정과 통계는 `$DSH_HOME`에 남습니다("데이터 저장 위치" 참조). ## 사용법 대화를 열고 입력창 오른쪽의 컨텍스트 아이콘을 클릭하면 패널이 위로 열립니다. - 상단의 세 탭: **Skills N** / **MCP N** / **Tools N** - 각 행 오른쪽의 스위치는 즉시 적용——새로고침도 재시작도 불필요 - 행을 클릭하면 설명이 펼쳐집니다 - 상단 필터는 이름, 설명, 상태 라벨을 검색 - 구분선은 각 탭을 출처별로 그룹화합니다: 프리셋 포함 항목은 프리셋 이름, 나머지는 디스크상의 디렉터리——구분선에 호버하면 전체 경로를 보여주고, 클릭하면 해당 폴더가 파일 관리자에서 열립니다 - 꺼진 행은 흐리게 표시되고, 모델의 시스템 프롬프트에도 "사용자가 끈 capability"가 명시됩니다 `run_code`는 예약된 Code Mode 트랜스포트로, 레지스트리가 마스킹을 금지하므로 스위치가 켜진 채로 고정됩니다. 두 스코프, 같은 스위치: **입력창의 패널**은 눈앞의 세션에 바인딩되고(재시작 후에도 함께 복원), **설정 → capability 패널**은 이후 모든 세션의 시작점을 결정합니다. ![설정 → capability 패널: 프리셋별 기본 capability](docs/images/panel-settings.png) ## 작동 원리 **구조적으로 경량.** 플러그인은 런타임 의존성이 전혀 없고——React, UI 프리미티브, 모든 `@deepseek-ai/*`는 호스트가 제공——읽기도 제로카피입니다. 로드 상태는 live 세션의 인메모리 surface(모델이 다음에 볼 내용)에서 가져오며, 영구 로그를 매번 다시 접지 않습니다. 스위치는 다음 프롬프트 조립 위의 얇은 오버레이(스킬은 동명 섀도우, 도구는 레지스트리 마스크)와 조립 시마다 재계산되는 안내 노트뿐입니다. 세션 전환은 세션 고유 id로 플러그인 설정 네임스페이스에 저장되므로, 복원된 세션은 자신의 스위치만 정확히 되찾고, 대화 로그에는 아무것도 기록되지 않습니다. ## 데이터 저장 위치 - 프리셋 기본값과 세션 바인딩 스위치 위치: `$DSH_HOME/settings.yaml`의 `capability-panel` 네임스페이스(세션 스위치는 `sessions.` 아래, 최대 200개 세션, 오래된 것부터 eviction). 하니스는 로드되지 않은 플러그인의 섹션을 절대 삭제하지 않으므로, 제거 후에도 직접 지우기 전까지 유지됩니다. - 차단 통계: `$DSH_HOME/capability-panel/stats.jsonl`. `curl 'http://127.0.0.1:3080/api/capability-panel/stats'`로 직접 읽을 수 있습니다. 데이터 라우트는 loopback 호출만 허용합니다. ## 개발 ```bash pnpm install pnpm dev # watch 빌드 pnpm build # 호스트와 클라이언트 양쪽 빌드 pnpm test # 테스트 pnpm typecheck # 타입 체크 pnpm lint # oxlint(type-aware 규칙 포함) pnpm check # typecheck + lint + test(100% 커버리지 게이트) pnpm scan:dead-code # 데드 코드 점검 보고서(권고용, 게이트 아님) ``` 호스트 측 변경은 dsh 재시작이 필요하고, 클라이언트 측은 `dsh web`과 watch 빌드가 함께 실행 중일 때 핫스왑됩니다. ## 응원하기 이 패널이 디버깅 시간을 아껴줬다면, [star](https://github.com/pure-craft/dsh-capability-panel)를 눌러주세요——필요한 다른 사람들이 찾을 수 있게 됩니다. dsh를 만지는 지인에게 공유해주셔도 좋습니다. Issue와 PR은 언제나 환영합니다——[기여 가이드](CONTRIBUTING.md)를 참고하세요. 변경 이력은 [CHANGELOG.md](CHANGELOG.md)에서 확인할 수 있습니다. ## 라이선스 [MIT](LICENSE)