opencode-ext-connector 0.3.0

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 (332) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +29 -0
  3. package/README.md +207 -0
  4. package/THIRD_PARTY_NOTICES.md +201 -0
  5. package/dist/catalog/parse-ids.d.ts +2 -0
  6. package/dist/catalog/parse-ids.js +49 -0
  7. package/dist/core/adapter.d.ts +16 -0
  8. package/dist/core/adapter.js +20 -0
  9. package/dist/core/clock.d.ts +7 -0
  10. package/dist/core/clock.js +1 -0
  11. package/dist/core/deadline.d.ts +13 -0
  12. package/dist/core/deadline.js +54 -0
  13. package/dist/core/errors.d.ts +57 -0
  14. package/dist/core/errors.js +81 -0
  15. package/dist/core/health.d.ts +22 -0
  16. package/dist/core/health.js +30 -0
  17. package/dist/core/http.d.ts +28 -0
  18. package/dist/core/http.js +1 -0
  19. package/dist/core/ids.d.ts +7 -0
  20. package/dist/core/ids.js +23 -0
  21. package/dist/core/lifecycle.d.ts +4 -0
  22. package/dist/core/lifecycle.js +16 -0
  23. package/dist/core/logger.d.ts +21 -0
  24. package/dist/core/logger.js +61 -0
  25. package/dist/core/models.d.ts +41 -0
  26. package/dist/core/models.js +59 -0
  27. package/dist/core/options.d.ts +31 -0
  28. package/dist/core/options.js +62 -0
  29. package/dist/core/process.d.ts +20 -0
  30. package/dist/core/process.js +1 -0
  31. package/dist/http/fetch-transport.d.ts +2 -0
  32. package/dist/http/fetch-transport.js +75 -0
  33. package/dist/http/package-version.d.ts +7 -0
  34. package/dist/http/package-version.js +46 -0
  35. package/dist/http/read-body.d.ts +9 -0
  36. package/dist/http/read-body.js +22 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.js +5 -0
  39. package/dist/logging/logger.d.ts +4 -0
  40. package/dist/logging/logger.js +11 -0
  41. package/dist/opencode/auth-store.d.ts +19 -0
  42. package/dist/opencode/auth-store.js +107 -0
  43. package/dist/opencode/beta-api.d.ts +3 -0
  44. package/dist/opencode/beta-api.js +1 -0
  45. package/dist/opencode/catalog-bridge.d.ts +3 -0
  46. package/dist/opencode/catalog-bridge.js +85 -0
  47. package/dist/opencode/health-refresh.d.ts +16 -0
  48. package/dist/opencode/health-refresh.js +49 -0
  49. package/dist/opencode/host-options.d.ts +2 -0
  50. package/dist/opencode/host-options.js +49 -0
  51. package/dist/opencode/language-factory.d.ts +13 -0
  52. package/dist/opencode/language-factory.js +37 -0
  53. package/dist/opencode/ollama-probe.d.ts +2 -0
  54. package/dist/opencode/ollama-probe.js +15 -0
  55. package/dist/opencode/ollama-production.d.ts +4 -0
  56. package/dist/opencode/ollama-production.js +10 -0
  57. package/dist/opencode/plugin.d.ts +33 -0
  58. package/dist/opencode/plugin.js +40 -0
  59. package/dist/opencode/process-exit.d.ts +4 -0
  60. package/dist/opencode/process-exit.js +22 -0
  61. package/dist/opencode/provider-entry.d.ts +25 -0
  62. package/dist/opencode/provider-entry.js +1 -0
  63. package/dist/opencode/providers.d.ts +16 -0
  64. package/dist/opencode/providers.js +140 -0
  65. package/dist/opencode/register-integrations.d.ts +3 -0
  66. package/dist/opencode/register-integrations.js +8 -0
  67. package/dist/opencode/reload.d.ts +9 -0
  68. package/dist/opencode/reload.js +30 -0
  69. package/dist/opencode/v1-anthropic-auth.d.ts +9 -0
  70. package/dist/opencode/v1-anthropic-auth.js +55 -0
  71. package/dist/opencode/v1-catalog.d.ts +13 -0
  72. package/dist/opencode/v1-catalog.js +80 -0
  73. package/dist/opencode/v1-language.d.ts +3 -0
  74. package/dist/opencode/v1-language.js +64 -0
  75. package/dist/opencode/v1-module.d.ts +23 -0
  76. package/dist/opencode/v1-module.js +74 -0
  77. package/dist/opencode/v1-session-auth.d.ts +5 -0
  78. package/dist/opencode/v1-session-auth.js +98 -0
  79. package/dist/providers/claude/adapter.d.ts +7 -0
  80. package/dist/providers/claude/adapter.js +37 -0
  81. package/dist/providers/claude/atomic-private-file.d.ts +13 -0
  82. package/dist/providers/claude/atomic-private-file.js +94 -0
  83. package/dist/providers/claude/auth-json.d.ts +2 -0
  84. package/dist/providers/claude/auth-json.js +14 -0
  85. package/dist/providers/claude/auth.d.ts +24 -0
  86. package/dist/providers/claude/auth.js +200 -0
  87. package/dist/providers/claude/cli-version.d.ts +10 -0
  88. package/dist/providers/claude/cli-version.js +36 -0
  89. package/dist/providers/claude/compat-betas.d.ts +5 -0
  90. package/dist/providers/claude/compat-betas.js +54 -0
  91. package/dist/providers/claude/compat-config.d.ts +8 -0
  92. package/dist/providers/claude/compat-config.js +31 -0
  93. package/dist/providers/claude/compat-request.d.ts +12 -0
  94. package/dist/providers/claude/compat-request.js +151 -0
  95. package/dist/providers/claude/compat-response.d.ts +1 -0
  96. package/dist/providers/claude/compat-response.js +54 -0
  97. package/dist/providers/claude/compat-signing.d.ts +9 -0
  98. package/dist/providers/claude/compat-signing.js +24 -0
  99. package/dist/providers/claude/compat-transform.d.ts +3 -0
  100. package/dist/providers/claude/compat-transform.js +224 -0
  101. package/dist/providers/claude/credentials.d.ts +7 -0
  102. package/dist/providers/claude/credentials.js +37 -0
  103. package/dist/providers/claude/emit-stream.d.ts +2 -0
  104. package/dist/providers/claude/emit-stream.js +62 -0
  105. package/dist/providers/claude/keychain-account.d.ts +1 -0
  106. package/dist/providers/claude/keychain-account.js +14 -0
  107. package/dist/providers/claude/language-model.d.ts +8 -0
  108. package/dist/providers/claude/language-model.js +109 -0
  109. package/dist/providers/claude/models.d.ts +9 -0
  110. package/dist/providers/claude/models.js +24 -0
  111. package/dist/providers/claude/prompt.d.ts +42 -0
  112. package/dist/providers/claude/prompt.js +134 -0
  113. package/dist/providers/claude/refresh.d.ts +19 -0
  114. package/dist/providers/claude/refresh.js +85 -0
  115. package/dist/providers/claude/sse-convert.d.ts +6 -0
  116. package/dist/providers/claude/sse-convert.js +74 -0
  117. package/dist/providers/claude/sse.d.ts +71 -0
  118. package/dist/providers/claude/sse.js +123 -0
  119. package/dist/providers/claude/transform.d.ts +32 -0
  120. package/dist/providers/claude/transform.js +52 -0
  121. package/dist/providers/claude/writeback.d.ts +18 -0
  122. package/dist/providers/claude/writeback.js +140 -0
  123. package/dist/providers/command-code/adapter.d.ts +7 -0
  124. package/dist/providers/command-code/adapter.js +37 -0
  125. package/dist/providers/command-code/auth.d.ts +5 -0
  126. package/dist/providers/command-code/auth.js +88 -0
  127. package/dist/providers/command-code/cli-version.d.ts +10 -0
  128. package/dist/providers/command-code/cli-version.js +36 -0
  129. package/dist/providers/command-code/emit-stream.d.ts +2 -0
  130. package/dist/providers/command-code/emit-stream.js +226 -0
  131. package/dist/providers/command-code/errors.d.ts +33 -0
  132. package/dist/providers/command-code/errors.js +105 -0
  133. package/dist/providers/command-code/language-model.d.ts +15 -0
  134. package/dist/providers/command-code/language-model.js +203 -0
  135. package/dist/providers/command-code/models.d.ts +3 -0
  136. package/dist/providers/command-code/models.js +18 -0
  137. package/dist/providers/command-code/record-stream.d.ts +1 -0
  138. package/dist/providers/command-code/record-stream.js +61 -0
  139. package/dist/providers/command-code/request-lifecycle.d.ts +8 -0
  140. package/dist/providers/command-code/request-lifecycle.js +33 -0
  141. package/dist/providers/command-code/request.d.ts +14 -0
  142. package/dist/providers/command-code/request.js +167 -0
  143. package/dist/providers/command-code/session.d.ts +5 -0
  144. package/dist/providers/command-code/session.js +9 -0
  145. package/dist/providers/cursor/adapter.d.ts +7 -0
  146. package/dist/providers/cursor/adapter.js +37 -0
  147. package/dist/providers/cursor/auth.d.ts +6 -0
  148. package/dist/providers/cursor/auth.js +56 -0
  149. package/dist/providers/cursor/blob-store.d.ts +26 -0
  150. package/dist/providers/cursor/blob-store.js +119 -0
  151. package/dist/providers/cursor/bridge-client.d.ts +33 -0
  152. package/dist/providers/cursor/bridge-client.js +200 -0
  153. package/dist/providers/cursor/bridge-event-sanitize.d.ts +3 -0
  154. package/dist/providers/cursor/bridge-event-sanitize.js +49 -0
  155. package/dist/providers/cursor/bridge-limits.d.ts +3 -0
  156. package/dist/providers/cursor/bridge-limits.js +10 -0
  157. package/dist/providers/cursor/bridge-process.d.ts +45 -0
  158. package/dist/providers/cursor/bridge-process.js +211 -0
  159. package/dist/providers/cursor/bridge-protocol.d.ts +68 -0
  160. package/dist/providers/cursor/bridge-protocol.js +49 -0
  161. package/dist/providers/cursor/bridge-serialize.d.ts +3 -0
  162. package/dist/providers/cursor/bridge-serialize.js +53 -0
  163. package/dist/providers/cursor/bridge-wire.d.ts +3 -0
  164. package/dist/providers/cursor/bridge-wire.js +163 -0
  165. package/dist/providers/cursor/checkpoint-store.d.ts +28 -0
  166. package/dist/providers/cursor/checkpoint-store.js +94 -0
  167. package/dist/providers/cursor/connect-frame-stream.d.ts +19 -0
  168. package/dist/providers/cursor/connect-frame-stream.js +160 -0
  169. package/dist/providers/cursor/connect-frame.d.ts +31 -0
  170. package/dist/providers/cursor/connect-frame.js +121 -0
  171. package/dist/providers/cursor/credentials.d.ts +5 -0
  172. package/dist/providers/cursor/credentials.js +22 -0
  173. package/dist/providers/cursor/direct-run-types.d.ts +33 -0
  174. package/dist/providers/cursor/direct-run-types.js +1 -0
  175. package/dist/providers/cursor/direct-run.d.ts +5 -0
  176. package/dist/providers/cursor/direct-run.js +213 -0
  177. package/dist/providers/cursor/direct-runtime.d.ts +23 -0
  178. package/dist/providers/cursor/direct-runtime.js +111 -0
  179. package/dist/providers/cursor/direct-stream.d.ts +28 -0
  180. package/dist/providers/cursor/direct-stream.js +190 -0
  181. package/dist/providers/cursor/exec-reply.d.ts +13 -0
  182. package/dist/providers/cursor/exec-reply.js +102 -0
  183. package/dist/providers/cursor/h2-bridge-response.d.ts +9 -0
  184. package/dist/providers/cursor/h2-bridge-response.js +51 -0
  185. package/dist/providers/cursor/h2-bridge-session.d.ts +24 -0
  186. package/dist/providers/cursor/h2-bridge-session.js +197 -0
  187. package/dist/providers/cursor/h2-bridge.d.ts +2 -0
  188. package/dist/providers/cursor/h2-bridge.js +12865 -0
  189. package/dist/providers/cursor/http2.d.ts +18 -0
  190. package/dist/providers/cursor/http2.js +144 -0
  191. package/dist/providers/cursor/interaction-reply.d.ts +6 -0
  192. package/dist/providers/cursor/interaction-reply.js +52 -0
  193. package/dist/providers/cursor/language-generate.d.ts +2 -0
  194. package/dist/providers/cursor/language-generate.js +35 -0
  195. package/dist/providers/cursor/language-model.d.ts +13 -0
  196. package/dist/providers/cursor/language-model.js +77 -0
  197. package/dist/providers/cursor/legacy-stream.d.ts +11 -0
  198. package/dist/providers/cursor/legacy-stream.js +115 -0
  199. package/dist/providers/cursor/mcp-tools.d.ts +7 -0
  200. package/dist/providers/cursor/mcp-tools.js +15 -0
  201. package/dist/providers/cursor/models.d.ts +14 -0
  202. package/dist/providers/cursor/models.js +116 -0
  203. package/dist/providers/cursor/ndjson.d.ts +3 -0
  204. package/dist/providers/cursor/ndjson.js +100 -0
  205. package/dist/providers/cursor/prompt.d.ts +4 -0
  206. package/dist/providers/cursor/prompt.js +142 -0
  207. package/dist/providers/cursor/proto/checkpoint.d.ts +35 -0
  208. package/dist/providers/cursor/proto/checkpoint.js +114 -0
  209. package/dist/providers/cursor/proto/context.d.ts +64 -0
  210. package/dist/providers/cursor/proto/context.js +178 -0
  211. package/dist/providers/cursor/proto/errors.d.ts +16 -0
  212. package/dist/providers/cursor/proto/errors.js +26 -0
  213. package/dist/providers/cursor/proto/exec-control.d.ts +20 -0
  214. package/dist/providers/cursor/proto/exec-control.js +54 -0
  215. package/dist/providers/cursor/proto/exec.d.ts +47 -0
  216. package/dist/providers/cursor/proto/exec.js +154 -0
  217. package/dist/providers/cursor/proto/fields.d.ts +22 -0
  218. package/dist/providers/cursor/proto/fields.js +97 -0
  219. package/dist/providers/cursor/proto/interaction-query.d.ts +15 -0
  220. package/dist/providers/cursor/proto/interaction-query.js +79 -0
  221. package/dist/providers/cursor/proto/interaction-tool-update.d.ts +10 -0
  222. package/dist/providers/cursor/proto/interaction-tool-update.js +58 -0
  223. package/dist/providers/cursor/proto/interaction-turn-ended.d.ts +6 -0
  224. package/dist/providers/cursor/proto/interaction-turn-ended.js +18 -0
  225. package/dist/providers/cursor/proto/interaction.d.ts +65 -0
  226. package/dist/providers/cursor/proto/interaction.js +185 -0
  227. package/dist/providers/cursor/proto/kv.d.ts +25 -0
  228. package/dist/providers/cursor/proto/kv.js +109 -0
  229. package/dist/providers/cursor/proto/mcp-result.d.ts +40 -0
  230. package/dist/providers/cursor/proto/mcp-result.js +150 -0
  231. package/dist/providers/cursor/proto/mcp.d.ts +19 -0
  232. package/dist/providers/cursor/proto/mcp.js +78 -0
  233. package/dist/providers/cursor/proto/model.d.ts +11 -0
  234. package/dist/providers/cursor/proto/model.js +36 -0
  235. package/dist/providers/cursor/proto/output-location.d.ts +7 -0
  236. package/dist/providers/cursor/proto/output-location.js +53 -0
  237. package/dist/providers/cursor/proto/prewarm.d.ts +16 -0
  238. package/dist/providers/cursor/proto/prewarm.js +68 -0
  239. package/dist/providers/cursor/proto/request-context.d.ts +16 -0
  240. package/dist/providers/cursor/proto/request-context.js +58 -0
  241. package/dist/providers/cursor/proto/request.d.ts +44 -0
  242. package/dist/providers/cursor/proto/request.js +111 -0
  243. package/dist/providers/cursor/proto/run-request.d.ts +19 -0
  244. package/dist/providers/cursor/proto/run-request.js +68 -0
  245. package/dist/providers/cursor/proto/server.d.ts +35 -0
  246. package/dist/providers/cursor/proto/server.js +93 -0
  247. package/dist/providers/cursor/proto/unknown-field.d.ts +1 -0
  248. package/dist/providers/cursor/proto/unknown-field.js +22 -0
  249. package/dist/providers/cursor/proto-value.d.ts +3 -0
  250. package/dist/providers/cursor/proto-value.js +170 -0
  251. package/dist/providers/cursor/proto-wire.d.ts +22 -0
  252. package/dist/providers/cursor/proto-wire.js +224 -0
  253. package/dist/providers/cursor/protocol-failure.d.ts +18 -0
  254. package/dist/providers/cursor/protocol-failure.js +45 -0
  255. package/dist/providers/cursor/recovery.d.ts +48 -0
  256. package/dist/providers/cursor/recovery.js +102 -0
  257. package/dist/providers/cursor/request-blob-ownership.d.ts +15 -0
  258. package/dist/providers/cursor/request-blob-ownership.js +39 -0
  259. package/dist/providers/cursor/request-build.d.ts +18 -0
  260. package/dist/providers/cursor/request-build.js +123 -0
  261. package/dist/providers/cursor/request-history.d.ts +32 -0
  262. package/dist/providers/cursor/request-history.js +163 -0
  263. package/dist/providers/cursor/request-input.d.ts +75 -0
  264. package/dist/providers/cursor/request-input.js +123 -0
  265. package/dist/providers/cursor/run-events.d.ts +15 -0
  266. package/dist/providers/cursor/run-events.js +43 -0
  267. package/dist/providers/cursor/run-session-expiry.d.ts +15 -0
  268. package/dist/providers/cursor/run-session-expiry.js +21 -0
  269. package/dist/providers/cursor/run-session.d.ts +50 -0
  270. package/dist/providers/cursor/run-session.js +205 -0
  271. package/dist/providers/cursor/run.d.ts +9 -0
  272. package/dist/providers/cursor/run.js +151 -0
  273. package/dist/providers/cursor/runner.d.ts +1 -0
  274. package/dist/providers/cursor/runner.js +55 -0
  275. package/dist/providers/cursor/server-dispatch-types.d.ts +83 -0
  276. package/dist/providers/cursor/server-dispatch-types.js +1 -0
  277. package/dist/providers/cursor/server-dispatch.d.ts +3 -0
  278. package/dist/providers/cursor/server-dispatch.js +178 -0
  279. package/dist/providers/cursor/session-state.d.ts +21 -0
  280. package/dist/providers/cursor/session-state.js +118 -0
  281. package/dist/providers/cursor/session.d.ts +1 -0
  282. package/dist/providers/cursor/session.js +26 -0
  283. package/dist/providers/cursor/settle-cleanup.d.ts +1 -0
  284. package/dist/providers/cursor/settle-cleanup.js +11 -0
  285. package/dist/providers/cursor/stream-adapter.d.ts +17 -0
  286. package/dist/providers/cursor/stream-adapter.js +99 -0
  287. package/dist/providers/cursor/tool-continuation.d.ts +14 -0
  288. package/dist/providers/cursor/tool-continuation.js +134 -0
  289. package/dist/providers/cursor/tool-stream.d.ts +2 -0
  290. package/dist/providers/cursor/tool-stream.js +220 -0
  291. package/dist/providers/cursor/usage.d.ts +3 -0
  292. package/dist/providers/cursor/usage.js +35 -0
  293. package/dist/providers/ollama/adapter.d.ts +8 -0
  294. package/dist/providers/ollama/adapter.js +65 -0
  295. package/dist/providers/ollama/catalog-state.d.ts +17 -0
  296. package/dist/providers/ollama/catalog-state.js +40 -0
  297. package/dist/providers/ollama/cloud-catalog.d.ts +3 -0
  298. package/dist/providers/ollama/cloud-catalog.js +82 -0
  299. package/dist/providers/ollama/errors.d.ts +14 -0
  300. package/dist/providers/ollama/errors.js +19 -0
  301. package/dist/providers/ollama/generate.d.ts +2 -0
  302. package/dist/providers/ollama/generate.js +49 -0
  303. package/dist/providers/ollama/html-links.d.ts +1 -0
  304. package/dist/providers/ollama/html-links.js +30 -0
  305. package/dist/providers/ollama/http.d.ts +12 -0
  306. package/dist/providers/ollama/http.js +67 -0
  307. package/dist/providers/ollama/index.d.ts +8 -0
  308. package/dist/providers/ollama/index.js +8 -0
  309. package/dist/providers/ollama/language-model.d.ts +11 -0
  310. package/dist/providers/ollama/language-model.js +62 -0
  311. package/dist/providers/ollama/local-catalog.d.ts +3 -0
  312. package/dist/providers/ollama/local-catalog.js +38 -0
  313. package/dist/providers/ollama/ndjson.d.ts +3 -0
  314. package/dist/providers/ollama/ndjson.js +51 -0
  315. package/dist/providers/ollama/prompt.d.ts +8 -0
  316. package/dist/providers/ollama/prompt.js +141 -0
  317. package/dist/providers/ollama/protocol.d.ts +56 -0
  318. package/dist/providers/ollama/protocol.js +26 -0
  319. package/dist/providers/ollama/runtime.d.ts +11 -0
  320. package/dist/providers/ollama/runtime.js +128 -0
  321. package/dist/providers/ollama/stream.d.ts +8 -0
  322. package/dist/providers/ollama/stream.js +110 -0
  323. package/dist/sdk/command-code.d.ts +5 -0
  324. package/dist/sdk/command-code.js +6 -0
  325. package/dist/sdk/cursor.d.ts +5 -0
  326. package/dist/sdk/cursor.js +6 -0
  327. package/dist/sdk/ollama.d.ts +5 -0
  328. package/dist/sdk/ollama.js +6 -0
  329. package/dist/server.d.ts +12 -0
  330. package/dist/server.js +94 -0
  331. package/docs/README.ko.md +189 -0
  332. package/package.json +75 -0
@@ -0,0 +1,110 @@
1
+ import { OllamaGenerationError } from "./errors";
2
+ import { parseOllamaNdjson } from "./ndjson";
3
+ import { OllamaChatChunkSchema } from "./protocol";
4
+ function usage(chunk) {
5
+ return {
6
+ inputTokens: {
7
+ total: chunk.prompt_eval_count,
8
+ noCache: chunk.prompt_eval_count,
9
+ cacheRead: undefined,
10
+ cacheWrite: undefined,
11
+ },
12
+ outputTokens: { total: chunk.eval_count, text: chunk.eval_count, reasoning: undefined },
13
+ };
14
+ }
15
+ function finishReason(raw, toolCalls) {
16
+ if (toolCalls)
17
+ return { unified: "tool-calls", raw };
18
+ switch (raw) {
19
+ case "stop":
20
+ case undefined:
21
+ return { unified: "stop", raw };
22
+ case "length":
23
+ return { unified: "length", raw };
24
+ case "content_filter":
25
+ return { unified: "content-filter", raw };
26
+ default:
27
+ return { unified: "other", raw };
28
+ }
29
+ }
30
+ export function createOllamaChatStream(options) {
31
+ let cancelled = false;
32
+ return new ReadableStream({
33
+ async start(controller) {
34
+ let textOpen = false;
35
+ let reasoningOpen = false;
36
+ let toolIndex = 0;
37
+ let hadToolCalls = false;
38
+ let terminal = false;
39
+ const closeSections = () => {
40
+ if (reasoningOpen)
41
+ controller.enqueue({ type: "reasoning-end", id: "reasoning-1" });
42
+ if (textOpen)
43
+ controller.enqueue({ type: "text-end", id: "text-1" });
44
+ reasoningOpen = false;
45
+ textOpen = false;
46
+ };
47
+ controller.enqueue({ type: "stream-start", warnings: options.warnings });
48
+ try {
49
+ for await (const chunk of parseOllamaNdjson(options.response, OllamaChatChunkSchema, "chat-response")) {
50
+ if (options.includeRawChunks)
51
+ controller.enqueue({ type: "raw", rawValue: chunk });
52
+ if (chunk.message.thinking !== undefined && chunk.message.thinking.length > 0) {
53
+ if (!reasoningOpen)
54
+ controller.enqueue({ type: "reasoning-start", id: "reasoning-1" });
55
+ reasoningOpen = true;
56
+ controller.enqueue({
57
+ type: "reasoning-delta",
58
+ id: "reasoning-1",
59
+ delta: chunk.message.thinking,
60
+ });
61
+ }
62
+ if (chunk.message.content.length > 0) {
63
+ if (!textOpen)
64
+ controller.enqueue({ type: "text-start", id: "text-1" });
65
+ textOpen = true;
66
+ controller.enqueue({ type: "text-delta", id: "text-1", delta: chunk.message.content });
67
+ }
68
+ for (const call of chunk.message.tool_calls ?? []) {
69
+ toolIndex += 1;
70
+ hadToolCalls = true;
71
+ controller.enqueue({
72
+ type: "tool-call",
73
+ toolCallId: `ollama-tool-${toolIndex}`,
74
+ toolName: call.function.name,
75
+ input: JSON.stringify(call.function.arguments),
76
+ });
77
+ }
78
+ if (chunk.done && !terminal) {
79
+ terminal = true;
80
+ closeSections();
81
+ controller.enqueue({
82
+ type: "finish",
83
+ finishReason: finishReason(chunk.done_reason, hadToolCalls),
84
+ usage: usage(chunk),
85
+ });
86
+ }
87
+ }
88
+ if (!terminal)
89
+ throw new OllamaGenerationError("chat-response");
90
+ if (!cancelled)
91
+ controller.close();
92
+ }
93
+ catch (error) {
94
+ if (!cancelled) {
95
+ closeSections();
96
+ controller.enqueue({ type: "error", error });
97
+ controller.close();
98
+ }
99
+ }
100
+ finally {
101
+ options.finalize();
102
+ }
103
+ },
104
+ cancel() {
105
+ cancelled = true;
106
+ options.cancel();
107
+ options.finalize();
108
+ },
109
+ });
110
+ }
@@ -0,0 +1,5 @@
1
+ import type { LanguageModelV3 } from "@ai-sdk/provider";
2
+ export type CommandCodeProvider = {
3
+ readonly languageModel: (modelId: string) => LanguageModelV3;
4
+ };
5
+ export declare function createCommandCode(options?: Readonly<Record<string, unknown>>): CommandCodeProvider;
@@ -0,0 +1,6 @@
1
+ import { languageForV1Provider } from "../opencode/v1-language";
2
+ export function createCommandCode(options = {}) {
3
+ return {
4
+ languageModel: (modelId) => languageForV1Provider("command-code", modelId, options),
5
+ };
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { LanguageModelV3 } from "@ai-sdk/provider";
2
+ export type CursorProvider = {
3
+ readonly languageModel: (modelId: string) => LanguageModelV3;
4
+ };
5
+ export declare function createCursor(options?: Readonly<Record<string, unknown>>): CursorProvider;
@@ -0,0 +1,6 @@
1
+ import { languageForV1Provider } from "../opencode/v1-language";
2
+ export function createCursor(options = {}) {
3
+ return {
4
+ languageModel: (modelId) => languageForV1Provider("cursor", modelId, options),
5
+ };
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { LanguageModelV3 } from "@ai-sdk/provider";
2
+ export type OllamaProvider = {
3
+ readonly languageModel: (modelId: string) => LanguageModelV3;
4
+ };
5
+ export declare function createOllama(options?: Readonly<Record<string, unknown>>): OllamaProvider;
@@ -0,0 +1,6 @@
1
+ import { languageForV1Provider } from "../opencode/v1-language";
2
+ export function createOllama(options = {}) {
3
+ return {
4
+ languageModel: (modelId) => languageForV1Provider("ollama", modelId, options),
5
+ };
6
+ }
@@ -0,0 +1,12 @@
1
+ import type { Plugin as V1Plugin } from "@opencode-ai/plugin";
2
+ export declare const connectorServer: V1Plugin;
3
+ export declare const claudeAuthServer: V1Plugin;
4
+ export declare const cursorAuthServer: V1Plugin;
5
+ export declare const commandCodeAuthServer: V1Plugin;
6
+ export declare const ollamaAuthServer: V1Plugin;
7
+ export type ConnectorPluginModule = {
8
+ readonly id: "opencode-ext-connector";
9
+ readonly server: V1Plugin;
10
+ };
11
+ export declare const plugin: ConnectorPluginModule;
12
+ export default plugin;
package/dist/server.js ADDED
@@ -0,0 +1,94 @@
1
+ import { dirname, join } from "node:path";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import { createAsyncDisposable } from "./core/lifecycle";
4
+ import { parseConnectorOptions } from "./core/options";
5
+ import { createFetchHttpTransport } from "./http/fetch-transport";
6
+ import { createConsoleLogger } from "./logging/logger";
7
+ import { createOpenCodeAuthStore } from "./opencode/auth-store";
8
+ import { pickConnectorOptionsInput } from "./opencode/host-options";
9
+ import { createProviderRegistry, selectConfiguredProviders } from "./opencode/providers";
10
+ import { disposeV1LanguageRuntime } from "./opencode/v1-language";
11
+ import { createV1AuthServer, createV1Server } from "./opencode/v1-module";
12
+ import { writeClaudeCredentials } from "./providers/claude/writeback";
13
+ const env = process.env;
14
+ const transport = createFetchHttpTransport();
15
+ const authStore = createOpenCodeAuthStore({ env });
16
+ const clock = {
17
+ nowMs: () => Date.now(),
18
+ schedule: (delayMs, callback) => {
19
+ const handle = setTimeout(callback, delayMs);
20
+ handle.unref();
21
+ const cancel = () => {
22
+ clearTimeout(handle);
23
+ };
24
+ return {
25
+ cancel,
26
+ [Symbol.dispose]: cancel,
27
+ };
28
+ },
29
+ };
30
+ const logger = createConsoleLogger(clock);
31
+ const distDirectory = dirname(fileURLToPath(import.meta.url));
32
+ const npmSpecifiers = {
33
+ cursor: pathToFileURL(join(distDirectory, "sdk", "cursor.js")).href,
34
+ "command-code": pathToFileURL(join(distDirectory, "sdk", "command-code.js")).href,
35
+ ollama: pathToFileURL(join(distDirectory, "sdk", "ollama.js")).href,
36
+ };
37
+ const registry = createProviderRegistry({ writeClaudeCredentials });
38
+ const providerDeps = {
39
+ env,
40
+ transport,
41
+ clock,
42
+ authStore,
43
+ writeBackCredentials: false,
44
+ };
45
+ export const connectorServer = async (input, options) => {
46
+ const connectorOptions = parseConnectorOptions(pickConnectorOptionsInput(options));
47
+ const providers = selectConfiguredProviders(registry, connectorOptions.providers);
48
+ const hooks = await createV1Server({
49
+ clock,
50
+ transport,
51
+ authStore,
52
+ env,
53
+ providers,
54
+ npmSpecifiers,
55
+ snapshotTimeoutMs: connectorOptions.snapshotTimeoutMs,
56
+ catalogReloadMs: connectorOptions.catalogReloadMs,
57
+ health: connectorOptions.health,
58
+ logger,
59
+ })(input, options);
60
+ const dispose = hooks.dispose;
61
+ const disposal = createAsyncDisposable(async () => {
62
+ try {
63
+ await dispose?.();
64
+ }
65
+ finally {
66
+ await disposeV1LanguageRuntime();
67
+ }
68
+ });
69
+ return {
70
+ ...hooks,
71
+ dispose: disposal.dispose,
72
+ };
73
+ };
74
+ const claudeEntry = registry.find((entry) => entry.id === "claude");
75
+ const cursorEntry = registry.find((entry) => entry.id === "cursor");
76
+ const commandCodeEntry = registry.find((entry) => entry.id === "command-code");
77
+ const ollamaEntry = registry.find((entry) => entry.id === "ollama");
78
+ export const claudeAuthServer = claudeEntry === undefined
79
+ ? async () => ({})
80
+ : createV1AuthServer(claudeEntry, providerDeps);
81
+ export const cursorAuthServer = cursorEntry === undefined
82
+ ? async () => ({})
83
+ : createV1AuthServer(cursorEntry, providerDeps);
84
+ export const commandCodeAuthServer = commandCodeEntry === undefined
85
+ ? async () => ({})
86
+ : createV1AuthServer(commandCodeEntry, providerDeps);
87
+ export const ollamaAuthServer = ollamaEntry === undefined
88
+ ? async () => ({})
89
+ : createV1AuthServer(ollamaEntry, providerDeps);
90
+ export const plugin = {
91
+ id: "opencode-ext-connector",
92
+ server: connectorServer,
93
+ };
94
+ export default plugin;
@@ -0,0 +1,189 @@
1
+ <div align="center">
2
+
3
+ # OpenCode External Provider Connector
4
+
5
+ **Claude, Cursor, Command Code, Ollama를 위한 OpenCode 플러그인 설정 하나 — 기존 벤더 세션과 로컬 Ollama 데몬을 사용합니다. 새 OAuth 없음.**
6
+
7
+ <p>
8
+ <img src="https://img.shields.io/badge/Bun-%3E%3D1.3.14-000000?style=for-the-badge" alt="Bun >=1.3.14" />
9
+ <img src="https://img.shields.io/badge/TypeScript-6.0.2-3178C6?style=for-the-badge" alt="TypeScript 6.0.2" />
10
+ <img src="https://img.shields.io/badge/OpenCode-E2E_tested-111111?style=for-the-badge" alt="OpenCode E2E tested" />
11
+ <img src="https://img.shields.io/badge/License-BSD--3--Clause-blue?style=for-the-badge" alt="BSD-3-Clause" />
12
+ </p>
13
+
14
+ [English](../README.md) · **한국어** · [문서](#문서)
15
+
16
+ [상태](#상태) · [요구 사항](#요구-사항) · [빠른 설치](#빠른-설치) · [설정](#설정) · [최초 연결](#최초-연결) · [프로바이더](#프로바이더) · [문제 해결](#문제-해결) · [문서](#문서) · [테스트](#테스트) · [라이선스 및 면책 조항](#라이선스-및-면책-조항)
17
+
18
+ </div>
19
+
20
+ ## 상태
21
+
22
+ > 독립적인 비공식 커뮤니티 플러그인, 버전 **0.3.0**. CI에 설치된 OpenCode CLI를 대상으로 legacy multi-function 로더를 패키지 E2E 테스트로 검증합니다. `@opencode-ai/plugin@1.18.18`은 컴파일 시 사용하는 플러그인 API 대상이며 OpenCode 런타임 버전 고정이 아닙니다. 소스는 BSD-3-Clause입니다. 이 프로젝트는 OpenCode 또는 어떤 프로바이더와도 제휴, 보증, 후원, 승인 관계가 없습니다. 전체 조건은 [라이선스 및 면책 조항](#라이선스-및-면책-조항)에 있습니다.
23
+
24
+ 이미 가지고 있는 Claude, Cursor, Command Code, Ollama 세션을 재사용합니다. `opencode.json` 플러그인 항목 하나가 라이브 카탈로그를 OpenCode에 공개합니다. Claude와 Cursor는 OpenCode에 마커 또는 OAuth 레코드가 있고 벤더 세션이 있을 때까지 연결되지 않은 상태로 유지됩니다. Command Code는 OpenCode에 저장된 직접 API 키 또는 기존 CLI 세션/키를 사용할 수 있습니다. Ollama는 정확한 세션 마커와 응답하는 localhost 데몬이 필요합니다.
25
+
26
+ ## 요구 사항
27
+
28
+ | 필요 | 상세 |
29
+ | --- | --- |
30
+ | [Bun](https://bun.sh) | 1.3.14 이상 |
31
+ | Node.js | 22 이상, Cursor 직접 생성 전용 |
32
+ | OpenCode | legacy multi-function 플러그인 로더를 지원하는 런타임; 패키지 E2E는 CI에 설치된 CLI를 테스트합니다. `@opencode-ai/plugin@1.18.18`은 컴파일 시 사용하는 API 대상입니다. |
33
+ | Claude | 기존 Claude Code 자격 증명 (`~/.claude/.credentials.json` 및/또는 macOS Keychain). `claude` 바이너리는 선택 사항입니다. |
34
+ | Cursor | 기존 Cursor CLI 로그인 (`~/.config/cursor/auth.json` 또는 `CURSOR_ACCESS_TOKEN`) |
35
+ | Command Code | 기존 API 키 (`COMMAND_CODE_API_KEY` 또는 `~/.commandcode/auth.json`). `command-code` 바이너리는 선택 사항입니다. |
36
+ | Ollama | `localhost:11434`에서 실행 중인 설치된 로컬 데몬; 그 프로세스를 신뢰할 것; Cloud는 별도로 `ollama signin` 실행 |
37
+
38
+ OpenCode가 실행되는 곳에 벤더 CLI를 설치할 필요가 없습니다. Claude와 Command Code 요청에는 클라이언트 버전이 포함되는데, 커넥터는 `ANTHROPIC_CLI_VERSION` / `COMMAND_CODE_CLI_VERSION`이 설정되어 있으면 그 값을, 아니면 설치된 `claude` / `command-code` 바이너리를, 그것도 없으면 npm registry에 공개된 최신 버전(`@anthropic-ai/claude-code`, `command-code`)을 사용합니다. 패키지에 고정된 버전은 없습니다.
39
+
40
+ ## 빠른 설치
41
+
42
+ 이 저장소를 빌드한 뒤, 컴파일된 모듈을 OpenCode에 지정합니다:
43
+
44
+ ```bash
45
+ bun install
46
+ bun run build
47
+ ```
48
+
49
+ `opencode.json` / `opencode.jsonc` (공식 `plugin` 필드):
50
+
51
+ ```jsonc
52
+ {
53
+ "$schema": "https://opencode.ai/config.json",
54
+ "plugin": [
55
+ "file:///absolute/path/to/opencode-ext-connector/dist/index.js"
56
+ ]
57
+ }
58
+ ```
59
+
60
+ 신뢰할 수 있는, 사용자가 소유한 `file://` 빌드의 직접 `dist/index.js` URL을 사용하십시오. 패키지 디렉터리 URL은 이 커넥터의 named legacy auth hook을 로드하지 않습니다.
61
+
62
+ 패키지 항목 하나가 카탈로그 플러그인과 Claude, Cursor, Command Code, Ollama 인증 hook을 노출합니다. 프로바이더 id: `claude`, `cursor`, `command-code`, `ollama`. 모델 id는 각 프로바이더의 라이브 카탈로그에서 가져오며, 라이브 목록이 비어 있으면 문서화된 fallback은 Cursor의 `default`와 Command Code의 `Qwen/Qwen3.8-Max`입니다.
63
+
64
+ ## 설정
65
+
66
+ OpenCode는 플러그인 옵션을 두 요소 튜플의 두 번째 항목으로 전달합니다.
67
+
68
+ `providers`를 생략하면 네 프로바이더가 모두 활성화됩니다. 명시적 목록은 엄격한 allow-list입니다. 명시적 `[]`는 모두 비활성화합니다.
69
+
70
+ | 옵션 | 기본값 | 의미 |
71
+ | --- | --- | --- |
72
+ | `providers` | 네 프로바이더 모두 | 등록할 프로바이더 id: `claude`, `cursor`, `command-code`, `ollama`; 명시적 `[]`는 모두 비활성화 |
73
+ | `writeBackCredentials` | `false` | Claude OAuth 갱신 후 토큰을 Claude 파일, Keychain(macOS), OpenCode `auth.json`에 기록 |
74
+ | `credentialRefresh.mode` | `"auto"` | `"auto"`는 만료 전에 Claude 토큰을 갱신; `"never"`는 자격 증명 파일의 내용만 보내고 401 이후 그 파일을 다시 읽음 |
75
+ | `credentialRefresh.leadMs` | `60000` | `"auto"`가 만료 얼마 전부터 갱신을 시작할지 |
76
+ | `catalogReloadMs` | `300000` | 이 간격으로 카탈로그 스냅샷을 다시 실행; `0`이면 비활성화 |
77
+ | `snapshotTimeoutMs` | `30000` | 프로바이더별 스냅샷 기한 |
78
+ | `health.initialBackoffMs` | `1000` | 스냅샷 실패 후 health backoff |
79
+ | `health.maximumBackoffMs` | `60000` | health backoff 상한 |
80
+
81
+ writeback은 기본적으로 꺼져 있어, 요청하지 않는 한 이 플러그인은 자격 증명 저장소를 변경하지 않습니다. 명시적으로 켜십시오:
82
+
83
+ ```jsonc
84
+ {
85
+ "$schema": "https://opencode.ai/config.json",
86
+ "plugin": [
87
+ [
88
+ "file:///absolute/path/to/opencode-ext-connector/dist/index.js",
89
+ {
90
+ "writeBackCredentials": true
91
+ }
92
+ ]
93
+ ]
94
+ }
95
+ ```
96
+
97
+ 활성화된 프로바이더는 프로바이더별 인증 규칙이 충족될 때까지 연결되지 않은 상태로 유지됩니다. Claude와 Cursor는 OpenCode 마커 또는 OAuth 레코드와 벤더 세션이 필요하고, Command Code는 OpenCode에 저장된 직접 API 키 또는 기존 CLI 세션/키를 사용할 수 있으며, Ollama는 정확한 세션 마커와 응답하는 localhost 데몬이 필요합니다.
98
+
99
+ 커넥터는 항상 초기 카탈로그 갱신을 한 번 수행합니다. `snapshotTimeoutMs`는 각 프로바이더 스냅샷에 적용되고, `catalogReloadMs: 0`은 주기적 갱신만 비활성화합니다. 주기적 갱신은 fixed-delay이며 single-flight입니다. 다음 지연은 현재 갱신이 끝난 뒤에 시작됩니다. health backoff는 반복 실패를 억제합니다. 일시적 실패는 마지막으로 알려진 카탈로그를 유지하고, 명시적인 unavailable 스냅샷은 커넥터가 소유한 프로바이더 데이터만 제거합니다.
100
+
101
+ OpenCode는 인스턴스 구성 중에 활성 프로바이더 레지스트리를 만듭니다. 주기적 갱신은 커넥터가 유지하는 카탈로그와 health 상태를 갱신하지만, 새 인증이나 변경된 모델 소속은 정상적인 OpenCode 인스턴스 재생성 후에 표시됩니다. 커넥터는 재생성을 강제하지 않으며 생성된 프로바이더 설정을 기록하지 않습니다. `@opencode-ai/plugin@1.18.18` 패키지는 이 커넥터가 대상으로 하는 플러그인 API이며, OpenCode 런타임 고정이 아닙니다.
102
+
103
+ writeback이 꺼져 있으면 갱신된 Claude 토큰은 메모리에만 남습니다. 저장된 refresh 토큰이 회전하면 다음 프로세스 시작 때 동작하지 않을 수 있습니다 — 파일까지 갱신하려면 `writeBackCredentials: true`를 설정하십시오.
104
+
105
+ ### 여러 머신에서 하나의 Claude 로그인 공유
106
+
107
+ Anthropic은 갱신할 때마다 refresh 토큰을 회전시키고 이전 토큰을 무효화합니다. 따라서 `~/.claude/.credentials.json` 사본 두 개가 각자 갱신하면 서로를 깨뜨립니다. 파일 복사는 정확히 한 머신만 갱신하고, 나머지 머신이 자기 사본이 만료되기 전에 그 결과를 받을 때만 동작합니다:
108
+
109
+ - **소유자** (로그인한 곳): `writeBackCredentials: true`와 사본이 만료되기 전에 파일을 배포할 만큼 충분한 리드 타임, 예: `credentialRefresh: { mode: "auto", leadMs: 1800000 }`.
110
+ - **모든 사본**: `credentialRefresh: { mode: "never" }`. 그 머신은 OAuth 엔드포인트에 절대 접속하지 않으며, 요청이 401을 반환하면 파일을 다시 읽고 소유자가 push한 내용으로 한 번 재시도합니다.
111
+ - 소유자의 `~/.claude/.credentials.json`이 바뀔 때마다 각 사본으로 push하십시오(파일 watcher면 충분합니다). OpenCode 자체 `auth.json`은 `anthropic` 레코드만 한 번 있으면 되며, 다른 프로바이더 레코드는 건드리지 마십시오.
112
+
113
+ 대화형으로 사용하는 Claude Code 설치처럼 스스로 갱신하는 머신은 파일을 공유하면 안 됩니다. 그곳에서는 별도로 로그인하십시오.
114
+
115
+ ## 최초 연결
116
+
117
+ 1. 플러그인 URL을 추가한 뒤 **OpenCode를 완전히 재시작**하십시오. 프로세스를 종료한 다음 다시 시작해야 named legacy auth hook이 로드됩니다. 리로드나 주기적 카탈로그 갱신은 인스턴스 재생성이 아닙니다.
118
+ 2. 활성화한 프로바이더의 **로컬 전제 조건을 확인**하십시오. Claude와 Cursor는 벤더 세션이 필요합니다. Command Code는 OpenCode에 저장할 API 키 또는 기존 CLI 세션/키가 필요합니다. Ollama는 `http://localhost:11434`에서 신뢰하는 프로세스가 필요하며, Cloud는 별도로 `ollama signin`이 여전히 필요합니다.
119
+ 3. 원하는 각 프로바이더에 대해 **`/connect`를 실행**하십시오. Claude와 Cursor는 벤더 세션이 사용 가능할 때만 마커 또는 OAuth 항목을 기록합니다. Command Code는 OpenCode에 직접 API 키를 저장하거나 기존 CLI 세션/키를 재사용할 수 있습니다. Ollama는 localhost 데몬이 응답할 때만 정확한 세션 마커를 저장합니다. 모델은 그 프로바이더별 규칙이 충족된 뒤에만 공개됩니다.
120
+ 4. **카탈로그를 확인**하십시오. Claude, Cursor, Command Code 모델이 OpenCode에 나타나는지 확인합니다. Ollama는 `opencode models ollama`를 실행하여 로컬로 pull된 모델과, 커넥터가 자격 증명을 제공하지 않은 채 비인증으로 발견된 Cloud 태그를 확인하십시오.
121
+
122
+ Ollama `/connect`는 로컬 데몬을 조사하고 정확한 세션 마커를 저장합니다. `ollama signin`을 실행하거나 Ollama 자격 증명을 다루지 않습니다.
123
+
124
+ ## 프로바이더
125
+
126
+ | 프로바이더 | 하는 일 |
127
+ | --- | --- |
128
+ | **Claude** | 기존 Claude Code 자격 증명을 재사용합니다. OAuth를 발급하지 않습니다. 호환 fetch가 CLI 호환 요청 메타데이터를 보내고, 내장 `anthropic` 경로에서 Anthropic SSE를 스트림합니다. `writeBackCredentials` 기본값은 `false`(메모리 내 갱신만); `true`는 갱신된 토큰을 Claude 파일, macOS Keychain, OpenCode `auth.json`에 기록합니다. |
129
+ | **Cursor** | CLI 액세스 토큰으로 Cursor의 미공개 클라이언트 프로토콜(`api2.cursor.sh` `AgentService`, HTTP/2 위의 Connect+protobuf)을 호출합니다. 플러그인이 소유한 Node 자식 프로세스가 private stdio로 통신하고, 툴 결과를 같은 bidi Run에 유지하며, parked call을 절대 재실행하지 않고, 사용자 대면 데몬을 열지 않으며, 생성에 `cursor-agent`를 절대 spawn하지 않습니다. 비공식이며 공개 Cursor API가 아닙니다. 프로토콜이 어긋난 뒤에는 암시적 fallback이 없습니다 — 해당 프로바이더가 실패합니다. Node.js 22 이상이 필요합니다. 라이브 카탈로그 id가 있으면 그것을 쓰고, 없으면 문서화된 fallback은 `default`입니다. |
130
+ | **Command Code** | CLI 호환 요청 메타데이터와 함께 `/alpha/generate`를 호출하고, 프로바이더 로컬 NDJSON 텍스트와 툴 이벤트를 스트림합니다. 클라이언트 버전은 `COMMAND_CODE_CLI_VERSION`, 설치된 `command-code` 바이너리, 또는 npm registry에서 가져옵니다. 요청 메타데이터에는 Node.js 버전, 플랫폼, 아키텍처, 절대 작업 디렉터리가 포함됩니다. 라이브 카탈로그 id가 있으면 그것을 쓰고, 없으면 문서화된 fallback은 `Qwen/Qwen3.8-Max`입니다. |
131
+ | **Ollama** | `http://localhost:11434`의 로컬 데몬만 사용하며, 고정된 `/api/tags`, `/api/pull`, `/api/chat`을 씁니다. 그 포트에 바인딩된 프로세스를 신뢰하십시오. 이미 로컬에 pull된 모델과, 커넥터가 자격 증명을 제공하지 않은 채 Ollama 공식 Cloud 검색 및 library 페이지에서 비인증으로 발견한 정확한 Cloud 태그를 공개합니다. 정확히 중복되는 항목은 로컬이 이깁니다. 불완전한 Cloud 갱신은 마지막 완전한 목록을 유지합니다. 없는 인가된 Cloud 태그를 선택하면 최초 사용 시 lightweight remote reference를 pull합니다. 같은 태그의 동시 pull은 하나의 in-flight 요청을 공유하고, 실패한 pull은 나중에 재시도할 수 있습니다. 로컬 데몬은 이후 사용자의 Ollama Cloud 구독으로 Cloud 태그 프롬프트를 proxy할 수 있습니다. 커넥터는 Ollama API 키, 사용량 과금 direct Cloud API, `OLLAMA_HOST`, 원격 Cloud 생성 endpoint를 절대 사용하지 않습니다. |
132
+
133
+ 프로바이더 health는 격리됩니다. 한 프로바이더가 실패해도 나머지는 제거되지 않습니다.
134
+
135
+ 독립 SDK entry는 `opencode-ext-connector/ollama`입니다. 로컬 데몬에 이미 있는 모델로 생성할 수 있으며, 커넥터가 관리하는 Cloud 자동 pull은 활성 Ollama 카탈로그 lease가 필요합니다.
136
+
137
+ ## 문제 해결
138
+
139
+ | 증상 | 확인할 것 |
140
+ | --- | --- |
141
+ | `/connect` 메서드가 없음 | 플러그인 URL은 신뢰할 수 있는, 사용자가 소유한 `file:///absolute/path/to/opencode-ext-connector/dist/index.js`여야 합니다. 패키지 디렉터리 URL은 named legacy auth hook을 로드하지 않습니다. 변경한 뒤 OpenCode를 완전히 재시작하십시오. |
142
+ | 프로바이더가 활성화됐지만 모델이 없음 | `providers`를 생략하면 네 프로바이더가 모두 활성화됩니다. 명시적 목록은 엄격한 allow-list입니다. Claude와 Cursor는 마커 또는 OAuth 레코드와 벤더 세션이 필요하고, Command Code는 OpenCode에 저장된 API 키 또는 CLI 세션/키를 사용할 수 있으며, Ollama는 정확한 마커와 응답하는 localhost 데몬이 필요합니다. `/connect` 후 완전히 재시작해야 인스턴스 재생성이 새 소속을 반영합니다. |
143
+ | Claude가 다음 시작 전까지만 동작함 | 기본 `writeBackCredentials: false`는 갱신된 토큰을 메모리에만 둡니다. 회전된 refresh 토큰은 writeback을 켜지 않으면 다음 프로세스 시작에서 실패합니다. |
144
+ | 복사한 자격 증명 파일에서 Claude가 `invalid_grant`를 보고함 | 같은 로그인의 다른 사본이 이미 갱신해서 refresh 토큰이 회전됐습니다. 한 머신에만 갱신 소유권을 주고 나머지에는 `credentialRefresh: { mode: "never" }`를 설정하거나, 별도로 로그인하십시오. |
145
+ | `Claude Code client version is unavailable` | `ANTHROPIC_CLI_VERSION`도, `claude` 바이너리도 없고 `registry.npmjs.org`에 접근할 수 없었습니다. 변수를 설정하거나 registry 접근을 허용하십시오. |
146
+ | Cursor 생성이 실패함 | Node.js 22 이상이 필요합니다. 생성은 `cursor-agent`가 아니라 private Node 자식 프로세스를 통한 미공개 프로토콜을 사용합니다. 프로토콜이 어긋나면 해당 프로바이더가 실패하며, 암시적 fallback은 없습니다. |
147
+ | Command Code 생성이 실패함 | 클라이언트 버전을 확인할 수 없었습니다: `COMMAND_CODE_CLI_VERSION`을 설정하거나, `command-code`를 설치하거나, `registry.npmjs.org` 접근을 허용하십시오. 요청 메타데이터에는 Node.js 버전, 플랫폼, 아키텍처, 절대 작업 디렉터리가 포함됩니다. |
148
+ | `opencode models ollama`에 Ollama가 없음 | `localhost:11434`에서 신뢰하는 프로세스를 시작한 뒤 `/connect`하여 정확한 세션 마커를 저장할 수 있게 하십시오. Cloud 태그는 커넥터가 자격 증명을 제공하지 않은 비인증 카탈로그 항목이며, 로컬 데몬이 Cloud 태그 프롬프트를 proxy할 수 있습니다. `OLLAMA_HOST`, API 키, direct Cloud 생성은 사용하지 않습니다. |
149
+ | 한 프로바이더가 다운됨 | 실패는 격리됩니다. 일시적 스냅샷 실패는 마지막으로 알려진 카탈로그를 유지하고, unavailable 스냅샷은 해당 커넥터 소유 프로바이더만 제거합니다. |
150
+
151
+ ## 문서
152
+
153
+ | 문서 | 내용 |
154
+ | --- | --- |
155
+ | [../README.md](../README.md) | 영어 README |
156
+ | [../CHANGELOG.md](../CHANGELOG.md) | 릴리스 노트 |
157
+ | [../LICENSE](../LICENSE) | BSD 3-Clause 라이선스 |
158
+ | [../THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md) | 파생 업스트림 작업 |
159
+
160
+ ## 테스트
161
+
162
+ ```bash
163
+ bun run check
164
+ bun test
165
+ bun run test:provider
166
+ bun run test:integration
167
+ bun run test:e2e
168
+ bun run verify:package
169
+ ```
170
+
171
+ E2E 스위트는 임시 HOME/XDG 디렉터리 아래에서 실제 격리된 `opencode serve` 프로세스를 실행합니다. 호스트 자격 증명, proxy/token 변수를 상속하거나 외부 벤더 endpoint에 접근해서는 안 됩니다.
172
+
173
+ ## 라이선스 및 면책 조항
174
+
175
+ BSD-3-Clause. [LICENSE](../LICENSE)를 참조하십시오. 파생 업스트림 작업은 [THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md)에 있습니다.
176
+
177
+ 이 프로젝트는 독립적이고 비공식적인 커뮤니티 프로젝트입니다. OpenCode 또는 제3자 서비스 제공자와 제휴, 보증, 후원, 승인 관계가 없습니다.
178
+
179
+ 모든 제품명, 상표, 등록상표는 각 소유자의 재산입니다. 본 프로젝트에서 이러한 명칭을 사용하는 것은 식별과 상호운용성을 위해서이며, 어떠한 제휴 또는 보증 관계를 암시하지 않습니다.
180
+
181
+ 이 프로젝트의 라이선스는 본 저장소에 배포된 소스 코드에만 적용됩니다. 이 라이선스는 제3자 서비스에 대한 접근, 사용, 수정, 자동화, 또는 제한 사항 우회 권한을 부여하지 않습니다.
182
+
183
+ 이 프로젝트는 접근 통제, 사용 제한, 인증 요건, 또는 서비스 약관을 무력화할 것을 조장하지 않습니다. 사용자는 자신의 사용이 허용되는지 여부를 스스로 판단하고, 관련 법률, 계약, 정책, 제공자 약관을 준수할 책임이 전적으로 있습니다.
184
+
185
+ 제3자 제공자는 언제든지 인터페이스, 인증 방식, 계정, 또는 서비스를 변경, 제한, 중단, 또는 종료할 수 있습니다. 본 소프트웨어를 사용하면 서비스 중단, 계정 제한 또는 해지, 데이터 손실, 예상치 못한 요금 발생, 또는 자격 증명 노출 등의 결과가 발생할 수 있습니다.
186
+
187
+ 본 소프트웨어는 "있는 그대로" 제공되며, 어떠한 형태의 보증도 하지 않습니다. 관련 법률이 허용하는 최대 범위 내에서, 저작자 및 기여자는 본 소프트웨어의 사용 또는 사용 불능으로 인해 발생하는 어떠한 청구, 손해, 손실, 계정 조치, 또는 기타 결과에 대해서도 책임지지 않습니다. 본 소프트웨어는 전적으로 사용자의 책임 하에 사용하십시오.
188
+
189
+ [LICENSE](../LICENSE)의 BSD 3-Clause 라이선스가 본 소프트웨어의 복사, 수정, 배포를 규율합니다. 본 면책 조항이 라이선스와 충돌하는 경우, 라이선스가 우선합니다.
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "opencode-ext-connector",
3
+ "version": "0.3.0",
4
+ "description": "External provider connector for OpenCode",
5
+ "type": "module",
6
+ "license": "BSD-3-Clause",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/kernalix7/opencode-ext-connector.git"
10
+ },
11
+ "homepage": "https://github.com/kernalix7/opencode-ext-connector#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/kernalix7/opencode-ext-connector/issues"
14
+ },
15
+ "sideEffects": false,
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./command-code": {
24
+ "types": "./dist/sdk/command-code.d.ts",
25
+ "import": "./dist/sdk/command-code.js"
26
+ },
27
+ "./cursor": {
28
+ "types": "./dist/sdk/cursor.d.ts",
29
+ "import": "./dist/sdk/cursor.js"
30
+ },
31
+ "./ollama": {
32
+ "types": "./dist/sdk/ollama.d.ts",
33
+ "import": "./dist/sdk/ollama.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "LICENSE",
39
+ "README.md",
40
+ "docs/README.ko.md",
41
+ "CHANGELOG.md",
42
+ "THIRD_PARTY_NOTICES.md"
43
+ ],
44
+ "scripts": {
45
+ "build": "bun run clean && tsc -p tsconfig.build.json && bun run build:h2-bridge",
46
+ "build:h2-bridge": "bun run scripts/build-cursor-h2-bridge.ts",
47
+ "check": "bun run lint && bun run typecheck && bun run check:policy && bun run check:loc && bun run test:foundation",
48
+ "check:loc": "bun run scripts/check-file-size.ts",
49
+ "check:policy": "bun run scripts/check-source-policy.ts",
50
+ "clean": "rm -rf dist",
51
+ "lint": "biome check .",
52
+ "test": "bun test",
53
+ "test:e2e": "bun test tests/e2e/opencode-legacy-loader.test.ts tests/e2e/opencode-provider-lifecycle.test.ts tests/e2e/ollama-lifecycle.test.ts tests/e2e/opencode-package-install.test.ts",
54
+ "test:foundation": "bun test tests/unit/scripts",
55
+ "test:integration": "bun test tests/integration",
56
+ "test:provider": "bun test tests/unit/providers",
57
+ "typecheck": "tsc --noEmit -p tsconfig.json",
58
+ "prepack": "bun run build",
59
+ "verify:package": "bun pm pack --dry-run"
60
+ },
61
+ "dependencies": {
62
+ "@ai-sdk/provider": "3.0.8",
63
+ "@opencode-ai/plugin": "1.18.18",
64
+ "zod": "4.1.8"
65
+ },
66
+ "devDependencies": {
67
+ "@biomejs/biome": "2.5.9",
68
+ "@types/bun": "1.3.14",
69
+ "typescript": "6.0.2"
70
+ },
71
+ "engines": {
72
+ "bun": ">=1.3.14"
73
+ },
74
+ "packageManager": "bun@1.3.14"
75
+ }