opencode-cursor-proxy 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/README.zh-CN.md +136 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +2 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/api/agent-service.d.ts +136 -0
  8. package/dist/lib/api/agent-service.js +938 -0
  9. package/dist/lib/api/agent-service.js.map +1 -0
  10. package/dist/lib/api/ai-service.d.ts +26 -0
  11. package/dist/lib/api/ai-service.js +38 -0
  12. package/dist/lib/api/ai-service.js.map +1 -0
  13. package/dist/lib/api/cursor-client.d.ts +119 -0
  14. package/dist/lib/api/cursor-client.js +511 -0
  15. package/dist/lib/api/cursor-client.js.map +1 -0
  16. package/dist/lib/api/cursor-models.d.ts +13 -0
  17. package/dist/lib/api/cursor-models.js +34 -0
  18. package/dist/lib/api/cursor-models.js.map +1 -0
  19. package/dist/lib/api/openai-compat.d.ts +10 -0
  20. package/dist/lib/api/openai-compat.js +262 -0
  21. package/dist/lib/api/openai-compat.js.map +1 -0
  22. package/dist/lib/api/proto/agent-messages.d.ts +25 -0
  23. package/dist/lib/api/proto/agent-messages.js +132 -0
  24. package/dist/lib/api/proto/agent-messages.js.map +1 -0
  25. package/dist/lib/api/proto/bidi.d.ts +17 -0
  26. package/dist/lib/api/proto/bidi.js +24 -0
  27. package/dist/lib/api/proto/bidi.js.map +1 -0
  28. package/dist/lib/api/proto/decoding.d.ts +19 -0
  29. package/dist/lib/api/proto/decoding.js +118 -0
  30. package/dist/lib/api/proto/decoding.js.map +1 -0
  31. package/dist/lib/api/proto/encoding.d.ts +64 -0
  32. package/dist/lib/api/proto/encoding.js +180 -0
  33. package/dist/lib/api/proto/encoding.js.map +1 -0
  34. package/dist/lib/api/proto/exec.d.ts +12 -0
  35. package/dist/lib/api/proto/exec.js +383 -0
  36. package/dist/lib/api/proto/exec.js.map +1 -0
  37. package/dist/lib/api/proto/index.d.ts +13 -0
  38. package/dist/lib/api/proto/index.js +10 -0
  39. package/dist/lib/api/proto/index.js.map +1 -0
  40. package/dist/lib/api/proto/interaction.d.ts +15 -0
  41. package/dist/lib/api/proto/interaction.js +99 -0
  42. package/dist/lib/api/proto/interaction.js.map +1 -0
  43. package/dist/lib/api/proto/kv.d.ts +52 -0
  44. package/dist/lib/api/proto/kv.js +156 -0
  45. package/dist/lib/api/proto/kv.js.map +1 -0
  46. package/dist/lib/api/proto/tool-calls.d.ts +9 -0
  47. package/dist/lib/api/proto/tool-calls.js +144 -0
  48. package/dist/lib/api/proto/tool-calls.js.map +1 -0
  49. package/dist/lib/api/proto/types.d.ts +201 -0
  50. package/dist/lib/api/proto/types.js +10 -0
  51. package/dist/lib/api/proto/types.js.map +1 -0
  52. package/dist/lib/auth/helpers.d.ts +40 -0
  53. package/dist/lib/auth/helpers.js +103 -0
  54. package/dist/lib/auth/helpers.js.map +1 -0
  55. package/dist/lib/auth/index.d.ts +7 -0
  56. package/dist/lib/auth/index.js +10 -0
  57. package/dist/lib/auth/index.js.map +1 -0
  58. package/dist/lib/auth/login.d.ts +55 -0
  59. package/dist/lib/auth/login.js +184 -0
  60. package/dist/lib/auth/login.js.map +1 -0
  61. package/dist/lib/config.d.ts +153 -0
  62. package/dist/lib/config.js +182 -0
  63. package/dist/lib/config.js.map +1 -0
  64. package/dist/lib/openai-compat/handler.d.ts +40 -0
  65. package/dist/lib/openai-compat/handler.js +808 -0
  66. package/dist/lib/openai-compat/handler.js.map +1 -0
  67. package/dist/lib/openai-compat/index.d.ts +9 -0
  68. package/dist/lib/openai-compat/index.js +13 -0
  69. package/dist/lib/openai-compat/index.js.map +1 -0
  70. package/dist/lib/openai-compat/types.d.ts +127 -0
  71. package/dist/lib/openai-compat/types.js +6 -0
  72. package/dist/lib/openai-compat/types.js.map +1 -0
  73. package/dist/lib/openai-compat/utils.d.ts +143 -0
  74. package/dist/lib/openai-compat/utils.js +348 -0
  75. package/dist/lib/openai-compat/utils.js.map +1 -0
  76. package/dist/lib/session-reuse.d.ts +88 -0
  77. package/dist/lib/session-reuse.js +198 -0
  78. package/dist/lib/session-reuse.js.map +1 -0
  79. package/dist/lib/storage.d.ts +55 -0
  80. package/dist/lib/storage.js +159 -0
  81. package/dist/lib/storage.js.map +1 -0
  82. package/dist/lib/utils/cache.d.ts +131 -0
  83. package/dist/lib/utils/cache.js +297 -0
  84. package/dist/lib/utils/cache.js.map +1 -0
  85. package/dist/lib/utils/fetch.d.ts +84 -0
  86. package/dist/lib/utils/fetch.js +261 -0
  87. package/dist/lib/utils/fetch.js.map +1 -0
  88. package/dist/lib/utils/index.d.ts +13 -0
  89. package/dist/lib/utils/index.js +22 -0
  90. package/dist/lib/utils/index.js.map +1 -0
  91. package/dist/lib/utils/jwt.d.ts +40 -0
  92. package/dist/lib/utils/jwt.js +102 -0
  93. package/dist/lib/utils/jwt.js.map +1 -0
  94. package/dist/lib/utils/logger.d.ts +107 -0
  95. package/dist/lib/utils/logger.js +227 -0
  96. package/dist/lib/utils/logger.js.map +1 -0
  97. package/dist/lib/utils/model-resolver.d.ts +49 -0
  98. package/dist/lib/utils/model-resolver.js +503 -0
  99. package/dist/lib/utils/model-resolver.js.map +1 -0
  100. package/dist/lib/utils/request-pool.d.ts +38 -0
  101. package/dist/lib/utils/request-pool.js +105 -0
  102. package/dist/lib/utils/request-pool.js.map +1 -0
  103. package/dist/lib/utils/request-transformer.d.ts +87 -0
  104. package/dist/lib/utils/request-transformer.js +154 -0
  105. package/dist/lib/utils/request-transformer.js.map +1 -0
  106. package/dist/lib/utils/tokenizer.d.ts +14 -0
  107. package/dist/lib/utils/tokenizer.js +76 -0
  108. package/dist/lib/utils/tokenizer.js.map +1 -0
  109. package/dist/plugin/index.d.ts +8 -0
  110. package/dist/plugin/index.js +9 -0
  111. package/dist/plugin/index.js.map +1 -0
  112. package/dist/plugin/plugin.d.ts +21 -0
  113. package/dist/plugin/plugin.js +309 -0
  114. package/dist/plugin/plugin.js.map +1 -0
  115. package/dist/plugin/types.d.ts +120 -0
  116. package/dist/plugin/types.js +7 -0
  117. package/dist/plugin/types.js.map +1 -0
  118. package/dist/server.d.ts +15 -0
  119. package/dist/server.js +95 -0
  120. package/dist/server.js.map +1 -0
  121. package/package.json +79 -0
@@ -0,0 +1,309 @@
1
+ /**
2
+ * OpenCode Cursor Auth Plugin
3
+ *
4
+ * An OpenCode plugin that provides OAuth authentication for Cursor's AI backend,
5
+ * following the architecture established by opencode-gemini-auth.
6
+ *
7
+ * This plugin uses a custom fetch function to intercept OpenAI API requests
8
+ * and route them through Cursor's Agent API.
9
+ */
10
+ import { ModelInfoMap } from "llm-info";
11
+ import { LoginManager, CURSOR_API_BASE_URL, openBrowser, } from "../lib/auth/login";
12
+ import { CursorClient } from "../lib/api/cursor-client";
13
+ import { listCursorModels } from "../lib/api/cursor-models";
14
+ import { decodeJwtPayload } from "../lib/utils/jwt";
15
+ import { refreshAccessToken } from "../lib/auth/helpers";
16
+ import { createPluginFetch } from "../lib/openai-compat";
17
+ // --- Constants ---
18
+ export const CURSOR_PROVIDER_ID = "cursor";
19
+ const CURSOR_TO_LLM_INFO_MAP = {
20
+ "sonnet-4.5": "claude-sonnet-4-5-20250929",
21
+ "sonnet-4.5-thinking": "claude-sonnet-4-5-20250929",
22
+ "opus-4.5": "claude-opus-4-5-20251101",
23
+ "opus-4.5-thinking": "claude-opus-4-5-20251101",
24
+ "opus-4.1": "claude-opus-4-1-20250805",
25
+ "gemini-3-pro": "gemini-3-pro-preview",
26
+ "gemini-3-flash": "gemini-2.5-flash",
27
+ "gpt-5.2": "gpt-5.2",
28
+ "gpt-5.2-high": "gpt-5.2",
29
+ "gpt-5.1": "gpt-5",
30
+ "gpt-5.1-high": "gpt-5",
31
+ "gpt-5.1-codex": "gpt-5",
32
+ "gpt-5.1-codex-high": "gpt-5",
33
+ "gpt-5.1-codex-max": "gpt-5",
34
+ "gpt-5.1-codex-max-high": "gpt-5",
35
+ "grok": "grok-4",
36
+ };
37
+ const DEFAULT_LIMITS = { context: 128000, output: 16384 };
38
+ function getModelLimits(cursorModelId) {
39
+ const llmInfoId = CURSOR_TO_LLM_INFO_MAP[cursorModelId];
40
+ if (!llmInfoId)
41
+ return DEFAULT_LIMITS;
42
+ const info = ModelInfoMap[llmInfoId];
43
+ if (!info)
44
+ return DEFAULT_LIMITS;
45
+ return {
46
+ context: info.contextWindowTokenLimit ?? DEFAULT_LIMITS.context,
47
+ output: info.outputTokenLimit ?? DEFAULT_LIMITS.output,
48
+ };
49
+ }
50
+ // --- Auth Helpers ---
51
+ /**
52
+ * Check if auth details are OAuth type
53
+ */
54
+ function isOAuthAuth(auth) {
55
+ return auth.type === "oauth";
56
+ }
57
+ /**
58
+ * Check if access token has expired or is missing
59
+ */
60
+ function accessTokenExpired(auth) {
61
+ if (!auth.access || typeof auth.expires !== "number") {
62
+ return true;
63
+ }
64
+ // Add 60 second buffer
65
+ return auth.expires <= Date.now() + 60 * 1000;
66
+ }
67
+ /**
68
+ * Parse stored refresh token parts (format: "refreshToken|apiKey")
69
+ */
70
+ function parseRefreshParts(refresh) {
71
+ const [refreshToken = "", apiKey = ""] = (refresh ?? "").split("|");
72
+ return {
73
+ refreshToken,
74
+ apiKey: apiKey || undefined,
75
+ };
76
+ }
77
+ /**
78
+ * Format refresh token parts for storage
79
+ */
80
+ function formatRefreshParts(refreshToken, apiKey) {
81
+ return apiKey ? `${refreshToken}|${apiKey}` : refreshToken;
82
+ }
83
+ /**
84
+ * Refresh an access token using the refresh token
85
+ */
86
+ async function refreshCursorAccessToken(auth, client) {
87
+ const parts = parseRefreshParts(auth.refresh);
88
+ if (!parts.refreshToken) {
89
+ return undefined;
90
+ }
91
+ try {
92
+ const result = await refreshAccessToken(parts.refreshToken, CURSOR_API_BASE_URL);
93
+ if (!result) {
94
+ return undefined;
95
+ }
96
+ const updatedAuth = {
97
+ type: "oauth",
98
+ refresh: formatRefreshParts(result.refreshToken, parts.apiKey),
99
+ access: result.accessToken,
100
+ expires: Date.now() + 3600 * 1000, // 1 hour default
101
+ };
102
+ // Try to get actual expiration from token
103
+ const payload = decodeJwtPayload(result.accessToken);
104
+ if (payload?.exp && typeof payload.exp === "number") {
105
+ updatedAuth.expires = payload.exp * 1000;
106
+ }
107
+ // Persist the updated auth
108
+ try {
109
+ await client.auth.set({
110
+ path: { id: CURSOR_PROVIDER_ID },
111
+ body: updatedAuth,
112
+ });
113
+ }
114
+ catch (e) {
115
+ console.error("Failed to persist refreshed Cursor credentials:", e);
116
+ }
117
+ return updatedAuth;
118
+ }
119
+ catch (error) {
120
+ console.error("Failed to refresh Cursor access token:", error);
121
+ return undefined;
122
+ }
123
+ }
124
+ // --- Main Plugin ---
125
+ /**
126
+ * Cursor OAuth Plugin for OpenCode
127
+ *
128
+ * Provides authentication for Cursor's AI backend using:
129
+ * - Browser-based OAuth flow with PKCE
130
+ * - API key authentication
131
+ * - Automatic token refresh
132
+ * - Custom fetch function (no proxy server needed)
133
+ */
134
+ export const CursorOAuthPlugin = async ({ client, }) => ({
135
+ auth: {
136
+ provider: CURSOR_PROVIDER_ID,
137
+ loader: async (getAuth, providerArg) => {
138
+ const auth = await getAuth();
139
+ if (!isOAuthAuth(auth)) {
140
+ return null;
141
+ }
142
+ // Refresh token if needed
143
+ let authRecord = auth;
144
+ if (accessTokenExpired(authRecord)) {
145
+ const refreshed = await refreshCursorAccessToken(authRecord, client);
146
+ if (refreshed) {
147
+ authRecord = refreshed;
148
+ }
149
+ }
150
+ const accessToken = authRecord.access;
151
+ if (!accessToken) {
152
+ return null;
153
+ }
154
+ // Ensure provider and provider.models exist
155
+ const provider = providerArg ?? {};
156
+ provider.models = provider.models ?? {};
157
+ // Set model costs to 0 (Cursor handles billing)
158
+ for (const model of Object.values(provider.models)) {
159
+ if (model) {
160
+ model.cost = { input: 0, output: 0 };
161
+ }
162
+ }
163
+ // Dynamically populate provider models from Cursor API if available.
164
+ try {
165
+ const cursorClient = new CursorClient(accessToken);
166
+ const models = await listCursorModels(cursorClient);
167
+ if (models.length > 0) {
168
+ for (const m of models) {
169
+ // Determine if this is a "thinking" (reasoning) model
170
+ const isThinking = m.modelId?.includes("thinking") ||
171
+ m.displayModelId?.includes("thinking") ||
172
+ m.displayName?.toLowerCase().includes("thinking");
173
+ // Use displayModelId as the primary ID (user-facing), fall back to modelId
174
+ const modelID = m.displayModelId || m.modelId;
175
+ if (!modelID)
176
+ continue;
177
+ const existingModel = provider.models[modelID];
178
+ const limits = getModelLimits(modelID);
179
+ const parsedModel = {
180
+ id: modelID,
181
+ api: {
182
+ id: modelID,
183
+ npm: "@ai-sdk/openai-compatible",
184
+ url: undefined,
185
+ },
186
+ status: "active",
187
+ name: m.displayName || m.displayNameShort || modelID,
188
+ providerID: CURSOR_PROVIDER_ID,
189
+ capabilities: {
190
+ temperature: true,
191
+ reasoning: isThinking,
192
+ attachment: true,
193
+ toolcall: true,
194
+ input: {
195
+ text: true,
196
+ audio: false,
197
+ image: true,
198
+ video: false,
199
+ pdf: false,
200
+ },
201
+ output: {
202
+ text: true,
203
+ audio: false,
204
+ image: false,
205
+ video: false,
206
+ pdf: false,
207
+ },
208
+ interleaved: false,
209
+ },
210
+ cost: {
211
+ input: 0,
212
+ output: 0,
213
+ cache: {
214
+ read: 0,
215
+ write: 0,
216
+ },
217
+ },
218
+ options: {},
219
+ limit: limits,
220
+ headers: {},
221
+ ...existingModel,
222
+ };
223
+ provider.models[modelID] = parsedModel;
224
+ }
225
+ }
226
+ }
227
+ catch (error) {
228
+ // Silently continue with defaults if model listing fails
229
+ }
230
+ // Create custom fetch function instead of starting proxy server
231
+ const customFetch = createPluginFetch({
232
+ accessToken,
233
+ // Disable logging to avoid polluting the UI
234
+ log: () => { },
235
+ });
236
+ // We need to provide baseURL even when using custom fetch
237
+ // OpenCode uses baseURL to identify the provider/API for the model
238
+ // The actual URL doesn't matter since our fetch intercepts everything
239
+ return {
240
+ apiKey: "cursor-via-opencode", // Dummy key, not used
241
+ baseURL: "https://cursor.opencode.local/v1", // Virtual URL, intercepted by fetch
242
+ fetch: customFetch,
243
+ };
244
+ },
245
+ methods: [
246
+ {
247
+ label: "OAuth with Cursor",
248
+ type: "oauth",
249
+ authorize: async (_inputs) => {
250
+ console.log("\n=== Cursor OAuth Setup ===");
251
+ console.log("1. You'll be asked to sign in to your Cursor account.");
252
+ console.log("2. After signing in, the authentication will complete automatically.");
253
+ console.log("3. Return to this terminal when you see confirmation.\n");
254
+ const loginManager = new LoginManager();
255
+ const { metadata, loginUrl } = loginManager.startLogin();
256
+ return {
257
+ url: loginUrl,
258
+ instructions: "Complete the sign-in flow in your browser. We'll automatically detect when you're done.",
259
+ method: "auto",
260
+ callback: async () => {
261
+ try {
262
+ // Open browser
263
+ try {
264
+ await openBrowser(loginUrl);
265
+ }
266
+ catch {
267
+ console.log("Could not open browser automatically. Please visit the URL above.");
268
+ }
269
+ // Wait for authentication
270
+ const result = await loginManager.waitForResult(metadata, {
271
+ onProgress: () => process.stdout.write("."),
272
+ });
273
+ if (!result) {
274
+ return {
275
+ type: "failed",
276
+ error: "Authentication timed out or was cancelled",
277
+ };
278
+ }
279
+ // Get token expiration
280
+ let expires = Date.now() + 3600 * 1000; // 1 hour default
281
+ const payload = decodeJwtPayload(result.accessToken);
282
+ if (payload?.exp && typeof payload.exp === "number") {
283
+ expires = payload.exp * 1000;
284
+ }
285
+ return {
286
+ type: "success",
287
+ refresh: result.refreshToken,
288
+ access: result.accessToken,
289
+ expires,
290
+ };
291
+ }
292
+ catch (error) {
293
+ return {
294
+ type: "failed",
295
+ error: error instanceof Error ? error.message : "Unknown error",
296
+ };
297
+ }
298
+ },
299
+ };
300
+ },
301
+ },
302
+ {
303
+ label: "Manually enter API Key",
304
+ type: "api",
305
+ },
306
+ ],
307
+ },
308
+ });
309
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAYzD,oBAAoB;AAEpB,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,MAAM,sBAAsB,GAA2B;IACrD,YAAY,EAAE,4BAA4B;IAC1C,qBAAqB,EAAE,4BAA4B;IACnD,UAAU,EAAE,0BAA0B;IACtC,mBAAmB,EAAE,0BAA0B;IAC/C,UAAU,EAAE,0BAA0B;IACtC,cAAc,EAAE,sBAAsB;IACtC,gBAAgB,EAAE,kBAAkB;IACpC,SAAS,EAAE,SAAS;IACpB,cAAc,EAAE,SAAS;IACzB,SAAS,EAAE,OAAO;IAClB,cAAc,EAAE,OAAO;IACvB,eAAe,EAAE,OAAO;IACxB,oBAAoB,EAAE,OAAO;IAC7B,mBAAmB,EAAE,OAAO;IAC5B,wBAAwB,EAAE,OAAO;IACjC,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF,MAAM,cAAc,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAE1D,SAAS,cAAc,CAAC,aAAqB;IAC3C,MAAM,SAAS,GAAG,sBAAsB,CAAC,aAAa,CAAC,CAAC;IACxD,IAAI,CAAC,SAAS;QAAE,OAAO,cAAc,CAAC;IAEtC,MAAM,IAAI,GAAI,YAAgG,CAAC,SAAS,CAAC,CAAC;IAC1H,IAAI,CAAC,IAAI;QAAE,OAAO,cAAc,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,uBAAuB,IAAI,cAAc,CAAC,OAAO;QAC/D,MAAM,EAAE,IAAI,CAAC,gBAAgB,IAAI,cAAc,CAAC,MAAM;KACvD,CAAC;AACJ,CAAC;AAED,uBAAuB;AAEvB;;GAEG;AACH,SAAS,WAAW,CAAC,IAAiB;IACpC,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,IAAsB;IAChD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,uBAAuB;IACvB,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,OAAe;IAIxC,MAAM,CAAC,YAAY,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpE,OAAO;QACL,YAAY;QACZ,MAAM,EAAE,MAAM,IAAI,SAAS;KAC5B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,YAAoB,EAAE,MAAe;IAC/D,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,YAAY,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;AAC7D,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,wBAAwB,CACrC,IAAsB,EACtB,MAA+B;IAE/B,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,KAAK,CAAC,YAAY,EAClB,mBAAmB,CACpB,CAAC;QAEF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,WAAW,GAAqB;YACpC,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC;YAC9D,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,iBAAiB;SACrD,CAAC;QAEF,0CAA0C;QAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACrD,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACpD,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;QAC3C,CAAC;QAED,2BAA2B;QAC3B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;gBACpB,IAAI,EAAE,EAAE,EAAE,EAAE,kBAAkB,EAAE;gBAChC,IAAI,EAAE,WAAW;aAClB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;QAC/D,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,sBAAsB;AAEtB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,EACtC,MAAM,GACQ,EAAyB,EAAE,CAAC,CAAC;IAC3C,IAAI,EAAE;QACJ,QAAQ,EAAE,kBAAkB;QAE5B,MAAM,EAAE,KAAK,EACX,OAAgB,EAChB,WAAqB,EACS,EAAE;YAChC,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC;YAE7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,0BAA0B;YAC1B,IAAI,UAAU,GAAG,IAAI,CAAC;YACtB,IAAI,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC;gBACnC,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;gBACrE,IAAI,SAAS,EAAE,CAAC;oBACd,UAAU,GAAG,SAAS,CAAC;gBACzB,CAAC;YACH,CAAC;YAED,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC;YACtC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,4CAA4C;YAC5C,MAAM,QAAQ,GAAG,WAAW,IAAK,EAAe,CAAC;YACjD,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC;YAExC,gDAAgD;YAChD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnD,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;gBACvC,CAAC;YACH,CAAC;YAED,qEAAqE;YACrE,IAAI,CAAC;gBACH,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC;gBACnD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;gBACpD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;wBACvB,sDAAsD;wBACtD,MAAM,UAAU,GACd,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC;4BAC/B,CAAC,CAAC,cAAc,EAAE,QAAQ,CAAC,UAAU,CAAC;4BACtC,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;wBAEpD,2EAA2E;wBAC3E,MAAM,OAAO,GAAG,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,OAAO,CAAC;wBAC9C,IAAI,CAAC,OAAO;4BAAE,SAAS;wBAEvB,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;wBAC/C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;wBAEvC,MAAM,WAAW,GAAG;4BAClB,EAAE,EAAE,OAAO;4BACX,GAAG,EAAE;gCACH,EAAE,EAAE,OAAO;gCACX,GAAG,EAAE,2BAA2B;gCAChC,GAAG,EAAE,SAAS;6BACf;4BACD,MAAM,EAAE,QAAiB;4BACzB,IAAI,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,gBAAgB,IAAI,OAAO;4BACpD,UAAU,EAAE,kBAAkB;4BAC9B,YAAY,EAAE;gCACZ,WAAW,EAAE,IAAI;gCACjB,SAAS,EAAE,UAAU;gCACrB,UAAU,EAAE,IAAI;gCAChB,QAAQ,EAAE,IAAI;gCACd,KAAK,EAAE;oCACL,IAAI,EAAE,IAAI;oCACV,KAAK,EAAE,KAAK;oCACZ,KAAK,EAAE,IAAI;oCACX,KAAK,EAAE,KAAK;oCACZ,GAAG,EAAE,KAAK;iCACX;gCACD,MAAM,EAAE;oCACN,IAAI,EAAE,IAAI;oCACV,KAAK,EAAE,KAAK;oCACZ,KAAK,EAAE,KAAK;oCACZ,KAAK,EAAE,KAAK;oCACZ,GAAG,EAAE,KAAK;iCACX;gCACD,WAAW,EAAE,KAAK;6BACnB;4BACD,IAAI,EAAE;gCACJ,KAAK,EAAE,CAAC;gCACR,MAAM,EAAE,CAAC;gCACT,KAAK,EAAE;oCACL,IAAI,EAAE,CAAC;oCACP,KAAK,EAAE,CAAC;iCACT;6BACF;4BACD,OAAO,EAAE,EAAE;4BACX,KAAK,EAAE,MAAM;4BACb,OAAO,EAAE,EAAE;4BACX,GAAG,aAAa;yBACjB,CAAC;wBAEF,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC;oBACzC,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,yDAAyD;YAC3D,CAAC;YAED,gEAAgE;YAChE,MAAM,WAAW,GAAG,iBAAiB,CAAC;gBACpC,WAAW;gBACX,4CAA4C;gBAC5C,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC;aACd,CAAC,CAAC;YAEH,0DAA0D;YAC1D,mEAAmE;YACnE,sEAAsE;YACtE,OAAO;gBACL,MAAM,EAAE,qBAAqB,EAAE,sBAAsB;gBACrD,OAAO,EAAE,kCAAkC,EAAE,oCAAoC;gBACjF,KAAK,EAAE,WAAW;aACnB,CAAC;QACJ,CAAC;QAED,OAAO,EAAE;YACP;gBACE,KAAK,EAAE,mBAAmB;gBAC1B,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,KAAK,EAAE,OAAgC,EAAE,EAAE;oBACpD,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;oBAC5C,OAAO,CAAC,GAAG,CACT,uDAAuD,CACxD,CAAC;oBACF,OAAO,CAAC,GAAG,CACT,sEAAsE,CACvE,CAAC;oBACF,OAAO,CAAC,GAAG,CACT,yDAAyD,CAC1D,CAAC;oBAEF,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;oBACxC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC;oBAEzD,OAAO;wBACL,GAAG,EAAE,QAAQ;wBACb,YAAY,EACV,yFAAyF;wBAC3F,MAAM,EAAE,MAAM;wBACd,QAAQ,EAAE,KAAK,IAAkC,EAAE;4BACjD,IAAI,CAAC;gCACH,eAAe;gCACf,IAAI,CAAC;oCACH,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gCAC9B,CAAC;gCAAC,MAAM,CAAC;oCACP,OAAO,CAAC,GAAG,CACT,mEAAmE,CACpE,CAAC;gCACJ,CAAC;gCAED,0BAA0B;gCAC1B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,QAAQ,EAAE;oCACxD,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;iCAC5C,CAAC,CAAC;gCAEH,IAAI,CAAC,MAAM,EAAE,CAAC;oCACZ,OAAO;wCACL,IAAI,EAAE,QAAQ;wCACd,KAAK,EAAE,2CAA2C;qCACnD,CAAC;gCACJ,CAAC;gCAED,uBAAuB;gCACvB,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,iBAAiB;gCACzD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gCACrD,IAAI,OAAO,EAAE,GAAG,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;oCACpD,OAAO,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;gCAC/B,CAAC;gCAED,OAAO;oCACL,IAAI,EAAE,SAAS;oCACf,OAAO,EAAE,MAAM,CAAC,YAAY;oCAC5B,MAAM,EAAE,MAAM,CAAC,WAAW;oCAC1B,OAAO;iCACR,CAAC;4BACJ,CAAC;4BAAC,OAAO,KAAK,EAAE,CAAC;gCACf,OAAO;oCACL,IAAI,EAAE,QAAQ;oCACd,KAAK,EACH,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;iCAC3D,CAAC;4BACJ,CAAC;wBACH,CAAC;qBACF,CAAC;gBACJ,CAAC;aACF;YACD;gBACE,KAAK,EAAE,wBAAwB;gBAC/B,IAAI,EAAE,KAAK;aACZ;SACF;KACF;CACF,CAAC,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * OpenCode Plugin Types
3
+ *
4
+ * Type definitions for the OpenCode plugin system.
5
+ * These types mirror the @opencode-ai/plugin interface.
6
+ */
7
+ export interface OAuthAuthDetails {
8
+ type: "oauth";
9
+ refresh: string;
10
+ access?: string;
11
+ expires?: number;
12
+ }
13
+ export interface ApiKeyAuthDetails {
14
+ type: "api";
15
+ apiKey: string;
16
+ }
17
+ export interface TokenAuthDetails {
18
+ type: "token";
19
+ token: string;
20
+ }
21
+ export type AuthDetails = OAuthAuthDetails | ApiKeyAuthDetails | TokenAuthDetails | {
22
+ type: string;
23
+ [key: string]: unknown;
24
+ };
25
+ export type GetAuth = () => Promise<AuthDetails>;
26
+ export interface ProviderModel {
27
+ cost?: {
28
+ input: number;
29
+ output: number;
30
+ };
31
+ [key: string]: unknown;
32
+ }
33
+ export interface Provider {
34
+ id?: string;
35
+ name?: string;
36
+ models?: Record<string, ProviderModel | undefined>;
37
+ }
38
+ /**
39
+ * RequestInfo type for fetch-like functions
40
+ */
41
+ export type FetchInput = Request | string | URL;
42
+ export interface LoaderResult {
43
+ apiKey?: string;
44
+ baseURL?: string;
45
+ fetch?(input: FetchInput, init?: RequestInit): Promise<Response>;
46
+ }
47
+ export interface TokenExchangeSuccess {
48
+ type: "success";
49
+ refresh: string;
50
+ access: string;
51
+ expires: number;
52
+ }
53
+ export interface TokenExchangeFailure {
54
+ type: "failed";
55
+ error?: string;
56
+ }
57
+ export type TokenExchangeResult = TokenExchangeSuccess | TokenExchangeFailure;
58
+ export interface OAuthAuthMethod {
59
+ label: string;
60
+ type: "oauth";
61
+ prompts?: AuthPrompt[];
62
+ authorize: (inputs?: Record<string, string>) => Promise<{
63
+ url: string;
64
+ instructions: string;
65
+ method: "auto" | "code";
66
+ callback: (callbackUrl?: string) => Promise<TokenExchangeResult>;
67
+ }>;
68
+ }
69
+ export interface AuthPrompt {
70
+ type: "text" | "select";
71
+ key: string;
72
+ message: string;
73
+ placeholder?: string;
74
+ validate?: (value: string) => string | undefined;
75
+ condition?: (inputs: Record<string, string>) => boolean;
76
+ options?: Array<{
77
+ label: string;
78
+ value: string;
79
+ hint?: string;
80
+ }>;
81
+ }
82
+ export interface ApiKeyAuthMethod {
83
+ label: string;
84
+ type: "api";
85
+ prompts?: AuthPrompt[];
86
+ authorize?: (inputs?: Record<string, string>) => Promise<{
87
+ type: "success";
88
+ key: string;
89
+ provider?: string;
90
+ } | {
91
+ type: "failed";
92
+ }>;
93
+ }
94
+ export type AuthMethod = OAuthAuthMethod | ApiKeyAuthMethod;
95
+ export interface PluginClient {
96
+ auth: {
97
+ set(input: {
98
+ path: {
99
+ id: string;
100
+ };
101
+ body: AuthDetails;
102
+ }): Promise<void>;
103
+ };
104
+ }
105
+ export interface PluginContext {
106
+ client: PluginClient;
107
+ }
108
+ export interface PluginResult {
109
+ auth: {
110
+ provider: string;
111
+ loader: (getAuth: GetAuth, provider: Provider) => Promise<LoaderResult | null>;
112
+ methods: AuthMethod[];
113
+ };
114
+ }
115
+ export type Plugin = (context: PluginContext) => Promise<PluginResult>;
116
+ export interface CursorAuthRecord {
117
+ accessToken: string;
118
+ refreshToken: string;
119
+ expires?: number;
120
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * OpenCode Plugin Types
3
+ *
4
+ * Type definitions for the OpenCode plugin system.
5
+ * These types mirror the @opencode-ai/plugin interface.
6
+ */
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * OpenAI-Compatible API Server
3
+ *
4
+ * Routes OpenAI API requests through Cursor's Agent API backend.
5
+ * Supports:
6
+ * - POST /v1/chat/completions (streaming and non-streaming)
7
+ * - GET /v1/models
8
+ *
9
+ * Usage:
10
+ * CURSOR_ACCESS_TOKEN=<token> bun run src/server.ts
11
+ *
12
+ * Or with auto-loaded credentials:
13
+ * bun run src/server.ts
14
+ */
15
+ export {};
package/dist/server.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * OpenAI-Compatible API Server
3
+ *
4
+ * Routes OpenAI API requests through Cursor's Agent API backend.
5
+ * Supports:
6
+ * - POST /v1/chat/completions (streaming and non-streaming)
7
+ * - GET /v1/models
8
+ *
9
+ * Usage:
10
+ * CURSOR_ACCESS_TOKEN=<token> bun run src/server.ts
11
+ *
12
+ * Or with auto-loaded credentials:
13
+ * bun run src/server.ts
14
+ */
15
+ import { FileCredentialManager } from "./lib/storage";
16
+ import { createRequestHandler } from "./lib/openai-compat";
17
+ // Debug logging - set CURSOR_DEBUG=1 to enable
18
+ const DEBUG = process.env.CURSOR_DEBUG === "1";
19
+ const debugLog = DEBUG ? console.log.bind(console) : () => { };
20
+ // --- Server Configuration ---
21
+ const PORT = Number.parseInt(process.env.PORT ?? "18741", 10);
22
+ // --- Authentication ---
23
+ async function getAccessToken() {
24
+ // First check environment variable
25
+ const envToken = process.env.CURSOR_ACCESS_TOKEN;
26
+ if (envToken) {
27
+ return envToken;
28
+ }
29
+ // Fall back to credential manager
30
+ const cm = new FileCredentialManager("cursor");
31
+ const token = await cm.getAccessToken();
32
+ if (!token) {
33
+ throw new Error("No access token found. Set CURSOR_ACCESS_TOKEN or authenticate first.");
34
+ }
35
+ return token;
36
+ }
37
+ // --- Main ---
38
+ debugLog("Starting OpenAI-compatible API server...");
39
+ let accessToken;
40
+ try {
41
+ accessToken = await getAccessToken();
42
+ debugLog("Access token loaded successfully");
43
+ }
44
+ catch (err) {
45
+ console.error("Failed to get access token:", err instanceof Error ? err.message : String(err));
46
+ process.exit(1);
47
+ }
48
+ // Create the request handler from shared module
49
+ const handleRequest = createRequestHandler({
50
+ accessToken,
51
+ log: debugLog,
52
+ });
53
+ Bun.serve({
54
+ port: PORT,
55
+ idleTimeout: 120, // 2 minutes to allow for long tool executions
56
+ async fetch(req) {
57
+ const url = new URL(req.url);
58
+ // Enhanced health check with version info (server-specific)
59
+ if (url.pathname === "/health" || url.pathname === "/") {
60
+ return new Response(JSON.stringify({ status: "ok", version: "1.0.0" }), {
61
+ headers: {
62
+ "Content-Type": "application/json",
63
+ "Access-Control-Allow-Origin": "*",
64
+ },
65
+ });
66
+ }
67
+ // Delegate to shared request handler
68
+ return handleRequest(req);
69
+ },
70
+ });
71
+ debugLog(`
72
+ ╔════════════════════════════════════════════════════════════╗
73
+ ║ OpenAI-Compatible API Server ║
74
+ ╠════════════════════════════════════════════════════════════╣
75
+ ║ Server running on http://localhost:${PORT.toString().padEnd(24)}║
76
+ ║ ║
77
+ ║ Endpoints: ║
78
+ ║ POST /v1/chat/completions - Chat completions ║
79
+ ║ GET /v1/models - List available models ║
80
+ ║ GET /health - Health check ║
81
+ ║ ║
82
+ ║ Usage with curl: ║
83
+ ║ curl http://localhost:${PORT}/v1/chat/completions ${" ".repeat(Math.max(0, 6 - PORT.toString().length))}║
84
+ ║ -H "Content-Type: application/json" \ ║
85
+ ║ -d '{"model":"gpt-4o","messages":[...]}' ║
86
+ ║ ║
87
+ ║ Usage with OpenAI SDK: ║
88
+ ║ const openai = new OpenAI({ ║
89
+ ║ baseURL: "http://localhost:${PORT}/v1",${" ".repeat(Math.max(0, 20 - PORT.toString().length))}║
90
+ ║ apiKey: "not-needed" ║
91
+ ║ }); ║
92
+
93
+ ╚════════════════════════════════════════════════════════════╝
94
+ `);
95
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "opencode-cursor-proxy",
3
+ "version": "1.0.1",
4
+ "description": "OpenCode plugin for Cursor's AI backend",
5
+ "author": "Morse Wayne",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/MorseWayne/opencode-cursor-proxy"
10
+ },
11
+ "module": "dist/index.js",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "type": "module",
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "README.zh-CN.md",
19
+ "LICENSE"
20
+ ],
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/index.js",
24
+ "types": "./dist/index.d.ts"
25
+ },
26
+ "./plugin": {
27
+ "import": "./dist/plugin/index.js",
28
+ "types": "./dist/plugin/index.d.ts"
29
+ }
30
+ },
31
+ "scripts": {
32
+ "build": "rm -rf dist && bun x tsc -p tsconfig.build.json",
33
+ "start": "bun run src/server.ts",
34
+ "server": "bun run src/server.ts",
35
+ "proxy": "bun run src/server.ts",
36
+ "auth": "bun run scripts/auth.ts",
37
+ "auth:status": "bun run scripts/auth.ts status",
38
+ "auth:login": "bun run scripts/auth.ts login",
39
+ "auth:logout": "bun run scripts/auth.ts logout",
40
+ "models": "bun run scripts/fetch-models.ts",
41
+ "test": "bun test tests/unit",
42
+ "test:integration": "bun test tests/integration",
43
+ "test:all": "bun test tests"
44
+ },
45
+ "keywords": [
46
+ "cursor",
47
+ "opencode",
48
+ "openai",
49
+ "api",
50
+ "proxy",
51
+ "llm",
52
+ "ai",
53
+ "tool-calling",
54
+ "streaming",
55
+ "claude",
56
+ "gpt"
57
+ ],
58
+ "devDependencies": {
59
+ "@opencode-ai/plugin": "^0.13.7",
60
+ "@opencode-ai/sdk": "^0.13.9",
61
+ "@types/babel__generator": "^7.27.0",
62
+ "@types/bun": "latest",
63
+ "@types/node": "^25.0.9",
64
+ "typescript": "^5"
65
+ },
66
+ "peerDependencies": {
67
+ "@opencode-ai/plugin": "^0.13.7",
68
+ "typescript": "^5"
69
+ },
70
+ "dependencies": {
71
+ "@anthropic-ai/tokenizer": "^0.0.4",
72
+ "@babel/generator": "^7.28.5",
73
+ "@babel/parser": "^7.28.5",
74
+ "@babel/types": "^7.28.5",
75
+ "@bufbuild/protobuf": "1.10.0",
76
+ "gpt-tokenizer": "^3.4.0",
77
+ "llm-info": "^1.0.69"
78
+ }
79
+ }