Dropstone Docs

外掛程式

編寫自己的外掛程式以擴展 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 外掛程式在啟動時使用 Bun 自動安裝。套件及其相依性會快取在 ~/.cache/dropstone/node_modules/ 中。

本機外掛程式直接從外掛程式目錄載入。若要使用外部套件,您必須在設定目錄中建立 package.json(請參閱相依性),或將外掛程式發佈到 npm 並將其新增到您的設定


載入順序

外掛程式從所有來源載入,所有掛接按順序執行。載入順序為:

  1. 全域設定(~/.config/dropstone/dropstone.json
  2. 專案設定(dropstone.json
  3. 全域外掛程式目錄(~/.config/dropstone/plugins/
  4. 專案外掛程式目錄(.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 的殼層 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.edited
  • file.watcher.updated

安裝事件

  • installation.updated

LSP 事件

  • lsp.client.diagnostics
  • lsp.updated

訊息事件

  • message.part.removed
  • message.part.updated
  • message.removed
  • message.updated

權限事件

  • permission.asked
  • permission.replied

伺服器事件

  • server.connected

工作階段事件

  • session.created
  • session.compacted
  • session.deleted
  • session.diff
  • session.error
  • session.idle
  • session.status
  • session.updated

待辦事項事件

  • todo.updated

殼層事件

  • shell.env

工具事件

  • tool.execute.after
  • tool.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")
      }
    },
  }
}

注入環境變數

將環境變數注入所有殼層執行(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:

如果外掛程式工具使用與內建工具相同的名稱,外掛程式工具優先。


記錄

使用 client.app.log() 而不是 console.log 進行結構化記錄:

export const MyPlugin = async ({ client }) => {
  await client.app.log({
    body: {
      service: "my-plugin",
      level: "info",
      message: "Plugin initialized",
      extra: { foo: "bar" },
    },
  })
}

層級:debuginfowarnerror。詳見 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 陣列會被忽略。

Ctrl+I