CH 17 · 플러그인 설치
본 장 목표
CH 12에서 이미 세 개의 플러그인을 설치하셨습니다 — dsh-mcp-client, dshmarket, dsh-skill-mcp-panel — 다만 그때는 "그때그때 설치하고, 작동하면 됐지" 식이었기에 세 가지 설치 방법에 대해서는 자세히 다루지 않았습니다. 이 장에서는 플러그인 설치를 체계적으로 다룹니다. 플러그인이 어디에서 오는지, 어디에 설치되는지, 설치 방법에는 어떤 것들이 있는지, 어떻게 관리하는지, 설치 후 어떻게 확인하는지 — 그리고 마지막에는 직접 한 번 실습으로 설치해 봅니다. 게다가 직접 dsh에게 설치를 맡기는 것까지 합니다.
먼저 한 문장만 기억해 두세요: 플러그인 설치 = 어떤 profile에 npm 의존성을 추가하는 것. dsh는 "모든 것이 플러그인"입니다(CH 08에서 다룸), 그러나 플러그인의 "설치" 자체는 표준 패키지 관리 방식을 따릅니다. 설치를 이해하면, CH 18에서 첫 플러그인을 직접 작성합니다.
먼저 본인 설치 현황 살펴보기
터미널을 열고, 먼저 dsh 본체의 버전을 확인합니다:
dsh --version제 출력입니다:
0.1.1-rc.2이어서 web profile에 이미 어떤 플러그인들이 설치되어 있는지 확인합니다:
dsh plugin --profile web list제 출력입니다(CH 12에서 설치한 결과 그대로):
Legend: production dependency, optional only, dev only
dsh-profile-web C:\Users\mortal\.dsh\profiles\web (PRIVATE)
│
│ dependencies:
├── @deepseek-ai/dsh-mcp-client@0.0.1-rc.1
├── dsh-skill-mcp-panel@2.0.1
└── dshmarket@1.40.0
3 packages이 세 줄이 정확히 세 가지 설치 방법에 각각 대응됩니다: mcp-client는 명령행으로 설치한 것이고, dshmarket는 명령행으로 설치한 마켓 본체이며, dsh-skill-mcp-panel은 마켓에서 원클릭 설치한 것입니다 — 그리고 이 둘이 별다른 설정 없이 곧바로 설정 트리에 들어가서 적용되는 이유는 세 번째 메커니즘인 bundle 자동 마운트 덕분입니다. 아래에서 하나씩 설명합니다.
플러그인은 어디에서 오는가: 네 가지 출처
플러그인은 본질적으로 npm 패키지이며, 출처는 다음과 같습니다:
| 출처 | 표기 | 사용 시점 |
|---|---|---|
| npm 패키지 | @deepseek-ai/dsh-mcp-client | 가장 흔함. 공식 패키지는 @deepseek-ai/ 접두사를 달고, 커뮤니티 패키지는 자체 scope 사용 |
| GitHub 소스 | github:owner/repo | 어떤 저장소의 main 브랜치를 설치하고 싶을 때, npm에 등록되지 않았을 때 |
| 로컬 디렉터리 | . 또는 file:../plugin | 본인이 플러그인을 개발 중일 때, 로컬 checkout을 그대로 설치하여 수정·테스트 |
| tarball / Release 산출물 | .tgz의 URL 또는 로컬 경로 | 작성자가 빌드 산출물만 배포할 때, 예: GitHub Release의 첨부 파일 |
CH 12에서 설치한 **dsh-market(플러그인 마켓)**은 새로운 출처가 아니라 그래픽 진입점입니다. 설치 후에는 설정에서 커뮤니티 플러그인을 탐색·검색·원클릭 설치할 수 있고, 내부적으로는 위에서 언급한 출처들을 호출합니다.
어디에 설치되는가: Profile 레벨, profile을 따름
dsh plugin은 특정 profile의 플러그인을 관리하므로, 명령에는 반드시 --profile <이름>을 붙여 어떤 환경에 설치할지 지정해야 합니다. 설치된 패키지는 다음 위치에 들어갑니다:
$DSH_HOME/profiles/<이름>/node_modulesWindows에서는 C:\Users\<사용자 이름>\.dsh\profiles\web\node_modules이며, pnpm이 관리하고 profile의 package.json에도 함께 기록됩니다.
쉽게 혼동하는 부분 하나를 짚고 가겠습니다 — 전역과 Profile의 차이:
- dsh 본체는 전역 설치됩니다(이전의
npm install -g @deepseek-ai/dsh), 모든 profile이 동일한 dsh를 공유합니다. - 플러그인은 기본적으로 profile별입니다:
dsh plugin --profile web add xxx는 web에서만 적용됩니다. headless에서도 사용하려면 headless에도 별도로 설치해야 합니다. - 머신 레벨 설정은 또 다른 계층입니다:
$DSH_HOME/cordis.patch.yml은 모든 profile이 공유하며(공식 명칭은 "machine-local preferences"), 게다가 profile 자체의cordis.patch.yml보다 우선순위가 더 높습니다 — 모든 환경에 동일한 변경을 적용하고 싶다면 여기에 작성하세요.
이 파일들이 각각 어디에 있는지 먼저 정리하고, 헷갈리지 않도록 합시다. profile 레벨의 파일은 C:\Users\<사용자 이름>\.dsh\profiles\web\cordis.patch.yml이며(CH 12에서 MCP 서버 설정을 수정한 바로 그 파일입니다), 머신 레벨의 파일은 C:\Users\<사용자 이름>\.dsh\cordis.patch.yml입니다 — 이 파일은 기본적으로 존재하지 않으며, 사용자가 직접 설정을 작성해야 만들어지고, dsh는 시작할 때 이 파일을 읽으며 파일이 없으면 건너뜁니다. 따라서 "내가 작성한 설정이 정말 머신 레벨인지" 확인하려면, .dsh 루트 디렉터리에 있는지 살펴보면 됩니다. profiles\<이름>\ 아래에 있다면 그것은 profile 레벨입니다.
- 공식 내장 bundle(
@deepseek-ai/dsh-base,@deepseek-ai/dsh-web-app등)은 dsh와 함께 제공되며 전역 설치에서 비롯됩니다. 본인이 직접 추가한 플러그인은 profile 자체의node_modules에 설치됩니다.
한 문장으로 정리: dsh 본체는 전역, 플러그인은 profile을 따르고, 머신 레벨 패치는 사이트 전체에 적용.
세 가지 설치 방법
① 명령행 dsh plugin: 가장 근본적인 방법
이것이 가장 근본적인 설치 방법입니다. dsh plugin --profile <이름>은 뒤따르는 인자를 있는 그대로 pnpm에 전달하므로, add, remove, update, why, list 같은 pnpm 동사들이 모두 사용 가능하고, 표기 역시 npm 패키지 관리 표기를 그대로 따릅니다:
dsh plugin --profile web add @deepseek-ai/dsh-mcp-client공식 문서의 전형적인 예시로는 두 개의 subagent 플러그인 설치(선택적 bundle)가 있습니다:
dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex @deepseek-ai/dsh-subagent-claude-code
dsh plugin --profile web remove @deepseek-ai/dsh-subagent-codex본인이 개발한 플러그인을 로컬 디렉터리에서 설치하는 것도 바로 이 방법을 사용합니다 — 플러그인 소스 디렉터리에서 dsh plugin --profile web add .를 실행하면 현재 checkout이 그대로 설치됩니다(상대 경로는 명령을 실행한 디렉터리를 기준으로 하며, profile 디렉터리가 아닙니다).
② 플러그인 마켓 dsh-market: 가장 쉬운 방법
그래픽 설치 방법입니다. 먼저 마켓 본체를 설치합니다:
dsh plugin --profile web add dshmarket설치 후 dsh를 재시작합니다(bundle 변경은 재시작이 필요하며, 자세한 내용은 아래에서 설명), 설정에 새로운 "플러그인 마켓"이 나타납니다. 카테고리별로 탐색하고, 검색하고, 커뮤니티 플러그인을 원클릭으로 설치할 수 있습니다. 마켓을 통해 설치한 대부분의 플러그인은 페이지를 새로 고치기만 하면 적용되어 dsh를 재시작할 필요가 없습니다. 일부 host 레벨 플러그인은 "재시작 필요"를 안내하는데, 안내에 따르시면 됩니다. CH 12에서 설치한 dsh-skill-mcp-panel은 마켓에서 검색해 원클릭으로 설치한 것이었습니다.

③ Bundle 자동 마운트: 설치와 동시에 설정 트리에 진입
반드시 한번쯤 의문을 가져보셨을 현상부터 짚고 가겠습니다: 왜 mcp-client는 설치 후 서버 설정을 위해 cordis.patch.yml에 수동으로 insert를 작성해야 하는 반면, dshmarket와 dsh-skill-mcp-panel은 설치 후 별다른 설정 없이 적용될까요? 답은 플러그인 자체의 package.json에 있습니다 — 차이는 dsh.bundle 선언 여부입니다. "설치 즉시 설정 트리에 자동 진입"하려면, 플러그인이 자신의 manifest에서 다음 필드를 선언해야 합니다:
{
"dsh": {
"bundle": {
"patch": "./cordis.patch.yml"
}
}
}dsh는 dsh plugin 실행이 성공할 때마다마다 bundle 목록을 재조정합니다. dependencies에 포함된 패키지 중 dsh.bundle 선언이 있는 것은 해당 profile의 bundle 레이어(설정 트리의 맨 아래에 있는 기본 레이어, CH 08에서 다룸)에 자동으로 추가되며, 수동으로 insert할 필요가 없습니다.
실례로, 선언이 있는 두 플러그인의 package.json을 살펴봅니다. dshmarket@1.40.0:
"dsh": {
"bundle": { "patch": "./cordis.patch.yml" },
"client": { "inject": ["@deepseek-ai/dsh-client-connection", "..."], "platform": "web" }
}dsh-skill-mcp-panel@2.0.1:
"dsh": {
"client": { "platform": "web", "inject": ["@deepseek-ai/dsh-client-runtime", "..."] },
"bundle": { "patch": "./cordis.patch.yml" }
}둘 다 bundle.patch 선언이 있으므로, 둘 다 profile manifest의 bundle 목록에 자동 등록됩니다. web profile의 package.json을 열어 보면, bundle 레이어는 다음과 같이 구성됩니다:
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-skill-mcp-panel",
"dshmarket"
]
}
}앞의 두 개는 공식 내장 bundle(전역 dsh 설치와 함께 제공)이고, 뒤의 두 개는 본인이 설치한 후 자동 마운트된 것입니다. 그렇다면 dsh-mcp-client는 어떨까요? 이 플러그인은 dsh.bundle 선언이 없으므로, 일반적인 의존성에 불과합니다 — profile의 package.json dependencies에는 나타나지만 bundles 목록에는 들어 있지 않습니다. 비유하자면: bundle 플러그인은 "설명서가 동봉된, 꺼내면 바로 쓸 수 있는 도구"이고, 일반 의존성은 "도구만 있고 설명서는 없는" 상태 — 물건은 도착했지만 dsh가 능력을 자동으로 적재하지는 않으며, 사용자가 직접 설정해야 합니다.
dsh-mcp-client가 바로 후자입니다: 이는 "MCP 서버에 연결하는 엔진"이며, 연결하는 법은 알지만 어디에 연결할지는 모릅니다. 사용자가 직접 어떤 서버에 연결할지, 주소는 무엇인지, 키는 어떻게 전달하는지를 알려주어야 합니다 — 이 행위가 바로 cordis.patch.yml에 insert를 작성하는 것입니다(서버 설정 한 줄을 설정 트리에 삽입). CH 12에서 작성하셨던 Firecrawl 설정이 바로 그러한 insert였습니다.
또 하나 짚어둘 점: 이 두 플러그인은 dsh.client 선언도 함께 가지고 있습니다(platform: web + client 플러그인 주입 목록). 그래서 이 두 플러그인이 Web UI 설정에 인터페이스를 추가할 수 있는 것입니다(플러그인 마켓, MCP 관리) — bundle이기도 하고(설정 트리에 진입) client 주입도 선언하는(인터페이스에 진입) 셈입니다.
반드시 기억할 경계: bundle 멤버(bundles 목록에 들어 있는 것)의 변경 이후에는 반드시 profile을 재시작해야 적용됩니다 — 실행 중인 profile은 시작 시점의 bundle 집합을 그대로 유지하며, 새로 설치한 bundle은 다음 시작 시에만 적재됩니다. 여기서 "재시작"의 의미는 단지 자동 적재를 위한 것일 뿐, 무언가를 설정해야 한다는 뜻이 아닙니다 — bundle 플러그인이 적재되면 곧바로 사용할 수 있으며, 설정을 만질 필요는 없습니다. 일반적인 cordis.patch.yml 수정은 핫 리로드로 처리되므로 재시작이 필요 없습니다. 하지만 bundle의 add/remove/update는 재시작이 불가피합니다. CH 12에서 dshmarket 설치 후 재시작하셨던 이유가 바로 이 자동 적재를 위해서였습니다.
관리 명령어 모음표
| 명령어 | 효과 |
|---|---|
dsh plugin --profile web list | 해당 profile에 설치된 항목 나열(pnpm list와 동일) |
dsh plugin --profile web add <출처> | 설치, 출처는 위의 네 가지 참조 |
dsh plugin --profile web remove <패키지> | 제거 |
dsh plugin --profile web update <패키지> | 최신 버전으로 갱신(bundle 선언이 있는 것은 새 선언과 재조정) |
dsh plugin --profile web why <패키지> | 해당 패키지가 설치된 이유 확인(누가 의존하는지) |
설치 후 어떻게 확인하나요? 두 가지 방법이 있습니다:
- 의존성과 bundle 귀속 확인:
dsh plugin --profile web list로 의존성 확인, bundle 레이어에 들어갔는지 보려면 profile의package.json(위의dsh.profile.bundles)을 직접 살펴봅니다. - 설정 트리에 실제로 마운트되었는지 확인:
dsh --profile web --dump-config로 전체 설정 트리를 출력하고 플러그인명을 검색합니다. bundle 기본 레이어만 보고 싶다면dsh --profile web --dump-default-config를 사용합니다.
실제로 쓸모 있는 커뮤니티 플러그인 세 개 설치하기
앞서 설치한 플러그인은 메커니즘 설명을 위한 것이었고, 그 과정에서도 실제로 필요한 것들이었습니다 — dsh는 원래 그렇습니다. 원하는 것을 설치하고, 모든 것이 플러그인입니다. 이제 "설치 즉시 사용성이 좋아지는" 커뮤니티 플러그인 세 개를 설치합니다. GitHub 소스와 npm에서 가져옵니다. 직접 명령을 입력할 필요 없이, dsh에게 맡기면 됩니다.
dsh-theme: Web UI 스킨 변경하기
독립형 테마 플러그인입니다. 설치 후 설정에 새로운 "외관(Appearance)" 항목이 추가됩니다:
- 세 가지 외관 모드: 라이트 / 다크 / 시스템 따르기
- 큐레이션된 15종 테마, 그중 5종은 읽기용 테마, 1종은 코드용 Carbon Code 테마
- 각 테마는 색상 단계, UI 폰트, 코드 폰트, 글자 크기를 통합된 설정으로 묶어 한 번에 전환 가능
- 강조 색상, 배경, 전경, 표면, 사이드바 색상을 실시간으로 개별 조정 가능
- 설정은 브라우저 로컬에 저장되어 새로 고침해도 유지(브라우저·profile 간 동기화는 안 됨)
dsh에게 설치를 맡기려면 입력창에 다음과 같이 보냅니다:
dsh-theme 플러그인을 web profile에 설치하고 잘 작동하는지 확인해 줘. GitHub에 oil-oil/dsh-theme 저장소에 있어.소스: oil-oil/dsh-theme. 설치 후 web profile을 재시작하면, 설정 → 외관에서 테마를 전환할 수 있으며, 모습은 다음과 같습니다:

dsh-oil-sticky-prompt: 스크롤 중 최신 사용자 메시지를 상단에 고정하기
긴 응답을 스크롤할 때, 최신 사용자 메시지가 압축된 풀폭 바로 대화 상단에 고정되며, 클릭하면 원래 위치로 돌아갑니다:
- 단일 고정 바, 여러 토픽이 있어도 충돌하지 않음
- 원래의 줄바꿈은 공백으로 평탄화되고, 최대 두 줄로 표시
- 메시지 자체를 수정하지 않으며, 세션 로그에도 손대지 않고, 설정도 저장하지 않음
dsh에게 설치를 맡기려면 입력창에 다음과 같이 보냅니다:
dsh-oil-sticky-prompt 플러그인을 web profile에 설치하고 잘 작동하는지 확인해 줘. GitHub에 oil-oil/dsh-oil-sticky-prompt 저장소에 있어.소스: oil-oil/dsh-oil-sticky-prompt. 설치 후 dsh를 재시작합니다. 아래는 dsh가 실제로 설치해 준 모습입니다 — Peer dependency 경고는 예상된 동작이며, 다음에 web profile을 재시작할 때 적용된다고 설명합니다:

dsh-better-sidebar: 사이드바를 본격 워크벤치로 바꾸기
기능이 가장 풍부한 플러그인으로, 오른쪽 사이드바를 "워크벤치"로 끌어올립니다. 그 설계 사상은 Codex 같은 AI 코딩 도구의 사이드바와 같은 계열입니다 — 파일, 터미널, Git을 Agent 옆으로 옮겨놓고, 작업하는 모습을 지켜볼 수 있게 합니다:
- 파일 워크벤치: 디렉터리 트리 + 코드 에디터, 이미지 / Markdown / HTML / PDF / Office 인라인 미리보기
- 임베디드 브라우저: 여러 웹페이지 탭, 샌드박스 iframe에서 실행
- 실제 터미널: xterm + node-pty로 실제 셸을 실행, 연결 끊김 시 재연결, 터미널 도구를 모델에 주입하는 옵션
- Git 패널: 실제 diff, 히스토리, 우클릭 stage / commit / revert
- 백그라운드 작업 페이지: subagent 토폴로지와 백그라운드 작업 확인(종료 코드 / 실시간 출력 / 강제 종료)
- 오른쪽 사이드바 + 하단 패널의 듀얼 워크벤치, 레이아웃은 세션별로 기억
dsh에게 설치를 맡기려면 입력창에 다음과 같이 보냅니다:
dsh-better-sidebar 플러그인을 web profile에 설치하고 잘 작동하는지 확인해 줘. GitHub에 omdsh-dev/DSH-better-sidebar 저장소에 있어 (npm 패키지 이름은 dsh-better-sidebar).소스: omdsh-dev/DSH-better-sidebar. 설치 후 dsh를 재시작한 다음 브라우저를 하드 새로고침해야 사이드바가 보입니다(bundle 멤버라서 재시작 시에만 적재). 우측 파일 브라우저 + 하단 터미널이 함께 나타납니다:

이 세 가지 모두
bundle선언이 있어 설치 시 자동 마운트됩니다(③의 메커니즘). GitHub 소스로 처음 설치하는 두 플러그인은 pnpm의 allowBuilds에 막힐 수 있는데, 그 부분은 "자주 겪는 함정"에서 다룹니다.
자주 겪는 함정
| 문제 | 현상 | 대응 |
|---|---|---|
| 설치했는데 UI 변화가 없음? | bundle 멤버를 설치한 경우 실행 중인 profile은 자동 리로드되지 않음 | dsh를 재시작한 뒤 설정 다시 확인 |
Git 소스 플러그인 첫 add에서 allowBuilds 오류? | pnpm ≥10은 기본적으로 소스 패키지가 prepare 빌드 스크립트를 실행하지 못하게 막음 | 오류에 표시된 안내에 따라 allow 키를 profile 디렉터리의 pnpm-workspace.yaml에 복사한 뒤 add 재실행 |
| dsh-better-sidebar 설치 시 "Ignored build scripts"가 보고됨? | pnpm 11이 node-pty 같은 네이티브 모듈의 빌드 스크립트를 차단 | profile 디렉터리(C:\Users\<사용자 이름>\.dsh\profiles\web)에서 pnpm approve-builds --all 실행 후 하드 새로고침 |
| 설치 후 사이드바가 두 개 나타남? | 이전에 수동으로 마운트한 라인이 자동 bundle과 이중 마운트됨 | cordis.patch.yml에서 기존의 - insert: ... better-sidebar ... 수동 마운트 라인 제거 |
| 잘못된 환경에 설치함? | --profile로 설치 대상이 결정됨 | 명령의 profile 이름이 원하는 것인지 확인(web / headless 등) |
| 설치했는데 오류 없이 적용되지 않음? | 일반 의존성(dsh.bundle 선언 없음)을 설치했을 수 있음 | 이는 단순히 "패키지 도착" 상태이며, 능력을 연결하려면 cordis.patch.yml에 직접 insert해야 함(mcp-client가 대표적 사례) |
이 장에서 배운 것
아래 항목들을 직접 해낼 수 있으면 합격입니다:
- [ ] 네 가지 플러그인 출처(npm / GitHub / 로컬 디렉터리 / tarball)를 말할 수 있고, 플러그인 마켓은 출처가 아니라 그래픽 진입점임을 설명할 수 있다
- [ ]
dsh plugin --profile <이름>이 특정 profile의 플러그인을 관리하며, 그 profile의node_modules에 설치된다는 것을 안다 - [ ] 구분할 수 있다: dsh 본체는 전역 설치, 플러그인은 profile별,
$DSH_HOME/cordis.patch.yml은 머신 레벨이며 사이트 전체에 적용 - [ ] 세 가지 설치 방법을 안다: 명령행 add / 마켓 원클릭 설치 /
dsh.bundle선언이 있는 의존성의 자동 마운트 - [ ] 세 가지 커뮤니티 플러그인의 용도(dsh-theme 스킨 / dsh-oil-sticky-prompt 고정 프롬프트 바 / dsh-better-sidebar 사이드바 워크벤치)를 말할 수 있고, 직접 설치해 본다
- [ ] bundle 멤버의 변경은 profile 재시작이 필요하다는 것을 알고, 일반 patch 수정은 핫 리로드로 처리됨을 안다
- [ ]
list/remove/update로 플러그인을 관리하고,--dump-config로 설정 트리에 마운트되었는지 확인한다
