Dropstone Docs

プラグイン

独自のプラグインを作成して Dropstone を拡張します。

プラグインを使用すると、様々なイベントにフックして動作をカスタマイズすることで Dropstone を拡張できます。新機能の追加、外部サービスとの統合、または Dropstone のデフォルト動作の変更を行うプラグインを作成できます。


プラグインを使用する

プラグインをロードする方法は 2 つあります。


ローカルファイルから

プラグインディレクトリに 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 パッケージは 1 回だけロードされます。ただし、ローカルプラグインと同様の名前の npm プラグインは両方とも別々にロードされます。


プラグインを作成する

プラグインは JavaScript/TypeScript モジュールで、1 つ以上のプラグイン関数をエクスポートします。各関数はコンテキストオブジェクトを受け取り、フックオブジェクトを返します。


依存関係

ローカルプラグインとカスタムツールは外部 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.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 イベント

  • 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"'`
      }
    },
  }
}

macOS で AppleScript を実行するために osascript を使用しています。ここではそれを使用して通知を送信しています。


.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:

プラグインツールが組み込みツールと同じ名前を使用する場合、プラグインツールが優先されます。


ログ

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" },
    },
  })
}

レベル: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