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,87 @@
1
+ /**
2
+ * Request Transformer
3
+ *
4
+ * Transforms incoming OpenAI-compatible requests for Cursor API compatibility.
5
+ * Based on techniques from opencode-openai-codex-auth project:
6
+ * - Filters AI SDK-only constructs (item_reference)
7
+ * - Strips message IDs for stateless mode
8
+ * - Handles store:false requirements
9
+ */
10
+ import type { OpenAIMessage, OpenAIMessageContent } from "../openai-compat/types";
11
+ /**
12
+ * Extended message type that includes optional fields that may need filtering
13
+ */
14
+ export interface ExtendedMessage extends OpenAIMessage {
15
+ id?: string;
16
+ type?: string;
17
+ item_reference?: string;
18
+ }
19
+ /**
20
+ * Result of request transformation
21
+ */
22
+ export interface TransformResult {
23
+ /** Transformed messages */
24
+ messages: OpenAIMessage[];
25
+ /** Statistics about the transformation */
26
+ stats: TransformStats;
27
+ }
28
+ /**
29
+ * Statistics about the transformation process
30
+ */
31
+ export interface TransformStats {
32
+ /** Original message count */
33
+ originalCount: number;
34
+ /** Final message count after filtering */
35
+ filteredCount: number;
36
+ /** Number of item_reference entries filtered */
37
+ itemReferencesFiltered: number;
38
+ /** Number of message IDs stripped */
39
+ idsStripped: number;
40
+ /** IDs that were stripped (for debugging) */
41
+ strippedIds: string[];
42
+ }
43
+ /**
44
+ * Filter and transform messages for Cursor API compatibility
45
+ *
46
+ * Key transformations:
47
+ * 1. Filter out item_reference type messages (AI SDK construct for server state lookup)
48
+ * 2. Strip message IDs (causes "item not found" errors in stateless mode)
49
+ * 3. Preserve all other message content
50
+ *
51
+ * @param messages - Original messages from the request
52
+ * @param options - Transformation options
53
+ * @returns Transformed messages and statistics
54
+ */
55
+ export declare function transformMessages(messages: ExtendedMessage[], options?: {
56
+ logStats?: boolean;
57
+ }): TransformResult;
58
+ /**
59
+ * Log transformation statistics for debugging
60
+ */
61
+ export declare function logTransformStats(stats: TransformStats): void;
62
+ /**
63
+ * Check if a message contains multimodal content
64
+ */
65
+ export declare function hasMultimodalContent(content: OpenAIMessageContent): boolean;
66
+ /**
67
+ * Extract text content from potentially multimodal content
68
+ */
69
+ export declare function extractTextContent(content: OpenAIMessageContent): string;
70
+ /**
71
+ * Extract image content from multimodal content
72
+ */
73
+ export declare function extractImageContent(content: OpenAIMessageContent): Array<{
74
+ url: string;
75
+ detail?: "auto" | "low" | "high";
76
+ }>;
77
+ /**
78
+ * Validate that messages are compatible with target model capabilities
79
+ *
80
+ * @param messages - Messages to validate
81
+ * @param supportsVision - Whether the model supports vision/images
82
+ * @returns Validation result with any warnings
83
+ */
84
+ export declare function validateMessagesForModel(messages: OpenAIMessage[], supportsVision: boolean): {
85
+ valid: boolean;
86
+ warnings: string[];
87
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Request Transformer
3
+ *
4
+ * Transforms incoming OpenAI-compatible requests for Cursor API compatibility.
5
+ * Based on techniques from opencode-openai-codex-auth project:
6
+ * - Filters AI SDK-only constructs (item_reference)
7
+ * - Strips message IDs for stateless mode
8
+ * - Handles store:false requirements
9
+ */
10
+ import { createLogger } from "./logger";
11
+ const logger = createLogger("request-transformer");
12
+ /**
13
+ * Filter and transform messages for Cursor API compatibility
14
+ *
15
+ * Key transformations:
16
+ * 1. Filter out item_reference type messages (AI SDK construct for server state lookup)
17
+ * 2. Strip message IDs (causes "item not found" errors in stateless mode)
18
+ * 3. Preserve all other message content
19
+ *
20
+ * @param messages - Original messages from the request
21
+ * @param options - Transformation options
22
+ * @returns Transformed messages and statistics
23
+ */
24
+ export function transformMessages(messages, options = {}) {
25
+ const stats = {
26
+ originalCount: messages.length,
27
+ filteredCount: 0,
28
+ itemReferencesFiltered: 0,
29
+ idsStripped: 0,
30
+ strippedIds: [],
31
+ };
32
+ const transformed = [];
33
+ for (const message of messages) {
34
+ // Filter out item_reference type messages
35
+ // These are AI SDK constructs for server state lookup (not in Cursor API spec)
36
+ if (message.type === "item_reference") {
37
+ stats.itemReferencesFiltered++;
38
+ continue;
39
+ }
40
+ // Create a clean copy without internal fields
41
+ const cleanMessage = {
42
+ role: message.role,
43
+ content: message.content,
44
+ };
45
+ // Track and strip message IDs
46
+ // In stateless mode, IDs cause "item not found" errors
47
+ if (message.id) {
48
+ stats.idsStripped++;
49
+ stats.strippedIds.push(message.id);
50
+ }
51
+ // Preserve tool_calls for assistant messages
52
+ if (message.tool_calls && message.tool_calls.length > 0) {
53
+ cleanMessage.tool_calls = message.tool_calls;
54
+ }
55
+ // Preserve tool_call_id for tool response messages
56
+ if (message.tool_call_id) {
57
+ cleanMessage.tool_call_id = message.tool_call_id;
58
+ }
59
+ transformed.push(cleanMessage);
60
+ }
61
+ stats.filteredCount = transformed.length;
62
+ // Log transformation stats if enabled
63
+ if (options.logStats) {
64
+ logTransformStats(stats);
65
+ }
66
+ return { messages: transformed, stats };
67
+ }
68
+ /**
69
+ * Log transformation statistics for debugging
70
+ */
71
+ export function logTransformStats(stats) {
72
+ const filtered = stats.originalCount - stats.filteredCount;
73
+ if (filtered > 0 || stats.idsStripped > 0) {
74
+ logger.debug(`[Request Transform] Processed ${stats.originalCount} messages: ` +
75
+ `filtered ${stats.itemReferencesFiltered} item_reference(s), ` +
76
+ `stripped ${stats.idsStripped} ID(s)`);
77
+ if (stats.strippedIds.length > 0 && stats.strippedIds.length <= 10) {
78
+ logger.debug(`[Request Transform] Stripped IDs: ${stats.strippedIds.join(", ")}`);
79
+ }
80
+ else if (stats.strippedIds.length > 10) {
81
+ logger.debug(`[Request Transform] Stripped IDs: ${stats.strippedIds.slice(0, 10).join(", ")} ` +
82
+ `... and ${stats.strippedIds.length - 10} more`);
83
+ }
84
+ }
85
+ }
86
+ /**
87
+ * Check if a message contains multimodal content
88
+ */
89
+ export function hasMultimodalContent(content) {
90
+ if (typeof content === "string" || content === null) {
91
+ return false;
92
+ }
93
+ return content.some((part) => part.type === "image_url");
94
+ }
95
+ /**
96
+ * Extract text content from potentially multimodal content
97
+ */
98
+ export function extractTextContent(content) {
99
+ if (content === null) {
100
+ return "";
101
+ }
102
+ if (typeof content === "string") {
103
+ return content;
104
+ }
105
+ // Handle array of content parts
106
+ const textParts = content
107
+ .filter((part) => part.type === "text")
108
+ .map((part) => part.text);
109
+ return textParts.join("\n");
110
+ }
111
+ /**
112
+ * Extract image content from multimodal content
113
+ */
114
+ export function extractImageContent(content) {
115
+ if (content === null || typeof content === "string") {
116
+ return [];
117
+ }
118
+ return content
119
+ .filter((part) => part.type === "image_url")
120
+ .map((part) => {
121
+ const imagePart = part;
122
+ return {
123
+ url: imagePart.image_url.url,
124
+ detail: imagePart.image_url.detail,
125
+ };
126
+ });
127
+ }
128
+ /**
129
+ * Validate that messages are compatible with target model capabilities
130
+ *
131
+ * @param messages - Messages to validate
132
+ * @param supportsVision - Whether the model supports vision/images
133
+ * @returns Validation result with any warnings
134
+ */
135
+ export function validateMessagesForModel(messages, supportsVision) {
136
+ const warnings = [];
137
+ for (let i = 0; i < messages.length; i++) {
138
+ const message = messages[i];
139
+ // Skip if message is undefined (shouldn't happen, but TypeScript safety)
140
+ if (!message) {
141
+ continue;
142
+ }
143
+ // Check for image content in non-vision models
144
+ if (!supportsVision && hasMultimodalContent(message.content)) {
145
+ warnings.push(`Message ${i + 1} contains image content but the model does not support vision. ` +
146
+ `Images will be ignored.`);
147
+ }
148
+ }
149
+ return {
150
+ valid: warnings.length === 0,
151
+ warnings,
152
+ };
153
+ }
154
+ //# sourceMappingURL=request-transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-transformer.js","sourceRoot":"","sources":["../../../src/lib/utils/request-transformer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export type ModelProvider = "openai" | "anthropic" | "gemini" | "unknown";
2
+ export declare function detectModelProvider(model: string): ModelProvider;
3
+ export declare function countOpenAITokens(text: string): number;
4
+ export declare function countAnthropicTokens(text: string): number;
5
+ export declare function countGeminiTokens(text: string): number;
6
+ export declare function estimateTokens(text: string): number;
7
+ export declare function countTokens(text: string, model: string): number;
8
+ export declare function isWithinTokenLimit(text: string, limit: number, model: string): number | false;
9
+ export interface TokenUsage {
10
+ prompt_tokens: number;
11
+ completion_tokens: number;
12
+ total_tokens: number;
13
+ }
14
+ export declare function calculateTokenUsage(prompt: string, completion: string, model: string): TokenUsage;
@@ -0,0 +1,76 @@
1
+ import { encode as encodeGpt, isWithinTokenLimit as gptIsWithinLimit } from "gpt-tokenizer";
2
+ import { countTokens as countClaudeTokens } from "@anthropic-ai/tokenizer";
3
+ const OPENAI_PATTERNS = [
4
+ /^gpt-/i,
5
+ /^o[1-4]-/i,
6
+ /^text-davinci/i,
7
+ /^davinci/i,
8
+ /^curie/i,
9
+ /^babbage/i,
10
+ /^ada/i,
11
+ ];
12
+ const ANTHROPIC_PATTERNS = [
13
+ /claude/i,
14
+ /sonnet/i,
15
+ /opus/i,
16
+ /haiku/i,
17
+ ];
18
+ const GEMINI_PATTERNS = [
19
+ /gemini/i,
20
+ ];
21
+ export function detectModelProvider(model) {
22
+ const normalizedModel = model.toLowerCase();
23
+ if (ANTHROPIC_PATTERNS.some(p => p.test(normalizedModel))) {
24
+ return "anthropic";
25
+ }
26
+ if (OPENAI_PATTERNS.some(p => p.test(normalizedModel))) {
27
+ return "openai";
28
+ }
29
+ if (GEMINI_PATTERNS.some(p => p.test(normalizedModel))) {
30
+ return "gemini";
31
+ }
32
+ return "unknown";
33
+ }
34
+ export function countOpenAITokens(text) {
35
+ return encodeGpt(text).length;
36
+ }
37
+ export function countAnthropicTokens(text) {
38
+ return countClaudeTokens(text);
39
+ }
40
+ export function countGeminiTokens(text) {
41
+ return encodeGpt(text).length;
42
+ }
43
+ export function estimateTokens(text) {
44
+ return Math.ceil(text.length / 4);
45
+ }
46
+ export function countTokens(text, model) {
47
+ const provider = detectModelProvider(model);
48
+ switch (provider) {
49
+ case "openai":
50
+ return countOpenAITokens(text);
51
+ case "anthropic":
52
+ return countAnthropicTokens(text);
53
+ case "gemini":
54
+ return countGeminiTokens(text);
55
+ default:
56
+ return countOpenAITokens(text);
57
+ }
58
+ }
59
+ export function isWithinTokenLimit(text, limit, model) {
60
+ const provider = detectModelProvider(model);
61
+ if (provider === "openai" || provider === "gemini") {
62
+ return gptIsWithinLimit(text, limit);
63
+ }
64
+ const count = countTokens(text, model);
65
+ return count <= limit ? count : false;
66
+ }
67
+ export function calculateTokenUsage(prompt, completion, model) {
68
+ const promptTokens = countTokens(prompt, model);
69
+ const completionTokens = countTokens(completion, model);
70
+ return {
71
+ prompt_tokens: promptTokens,
72
+ completion_tokens: completionTokens,
73
+ total_tokens: promptTokens + completionTokens,
74
+ };
75
+ }
76
+ //# sourceMappingURL=tokenizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizer.js","sourceRoot":"","sources":["../../../src/lib/utils/tokenizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,kBAAkB,IAAI,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE3E,MAAM,eAAe,GAAG;IACtB,QAAQ;IACR,WAAW;IACX,gBAAgB;IAChB,WAAW;IACX,SAAS;IACT,WAAW;IACX,OAAO;CACR,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,SAAS;IACT,SAAS;IACT,OAAO;IACP,QAAQ;CACT,CAAC;AAEF,MAAM,eAAe,GAAG;IACtB,SAAS;CACV,CAAC;AAIF,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAE5C,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QAC1D,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,KAAa;IACrD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAE5C,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,WAAW;YACd,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACpC,KAAK,QAAQ;YACX,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACjC;YACE,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAa,EAAE,KAAa;IAC3E,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAE5C,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvC,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AACxC,CAAC;AAQD,MAAM,UAAU,mBAAmB,CACjC,MAAc,EACd,UAAkB,EAClB,KAAa;IAEb,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAChD,MAAM,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAExD,OAAO;QACL,aAAa,EAAE,YAAY;QAC3B,iBAAiB,EAAE,gBAAgB;QACnC,YAAY,EAAE,YAAY,GAAG,gBAAgB;KAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * OpenCode Cursor Auth Plugin
3
+ *
4
+ * Entry point for the OpenCode plugin interface.
5
+ */
6
+ export { CursorOAuthPlugin, CURSOR_PROVIDER_ID, } from "./plugin.js";
7
+ export type { PluginContext, PluginResult, PluginClient, GetAuth, Provider, ProviderModel, LoaderResult, AuthDetails, OAuthAuthDetails, ApiKeyAuthDetails, TokenAuthDetails, AuthMethod, OAuthAuthMethod, ApiKeyAuthMethod, TokenExchangeResult, TokenExchangeSuccess, TokenExchangeFailure, CursorAuthRecord, } from "./types";
8
+ export { CursorOAuthPlugin as default } from "./plugin.js";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * OpenCode Cursor Auth Plugin
3
+ *
4
+ * Entry point for the OpenCode plugin interface.
5
+ */
6
+ export { CursorOAuthPlugin, CURSOR_PROVIDER_ID, } from "./plugin.js";
7
+ // Default export is the main plugin factory
8
+ export { CursorOAuthPlugin as default } from "./plugin.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAuBrB,4CAA4C;AAC5C,OAAO,EAAE,iBAAiB,IAAI,OAAO,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,21 @@
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 type { PluginContext, PluginResult } from "./types";
11
+ export declare const CURSOR_PROVIDER_ID = "cursor";
12
+ /**
13
+ * Cursor OAuth Plugin for OpenCode
14
+ *
15
+ * Provides authentication for Cursor's AI backend using:
16
+ * - Browser-based OAuth flow with PKCE
17
+ * - API key authentication
18
+ * - Automatic token refresh
19
+ * - Custom fetch function (no proxy server needed)
20
+ */
21
+ export declare const CursorOAuthPlugin: ({ client, }: PluginContext) => Promise<PluginResult>;