플러그인
Dropstone을 확장하기 위한 자신만의 플러그인을 작성하세요.
플러그인을 사용하면 다양한 이벤트에 연결하고 동작을 사용자 정의하여 Dropstone을 확장할 수 있습니다. 새로운 기능을 추가하거나, 외부 서비스와 통합하거나, Dropstone의 기본 동작을 수정하는 플러그인을 만들 수 있습니다.
플러그인 사용하기
플러그인을 로드하는 방법은 두 가지입니다.
로컬 파일에서
플러그인 디렉토리에 JavaScript 또는 TypeScript 파일을 배치합니다.
.dropstone/plugins/- 프로젝트 수준 플러그인~/.config/dropstone/plugins/- 전역 플러그인
이 디렉토리의 파일은 시작 시 자동으로 로드됩니다.
npm에서
설정 파일에서 npm 패키지를 지정합니다.
{
"$schema": "https://dropstone.io/schema/config.json",
"plugin": ["@my-org/internal-plugin", "dropstone-notify-on-idle"]
}
일반 npm 패키지와 스코프가 지정된 npm 패키지 모두 지원됩니다.
플러그인 설치 방법
npm 플러그인은 시작 시 Bun을 사용하여 자동으로 설치됩니다. 패키지와 해당 종속성은 ~/.cache/dropstone/node_modules/에 캐시됩니다.
로컬 플러그인은 플러그인 디렉토리에서 직접 로드됩니다. 외부 패키지를 사용하려면 설정 디렉토리 내에 package.json을 만들어야 합니다(종속성 참조). 또는 플러그인을 npm에 게시하고 설정에 추가할 수 있습니다.
로드 순서
플러그인은 모든 소스에서 로드되고 모든 훅이 순차적으로 실행됩니다. 로드 순서는 다음과 같습니다:
- 전역 설정 (
~/.config/dropstone/dropstone.json) - 프로젝트 설정 (
dropstone.json) - 전역 플러그인 디렉토리 (
~/.config/dropstone/plugins/) - 프로젝트 플러그인 디렉토리 (
.dropstone/plugins/)
같은 이름과 버전의 중복된 npm 패키지는 한 번만 로드됩니다. 그러나 유사한 이름의 로컬 플러그인과 npm 플러그인은 별도로 로드됩니다.
플러그인 만들기
플러그인은 JavaScript/TypeScript 모듈로, 하나 이상의 플러그인 함수를 내보냅니다. 각 함수는 컨텍스트 객체를 받고 훅 객체를 반환합니다.
종속성
로컬 플러그인과 사용자 정의 도구는 외부 npm 패키지를 사용할 수 있습니다. 필요한 종속성과 함께 설정 디렉토리에 package.json을 추가합니다.
{
"dependencies": {
"shescape": "^2.1.0"
}
}
Dropstone은 시작 시 bun install을 실행하여 이를 설치합니다. 플러그인과 도구는 이를 가져올 수 있습니다.
import { escape } from "shescape"
export const MyPlugin = async (ctx) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "bash") {
output.args.command = escape(output.args.command)
}
},
}
}
기본 구조
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
console.log("Plugin initialized!")
return {
// Hook implementations go here
}
}
플러그인 함수는 다음을 받습니다:
project: 현재 프로젝트 정보입니다.directory: 현재 작업 디렉토리입니다.worktree: git worktree 경로입니다.client: 에이전트와 상호작용하기 위한 Dropstone SDK 클라이언트입니다.$: 명령을 실행하기 위한 Bun의 shell API입니다.
TypeScript 지원
TypeScript 플러그인의 경우 플러그인 패키지에서 타입을 가져올 수 있습니다:
import type { Plugin } from "@blankline/dropstone-plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// Type-safe hook implementations
}
}
이벤트
플러그인은 아래 예제 섹션에서 볼 수 있는 이벤트를 구독할 수 있습니다. 다음은 사용 가능한 다양한 이벤트 목록입니다.
명령 이벤트
command.executed
파일 이벤트
file.editedfile.watcher.updated
설치 이벤트
installation.updated
LSP 이벤트
lsp.client.diagnosticslsp.updated
메시지 이벤트
message.part.removedmessage.part.updatedmessage.removedmessage.updated
권한 이벤트
permission.askedpermission.replied
서버 이벤트
server.connected
세션 이벤트
session.createdsession.compactedsession.deletedsession.diffsession.errorsession.idlesession.statussession.updated
Todo 이벤트
todo.updated
Shell 이벤트
shell.env
도구 이벤트
tool.execute.aftertool.execute.before
예제
Dropstone을 확장하는 데 사용할 수 있는 플러그인 예제입니다.
알림 보내기
특정 이벤트가 발생할 때 알림을 보냅니다:
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
return {
event: async ({ event }) => {
// Send notification on session completion
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "dropstone"'`
}
},
}
}
osascript를 사용하여 macOS에서 AppleScript를 실행합니다. 여기서는 이를 사용하여 알림을 보냅니다.
.env 보호
Dropstone이 .env 파일을 읽지 못하도록 방지합니다:
export const EnvProtection = async ({ project, client, $, directory, worktree }) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}
환경 변수 주입
모든 shell 실행(AI 도구 및 사용자 터미널)에 환경 변수를 주입합니다:
export const InjectEnvPlugin = async () => {
return {
"shell.env": async (input, output) => {
output.env.MY_API_KEY = "secret"
output.env.PROJECT_ROOT = input.cwd
},
}
}
사용자 정의 도구
플러그인은 Dropstone에 사용자 정의 도구를 추가할 수도 있습니다:
import { type Plugin, tool } from "@blankline/dropstone-plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "This is a custom tool",
args: {
foo: tool.schema.string(),
},
async execute(args, context) {
const { directory, worktree } = context
return `Hello ${args.foo} from ${directory} (worktree: ${worktree})`
},
}),
},
}
}
tool 헬퍼는 Dropstone이 호출할 수 있는 사용자 정의 도구를 만듭니다. Zod 스키마 함수를 받고 다음을 포함하는 도구 정의를 반환합니다:
description: 도구가 하는 일args: 도구의 인수에 대한 Zod 스키마execute: 도구가 호출될 때 실행되는 함수
사용자 정의 도구는 기본 제공 도구와 함께 Dropstone에서 사용할 수 있습니다.
Note:
플러그인 도구가 기본 제공 도구와 같은 이름을 사용하면 플러그인 도구가 우선합니다.
로깅
console.log 대신 client.app.log()를 사용하여 구조화된 로깅을 수행합니다:
export const MyPlugin = async ({ client }) => {
await client.app.log({
body: {
service: "my-plugin",
level: "info",
message: "Plugin initialized",
extra: { foo: "bar" },
},
})
}
레벨: debug, info, warn, error. 자세한 내용은 SDK 참조를 참조하세요.
압축 훅
세션이 압축될 때 포함되는 컨텍스트를 사용자 정의합니다:
import type { Plugin } from "@blankline/dropstone-plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// Inject additional context into the compaction prompt
output.context.push(`
## Custom Context
Include any state that should persist across compaction:
- Current task status
- Important decisions made
- Files being actively worked on
`)
},
}
}
experimental.session.compacting 훅은 LLM이 연속 요약을 생성하기 전에 실행됩니다. 기본 압축 프롬프트가 놓칠 수 있는 도메인 특정 컨텍스트를 주입하는 데 사용합니다.
output.prompt를 설정하여 압축 프롬프트를 완전히 바꿀 수도 있습니다:
import type { Plugin } from "@blankline/dropstone-plugin"
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// Replace the entire compaction prompt
output.prompt = `
You are generating a continuation prompt for a long-running coding session.
Summarize:
1. The current task and its status
2. Which files are being modified
3. Any blockers or open questions
4. The next steps to complete the work
Format as a structured prompt the next session can use to resume work.
`
},
}
}
output.prompt가 설정되면 기본 압축 프롬프트를 완전히 대체합니다. 이 경우 output.context 배열은 무시됩니다.