플러그지 패키징 및 설치
이전 튜토리얼에서는 --patch 오버레이를 통해 로컬 플러그인을 로드했습니다. 이 튜토리얼에서는 이를 설치 가능한 번들로 패키징하고, dsh plugin add를 사용하여 프로필 에 설치하며, 구성된 설정을 결정하는 계층 순서를 설명합니다. dsh CLI가 설치되어 있다고 가정합니다. 먼저 플러그인 구성을 완료하세요.
대신 새 소스 체크아웃을 사용하려면 소스에서 실행 섹션을 완료하고, 이 튜토리얼의 hello-plugin 디렉터리를 저장소 루트에 유지한 다음, 나머지 dsh ... 명령을 그 위치에서 pnpm dsh ...로 실행하세요. 빌드 및 런처 동작은 소스 실행을 참조하세요.
두 가지 개념, 두 가지 매니페스트
설치는 두 가지 개념을 기반으로 합니다. 둘 다 package.json로 설명되지만, dsh 키 아래에 서로 다른 종류의 매니페스트를 가지며 서로 다른 질문에 답합니다.
- 번들 은 구성 계층을 제공하는 npm 패키지입니다. 매니페스트에서
dsh.bundle를 선언하여 “이 패키지는 무엇을 제공하는가?”에 답합니다. 즉, 플러그인 행을 삽입하거나 재정의하는 패치 파일입니다. - 프로필 은 하나의 실행 가능한 구성을 설명하는
$DSH_HOME/profiles/<name>아래의 디렉터리입니다. 매니페스트에서dsh.profile를 선언하여 “어떤 번들이 이 설정을 어떤 순서로 구성하는가?”에 답합니다.
번들은 작성하고 배포하는 대상이며, 프로필은 사용자가 dsh --profile <name>로 부팅하는 대상입니다. 둘을 겸하는 것은 없습니다.
번들 매니페스트
패키지 디렉터리를 만드세요.
mkdir -p hello-pluginhello-plugin/
├── package.json # declares dsh.bundle
├── cordis.patch.yml # the layer applied when a profile lists this bundle
└── index.js # plugin modules the patch rows referencehello-plugin/package.json를 만드세요.
{
"name": "dsh-hello-plugin",
"version": "0.1.0",
"type": "module",
"main": "index.js",
"files": ["index.js", "cordis.patch.yml"],
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}플러그인 진입점이 포함된 hello-plugin/index.js를 만드세요.
export const name = 'hello-plugin'
export function apply() {
console.log('[hello-plugin] plugin loaded!')
}hello-plugin/cordis.patch.yml를 만드세요. 패치는 작성해 온 --patch 오버레이와 같은 YAML 배열이지만, Node 해석이 설치된 코드를 찾을 수 있도록 플러그인 행에서는 상대 소스 경로 대신 패키지 이름을 참조합니다.
- insert:
- id: hello
name: dsh-hello-plugindsh.bundle 선언이 없는 패키지도 설치되지만 일반 의존성으로만 설치됩니다. dsh plugin는 경고를 출력하고 어떤 계층도 활성화하지 않습니다. 플러그인 사용자가 활성화하는 패키지가 아니라 플러그인 패키지가 가져오는 라이브러리에는 이 패키지 형식을 사용하세요.
프로필 매니페스트
프로필 디렉터리에는 두 파일이 있습니다.
package.json— 프로필의 트리 외부 플러그인 의존성(pnpm에서 관리)과 정렬된bundles목록이 포함된dsh.profile매니페스트입니다.cordis.patch.yml— 모든 번들 계층 뒤에 적용되는 사용자의 자체 패치 계층입니다.
프로필 매니페스트를 직접 작성할 필요는 없습니다. dsh plugin가 이를 만들고 유지 관리합니다. 다음 섹션에서 결과를 보여 줍니다.
프로필에 설치
dsh plugin --profile <name> <args...>는 프로필 디렉터리에서 pnpm으로 전달하므로 모든 pnpm 동사를 사용할 수 있습니다. hello-plugin를 포함하는 디렉터리에서 패키지 체크아웃을 설치하세요.
dsh plugin --profile demo add ./hello-plugin처음 사용하면 프로필이 초기화되고(첫 번째 번들로 @deepseek-ai/dsh-base 사용), pnpm이 체크아웃을 연결하며, 패키지가 dsh.bundle를 선언하므로 dsh가 번들을 dsh.profile.bundles에 추가합니다.
{
"name": "dsh-profile-demo",
"private": true,
"dependencies": {
"dsh-hello-plugin": "link:/path/to/hello-plugin"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"dsh-hello-plugin"
]
}
}
}부팅하기 전에 계층을 확인한 다음 부팅하세요.
dsh --profile demo --dump-config # shows a "# == dsh-hello-plugin" layer
dsh --profile demodsh plugin --profile demo remove dsh-hello-plugin는 의존성과 계층을 모두 제거합니다.
로드 순서
유효 구성은 빈 루트에 다음을 순서대로 적용하여 구성됩니다.
- 프로필의
dsh.profile.bundles목록에 이름이 지정된 각 번들 패치(목록 순서대로) — 먼저@deepseek-ai/dsh-base, 그다음 추가된 순서대로 설치된 각 번들입니다. - 프로필 자체의
cordis.patch.yml입니다. - 홈 수준의
$DSH_HOME/cordis.patch.yml— 모든 프로필이 공유하는 머신 로컬 기본 설정입니다. - argv 순서에 따른 각
--patch <path>오버레이입니다.
앱 인수는 또 다른 패치 계층이 아닙니다. 표면 번들은 아래에 설명된 일반 앱 소유 서비스를 통해 이를 해석할 수 있습니다.
나중 계층이 행별로 우선하며, 패치는 키를 깊이 병합하는 대신 행 전체의 config 값을 교체합니다. 번들 작성자에게는 두 가지 결과가 있습니다.
- 패치는
id를 통해 이전 계층의 행을 재정의할 수 있습니다.dsh-web-app번들이dsh-base행을 재정의하는 방식과 같지만, 변경된 키뿐 아니라 행에 필요한 모든 키를 다시 명시해야 합니다. - 사용자는 패키지를 건드리지 않고 프로필의
cordis.patch.yml에서 행을 재정의할 수 있으므로, 사용자가 유지할 가능성이 높은 구성 기본값을 선호하고 나머지는 스키마가 담당하게 하세요.
내장 번들 이름은 항상 dsh 설치 자체에서 해석됩니다. pnpm은 트리 외부 패키지만 관리하므로 번들은 @deepseek-ai/dsh-base가 존재하며 최신 상태임을 전제로 할 수 있습니다.
표면 번들에 자체 명령줄 제공
실행 가능한 앱을 정의하는 번들은 일반 공급자 플러그인을 마운트합니다.
- id: hello-startup
name: 'dsh-hello-plugin/startup'플러그인은 inject = ['cmdlineArgs']를 내보내고, 자체 commander 프로그램으로 @deepseek-ai/dsh-cmdline의 parseCmdline를 호출하며, 프로그램의 action에서 앱 소유 서비스를 제공합니다. 런처는 런처 플래그 뒤의 동일한 불변 인수를 모든 플러그인에 전달하므로, 앱별 플래그는 런처 변경이 필요 없고 여러 플러그인이 스냅샷을 파싱할 수 있습니다. Loader 행에는 런처 마커나 특수 종류가 필요하지 않습니다.
이러한 인수로 구성된 행은 공급자의 서비스를 주입하고 자체 !!js 옵션에서 이를 읽으며, 그 옆의 배포 값을 대체 값으로 사용합니다.
- id: my-app
name: '@example/my-app'
inject: [myAppStartup]
config:
port: !!js ctx.myAppStartup.port ?? 8080--help에서는 공급자가 서비스를 게시하지 않으므로 해당 행은 활성화되지 않습니다. Loader는 구성을 한 번 마운트하고 각 행의 일반 주입을 기다린 후에만 해당 행의 !!js 구성을 주입된 컨텍스트에 대해 평가합니다.
GitHub에서 설치: 빌드 스크립트 주의점
레지스트리에 게시할 필요는 없습니다. 사용자는 git 호스트에서 직접 설치할 수 있습니다.
dsh plugin --profile demo add github:you/hello-plugin하지만 git 설치는 빌드된 아티팩트가 아닌 소스를 가져옵니다. build 스크립트는 실행되지 않으므로 TypeScript 패키지는 lib/ 출력 없이 도착하여 로드에 실패합니다. 양쪽에서 각각 한 가지씩, 두 가지가 수행되어야 합니다.
작성자 는 git 설치 후 pnpm이 실행하는
prepare스크립트를 제공해야 합니다. 이 스크립트는 소스에서 게시된 진입점을 자체적으로 빌드해야 하며, 인접한 모노레포 체크아웃과 같은 개발 전용 컨텍스트를 가정해서는 안 됩니다. turtle-ui가 작동하는 예입니다. 이 패키지의prepare는 프로젝트 참조나 형식 검사 없이src/를 트랜스파일하는 전용 tsdown 구성을 실행합니다.사용자 는 빌드를 허용 목록에 추가합니다. pnpm ≥10은 명시적으로 허용되기 전까지 git 의존성의
prepare스크립트 실행을 거부하므로 첫 번째add가 실패합니다.dsh가 해결 방법을 안내합니다. pnpm이 출력한 정확한 패키지 키를 프로필의pnpm-workspace.yaml에 복사하세요.yamlallowBuilds: dsh-hello-plugin: true그런 다음
add를 다시 실행하세요.
이 권한의 의미를 분명히 이해해야 합니다. 즉, 설치 시점에 머신에서 패키지의 코드를 실행할 수 있는 권한이며, 에이전트가 실행되는 모든 샌드박스 외부에서 이루어집니다. 소스를 신뢰할 수 있는 패키지만 허용하고 커밋(github:you/hello-plugin#<sha>)을 고정하여 이후 푸시로 실행되는 내용이 조용히 변경되지 않도록 하세요.
사용자에게 이 권한을 요청하지 않으려면 빌드된 아티팩트를 대신 배포하세요. 어느 방식도 빌드 권한이 필요하지 않습니다.
- npm에 게시 :
lib/을(를)pnpm publish시점에 빌드하면dsh plugin add your-package이(가) 사전 빌드된 코드를 설치합니다. - tarball 배포 :
pnpm pack에서 배포하며, 사용자는dsh plugin add ./hello-plugin-0.1.0.tgz을(를) 실행합니다.
다음 단계
- 플러그인 및 수명 주기 — 전체 플러그인 수명 주기
- CLI 동작 참조 — 정확한 계층 우선순위, 플래그 및 프로필 메커니즘