summaryrefslogtreecommitdiffhomepage
path: root/packages/plugin/src/index.ts
blob: fca176f57e77b93208e5de4e17bb70bf5e0b2516 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import type {
  Event,
  createOpencodeClient,
  Project,
  Model,
  Provider,
  Permission,
  UserMessage,
  Part,
  Auth,
  Config,
} from "@opencode-ai/sdk"
import type { BunShell } from "./shell"

export type PluginInput = {
  client: ReturnType<typeof createOpencodeClient>
  project: Project
  directory: string
  worktree: string
  $: BunShell
  Tool: {
    define(
      id: string,
      init: any | (() => Promise<any>)
    ): any
  }
  z: any // Zod instance for creating schemas
}
export type Plugin = (input: PluginInput) => Promise<Hooks>

// Lightweight schema spec for HTTP-registered tools
export type HttpParamSpec = {
  type: "string" | "number" | "boolean" | "array"
  description?: string
  optional?: boolean
  items?: "string" | "number" | "boolean"
}
export type HttpToolRegistration = {
  id: string
  description: string
  parameters: {
    type: "object"
    properties: Record<string, HttpParamSpec>
  }
  callbackUrl: string
  headers?: Record<string, string>
}

export interface Hooks {
  event?: (input: { event: Event }) => Promise<void>
  config?: (input: Config) => Promise<void>
  auth?: {
    provider: string
    loader?: (auth: () => Promise<Auth>, provider: Provider) => Promise<Record<string, any>>
    methods: (
      | {
          type: "oauth"
          label: string
          authorize(): Promise<
            { url: string; instructions: string } & (
              | {
                  method: "auto"
                  callback(): Promise<
                    | ({
                        type: "success"
                      } & (
                        | {
                            refresh: string
                            access: string
                            expires: number
                          }
                        | { key: string }
                      ))
                    | {
                        type: "failed"
                      }
                  >
                }
              | {
                  method: "code"
                  callback(code: string): Promise<
                    | ({
                        type: "success"
                      } & (
                        | {
                            refresh: string
                            access: string
                            expires: number
                          }
                        | { key: string }
                      ))
                    | {
                        type: "failed"
                      }
                  >
                }
            )
          >
        }
      | { type: "api"; label: string }
    )[]
  }
  /**
   * Called when a new message is received
   */
  "chat.message"?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
  /**
   * Modify parameters sent to LLM
   */
  "chat.params"?: (
    input: { model: Model; provider: Provider; message: UserMessage },
    output: { temperature: number; topP: number; options: Record<string, any> },
  ) => Promise<void>
  "permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
  "tool.execute.before"?: (
    input: { tool: string; sessionID: string; callID: string },
    output: { args: any },
  ) => Promise<void>
  "tool.execute.after"?: (
    input: { tool: string; sessionID: string; callID: string },
    output: {
      title: string
      output: string
      metadata: any
    },
  ) => Promise<void>
  /**
   * Allow plugins to register additional tools with the server.
   * Use registerHTTP to add a tool that calls back to your plugin/service.
   * Use register to add a native/local tool with direct function execution.
   */
  "tool.register"?: (
    input: {},
    output: {
      registerHTTP: (tool: HttpToolRegistration) => void | Promise<void>
      register: (tool: any) => void | Promise<void>  // Tool.Info type from opencode
    },
  ) => Promise<void>
}