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,200 @@
1
+ import { OperationCancelledError, ResourceDisposedError } from "../../core/errors";
2
+ import { createAsyncDisposable } from "../../core/lifecycle";
3
+ import { CursorBridgeProcessError, createNodeCursorBridgeProcessFactory, } from "./bridge-process";
4
+ import { CursorBridgeProtocolError, createBridgeEventLineDecoder, serializeBridgeCommand, } from "./bridge-protocol";
5
+ export class CursorBridgeSessionError extends Error {
6
+ reason;
7
+ name = "CursorBridgeSessionError";
8
+ code = "CURSOR_BRIDGE_SESSION_ERROR";
9
+ constructor(reason) {
10
+ super("Cursor bridge stream is unavailable");
11
+ this.reason = reason;
12
+ }
13
+ }
14
+ class EventInbox {
15
+ events = [];
16
+ waiters = [];
17
+ failure = null;
18
+ finished = false;
19
+ push(event) {
20
+ if (this.failure !== null || this.finished)
21
+ return;
22
+ const waiter = this.waiters.shift();
23
+ if (waiter === undefined)
24
+ this.events.push(event);
25
+ else {
26
+ if (waiter.signal !== undefined && waiter.onAbort !== undefined) {
27
+ waiter.signal.removeEventListener("abort", waiter.onAbort);
28
+ }
29
+ waiter.resolve(event);
30
+ }
31
+ }
32
+ next(signal) {
33
+ const event = this.events.shift();
34
+ if (event !== undefined)
35
+ return Promise.resolve(event);
36
+ if (this.failure !== null)
37
+ return Promise.reject(this.failure);
38
+ if (this.finished)
39
+ return Promise.reject(new CursorBridgeSessionError("stream-closed"));
40
+ if (signal?.aborted === true) {
41
+ return Promise.reject(new OperationCancelledError("wait-cursor-bridge-event"));
42
+ }
43
+ const deferred = Promise.withResolvers();
44
+ const onAbort = signal === undefined
45
+ ? undefined
46
+ : () => {
47
+ const index = this.waiters.findIndex((candidate) => candidate.resolve === deferred.resolve);
48
+ if (index >= 0)
49
+ this.waiters.splice(index, 1);
50
+ deferred.reject(new OperationCancelledError("wait-cursor-bridge-event"));
51
+ };
52
+ if (onAbort !== undefined)
53
+ signal?.addEventListener("abort", onAbort, { once: true });
54
+ this.waiters.push({ resolve: deferred.resolve, reject: deferred.reject, signal, onAbort });
55
+ return deferred.promise;
56
+ }
57
+ finish() {
58
+ this.finished = true;
59
+ this.rejectWaiters(new CursorBridgeSessionError("stream-closed"));
60
+ }
61
+ fail(error) {
62
+ if (this.failure !== null || this.finished)
63
+ return;
64
+ this.failure = error;
65
+ this.rejectWaiters(error);
66
+ }
67
+ rejectWaiters(error) {
68
+ for (const waiter of this.waiters.splice(0)) {
69
+ if (waiter.signal !== undefined && waiter.onAbort !== undefined) {
70
+ waiter.signal.removeEventListener("abort", waiter.onAbort);
71
+ }
72
+ waiter.reject(error);
73
+ }
74
+ }
75
+ }
76
+ function processFailure(exit) {
77
+ const status = exit.code === null ? (exit.signal ?? "unknown signal") : `code ${exit.code}`;
78
+ const detail = exit.stderr.length === 0 ? status : `${status}: ${exit.stderr}`;
79
+ return new CursorBridgeProcessError("child-exited", detail);
80
+ }
81
+ export async function createCursorBridgeClient(options = {}) {
82
+ const lifecycle = new AbortController();
83
+ if (options.signal?.aborted === true)
84
+ throw new OperationCancelledError("start-cursor-bridge");
85
+ const processFactory = options.processFactory ?? createNodeCursorBridgeProcessFactory();
86
+ const child = await processFactory.start(options.signal ?? lifecycle.signal);
87
+ const sessions = new Map();
88
+ const claimedIds = new Set();
89
+ const decoder = createBridgeEventLineDecoder();
90
+ let fatal = null;
91
+ let disposed = false;
92
+ let writes = Promise.resolve();
93
+ const failAll = (error) => {
94
+ if (fatal === null)
95
+ fatal = error;
96
+ for (const session of sessions.values())
97
+ session.inbox.fail(error);
98
+ sessions.clear();
99
+ };
100
+ const send = (command, signal = lifecycle.signal) => {
101
+ const operation = writes.then(async () => {
102
+ if (disposed)
103
+ throw new ResourceDisposedError("cursor-bridge-client");
104
+ if (fatal !== null)
105
+ throw fatal;
106
+ await child.write(serializeBridgeCommand(command), signal);
107
+ });
108
+ writes = operation.then(() => undefined, () => undefined);
109
+ return operation;
110
+ };
111
+ const finishSession = (id, event) => {
112
+ const session = sessions.get(id);
113
+ if (session === undefined)
114
+ return;
115
+ session.inbox.push(event);
116
+ if (event.kind === "end" || event.kind === "error") {
117
+ session.abortSignal.removeEventListener("abort", session.abortListener);
118
+ session.inbox.finish();
119
+ sessions.delete(id);
120
+ }
121
+ };
122
+ const outputTask = (async () => {
123
+ try {
124
+ for await (const chunk of child.stdout) {
125
+ for (const event of decoder.push(chunk))
126
+ finishSession(event.id, event);
127
+ }
128
+ decoder.finish();
129
+ }
130
+ catch (error) {
131
+ const failure = error instanceof CursorBridgeProtocolError || error instanceof CursorBridgeProcessError
132
+ ? error
133
+ : new CursorBridgeProcessError("stdout-failed", "stdout reader failed");
134
+ failAll(failure);
135
+ await child.terminate();
136
+ }
137
+ })();
138
+ const exitTask = child.wait().then((exit) => {
139
+ if (!disposed && fatal === null)
140
+ failAll(processFailure(exit));
141
+ });
142
+ const disposal = createAsyncDisposable(async () => {
143
+ disposed = true;
144
+ lifecycle.abort();
145
+ const error = new ResourceDisposedError("cursor-bridge-client");
146
+ for (const session of sessions.values()) {
147
+ session.abortSignal.removeEventListener("abort", session.abortListener);
148
+ session.inbox.fail(error);
149
+ }
150
+ sessions.clear();
151
+ await child.dispose();
152
+ await Promise.all([outputTask, exitTask]);
153
+ });
154
+ return {
155
+ pid: child.pid,
156
+ async open(input) {
157
+ if (disposed)
158
+ throw new ResourceDisposedError("cursor-bridge-client");
159
+ if (fatal !== null)
160
+ throw fatal;
161
+ if (claimedIds.has(input.id))
162
+ throw new CursorBridgeSessionError("duplicate-stream");
163
+ if (input.signal.aborted)
164
+ throw new OperationCancelledError("open-cursor-bridge-stream");
165
+ claimedIds.add(input.id);
166
+ const inbox = new EventInbox();
167
+ let abortOperation = null;
168
+ const abort = () => {
169
+ if (abortOperation !== null)
170
+ return abortOperation;
171
+ sessions.delete(input.id);
172
+ input.signal.removeEventListener("abort", abortListener);
173
+ inbox.fail(new OperationCancelledError("cursor-bridge-stream"));
174
+ abortOperation = send({ kind: "abort", id: input.id });
175
+ return abortOperation;
176
+ };
177
+ const abortListener = () => {
178
+ void abort();
179
+ };
180
+ sessions.set(input.id, { inbox, abortSignal: input.signal, abortListener });
181
+ input.signal.addEventListener("abort", abortListener, { once: true });
182
+ await send({
183
+ kind: "open",
184
+ id: input.id,
185
+ accessToken: input.accessToken,
186
+ path: input.path,
187
+ headers: input.headers,
188
+ });
189
+ return {
190
+ id: input.id,
191
+ write: (payload, signal) => send({ kind: "write-frame", id: input.id, payload }, signal),
192
+ nextEvent: (signal) => inbox.next(signal),
193
+ abort,
194
+ close: () => send({ kind: "close", id: input.id }),
195
+ };
196
+ },
197
+ dispose: disposal.dispose,
198
+ [Symbol.asyncDispose]: disposal.dispose,
199
+ };
200
+ }
@@ -0,0 +1,3 @@
1
+ import type { BridgeEvent } from "./bridge-protocol";
2
+ export declare function isSensitiveBridgeHeader(name: string): boolean;
3
+ export declare function sanitizeBridgeEvent(event: BridgeEvent, accessToken: string): BridgeEvent;
@@ -0,0 +1,49 @@
1
+ function assertNever(event) {
2
+ void event;
3
+ throw new TypeError("unexpected bridge event");
4
+ }
5
+ function redactExactToken(value, accessToken) {
6
+ return accessToken.length === 0 ? value : value.split(accessToken).join("[REDACTED]");
7
+ }
8
+ function containsExactToken(value, accessToken) {
9
+ return accessToken.length > 0 && value.includes(accessToken);
10
+ }
11
+ export function isSensitiveBridgeHeader(name) {
12
+ return (name === "authorization" ||
13
+ name === "proxy-authorization" ||
14
+ name === "cookie" ||
15
+ name === "set-cookie" ||
16
+ name.includes("token") ||
17
+ name.includes("api-key") ||
18
+ name.includes("apikey") ||
19
+ name.includes("api_key") ||
20
+ name.includes("secret") ||
21
+ name.includes("password"));
22
+ }
23
+ function sanitizeHeaders(headers, accessToken) {
24
+ const sanitized = {};
25
+ for (const [name, value] of Object.entries(headers)) {
26
+ if (!isSensitiveBridgeHeader(name) && !containsExactToken(name, accessToken)) {
27
+ sanitized[name] = redactExactToken(value, accessToken);
28
+ }
29
+ }
30
+ return sanitized;
31
+ }
32
+ export function sanitizeBridgeEvent(event, accessToken) {
33
+ switch (event.kind) {
34
+ case "opened":
35
+ case "data":
36
+ case "end":
37
+ return event;
38
+ case "headers":
39
+ case "trailers":
40
+ return { ...event, headers: sanitizeHeaders(event.headers, accessToken) };
41
+ case "error":
42
+ return {
43
+ ...event,
44
+ message: redactExactToken(event.message, accessToken),
45
+ };
46
+ default:
47
+ return assertNever(event);
48
+ }
49
+ }
@@ -0,0 +1,3 @@
1
+ export declare const MAX_BRIDGE_BINARY_BYTES: number;
2
+ export declare const MAX_BRIDGE_BASE64_CHARACTERS: number;
3
+ export declare const MAX_BRIDGE_LINE_LENGTH: number;
@@ -0,0 +1,10 @@
1
+ import { MAX_CONNECT_FRAME_BYTES } from "./connect-frame";
2
+ const MAX_BRIDGE_ID_CHARACTERS = 128;
3
+ const MAX_BRIDGE_WIRE_OVERHEAD = '{"kind":"write-frame","id":"","payload":""}'.length;
4
+ const OPTIONAL_CARRIAGE_RETURN_CHARACTERS = 1;
5
+ export const MAX_BRIDGE_BINARY_BYTES = MAX_CONNECT_FRAME_BYTES;
6
+ export const MAX_BRIDGE_BASE64_CHARACTERS = Math.ceil(MAX_BRIDGE_BINARY_BYTES / 3) * 4;
7
+ export const MAX_BRIDGE_LINE_LENGTH = MAX_BRIDGE_BASE64_CHARACTERS +
8
+ MAX_BRIDGE_ID_CHARACTERS +
9
+ MAX_BRIDGE_WIRE_OVERHEAD +
10
+ OPTIONAL_CARRIAGE_RETURN_CHARACTERS;
@@ -0,0 +1,45 @@
1
+ import { type AsyncDisposableHandle } from "../../core/lifecycle";
2
+ export type CursorBridgeUnavailableReason = "node-unavailable" | "malformed-node-version" | "unsupported-node" | "spawn-failed";
3
+ export declare class CursorBridgeUnavailableError extends Error {
4
+ readonly reason: CursorBridgeUnavailableReason;
5
+ readonly name = "CursorBridgeUnavailableError";
6
+ readonly code = "CURSOR_BRIDGE_UNAVAILABLE";
7
+ constructor(reason: CursorBridgeUnavailableReason);
8
+ }
9
+ export type CursorBridgeProcessErrorReason = "stdin-closed" | "stdout-failed" | "child-exited" | "termination-failed";
10
+ export declare class CursorBridgeProcessError extends Error {
11
+ readonly reason: CursorBridgeProcessErrorReason;
12
+ readonly name = "CursorBridgeProcessError";
13
+ readonly code = "CURSOR_BRIDGE_PROCESS_ERROR";
14
+ readonly detail: string;
15
+ constructor(reason: CursorBridgeProcessErrorReason, detail: string);
16
+ }
17
+ export type CursorBridgeProcessExit = {
18
+ readonly code: number | null;
19
+ readonly signal: string | null;
20
+ readonly stderr: string;
21
+ };
22
+ export interface CursorBridgeProcess extends AsyncDisposableHandle {
23
+ readonly pid: number;
24
+ readonly stdout: AsyncIterable<string>;
25
+ write(data: string, signal: AbortSignal): Promise<void>;
26
+ wait(): Promise<CursorBridgeProcessExit>;
27
+ terminate(): Promise<void>;
28
+ }
29
+ export interface CursorBridgeProcessFactory {
30
+ start(signal: AbortSignal): Promise<CursorBridgeProcess>;
31
+ }
32
+ export type CursorBridgeSpawnInput = {
33
+ readonly executable: string;
34
+ readonly arguments: readonly string[];
35
+ readonly env: Readonly<Record<string, string>>;
36
+ };
37
+ export type NodeCursorBridgeProcessFactoryOptions = {
38
+ readonly nodeExecutable?: string;
39
+ readonly env?: Readonly<Record<string, string | undefined>>;
40
+ readonly childUrl?: URL;
41
+ readonly endpoint?: string;
42
+ readonly probeVersion?: (executable: string, signal: AbortSignal) => Promise<string>;
43
+ readonly spawnBridge?: (input: CursorBridgeSpawnInput, signal: AbortSignal) => Promise<CursorBridgeProcess>;
44
+ };
45
+ export declare function createNodeCursorBridgeProcessFactory(options?: NodeCursorBridgeProcessFactoryOptions): CursorBridgeProcessFactory;
@@ -0,0 +1,211 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { execFile, spawn } from "node:child_process";
3
+ import { fileURLToPath } from "node:url";
4
+ import { promisify } from "node:util";
5
+ import { OperationCancelledError } from "../../core/errors";
6
+ import { createAsyncDisposable } from "../../core/lifecycle";
7
+ const execFileAsync = promisify(execFile);
8
+ const maximumStderrBytes = 16 * 1024;
9
+ const preservedEnvironment = [
10
+ "PATH",
11
+ "SystemRoot",
12
+ "WINDIR",
13
+ "NODE_EXTRA_CA_CERTS",
14
+ "SSL_CERT_FILE",
15
+ "SSL_CERT_DIR",
16
+ ];
17
+ export class CursorBridgeUnavailableError extends Error {
18
+ reason;
19
+ name = "CursorBridgeUnavailableError";
20
+ code = "CURSOR_BRIDGE_UNAVAILABLE";
21
+ constructor(reason) {
22
+ super("Cursor bridge is unavailable");
23
+ this.reason = reason;
24
+ }
25
+ }
26
+ export class CursorBridgeProcessError extends Error {
27
+ reason;
28
+ name = "CursorBridgeProcessError";
29
+ code = "CURSOR_BRIDGE_PROCESS_ERROR";
30
+ detail;
31
+ constructor(reason, detail) {
32
+ super("Cursor bridge process failed");
33
+ this.reason = reason;
34
+ this.detail = redactProcessText(detail);
35
+ }
36
+ }
37
+ function safeEnvironment(source) {
38
+ const env = {};
39
+ for (const name of preservedEnvironment) {
40
+ const value = source[name];
41
+ if (value !== undefined)
42
+ env[name] = value;
43
+ }
44
+ return env;
45
+ }
46
+ function redactProcessText(value) {
47
+ return value
48
+ .replace(/\bBearer\s+[^\s,;]+/gi, "Bearer [REDACTED]")
49
+ .replace(/\b(authorization|cookie|token|api[-_]?key|password|secret)\s*[:=]\s*[^\s,;]+/gi, "$1=[REDACTED]")
50
+ .replace(/([?&][^=&#\s]+)=([^&#\s]*)/g, "$1=[REDACTED]");
51
+ }
52
+ function parseNodeMajor(version) {
53
+ const match = /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?\r?\n?$/.exec(version);
54
+ if (match === null)
55
+ return null;
56
+ const major = Number(match[1]);
57
+ return Number.isSafeInteger(major) ? major : null;
58
+ }
59
+ async function defaultProbeVersion(executable, signal, env) {
60
+ const result = await execFileAsync(executable, ["--version"], {
61
+ encoding: "utf8",
62
+ env,
63
+ signal,
64
+ windowsHide: true,
65
+ });
66
+ return result.stdout;
67
+ }
68
+ async function* readStdout(child) {
69
+ const decoder = new TextDecoder();
70
+ for await (const value of child.stdout) {
71
+ const chunk = value;
72
+ if (!Buffer.isBuffer(chunk)) {
73
+ throw new CursorBridgeProcessError("stdout-failed", "non-buffer stdout chunk");
74
+ }
75
+ yield decoder.decode(chunk, { stream: true });
76
+ }
77
+ const trailing = decoder.decode();
78
+ if (trailing.length > 0)
79
+ yield trailing;
80
+ }
81
+ class NodeCursorBridgeProcess {
82
+ child;
83
+ pid;
84
+ stdout;
85
+ exit = Promise.withResolvers();
86
+ disposal;
87
+ stderr = [];
88
+ stderrBytes = 0;
89
+ constructor(child) {
90
+ this.child = child;
91
+ const pid = child.pid;
92
+ if (pid === undefined)
93
+ throw new CursorBridgeUnavailableError("spawn-failed");
94
+ this.pid = pid;
95
+ this.stdout = readStdout(child);
96
+ child.stderr.on("data", (value) => {
97
+ if (!Buffer.isBuffer(value) || this.stderrBytes >= maximumStderrBytes)
98
+ return;
99
+ const remaining = maximumStderrBytes - this.stderrBytes;
100
+ const chunk = value.subarray(0, remaining);
101
+ this.stderr.push(chunk);
102
+ this.stderrBytes += chunk.byteLength;
103
+ });
104
+ child.once("exit", (code, signal) => {
105
+ this.exit.resolve({
106
+ code,
107
+ signal,
108
+ stderr: redactProcessText(Buffer.concat(this.stderr).toString("utf8")),
109
+ });
110
+ });
111
+ this.disposal = createAsyncDisposable(() => this.terminate());
112
+ }
113
+ write(data, signal) {
114
+ if (signal.aborted)
115
+ return Promise.reject(new OperationCancelledError("write-cursor-bridge"));
116
+ const deferred = Promise.withResolvers();
117
+ const onAbort = () => deferred.reject(new OperationCancelledError("write-cursor-bridge"));
118
+ signal.addEventListener("abort", onAbort, { once: true });
119
+ this.child.stdin.write(data, (error) => {
120
+ signal.removeEventListener("abort", onAbort);
121
+ if (error === null || error === undefined)
122
+ deferred.resolve();
123
+ else
124
+ deferred.reject(new CursorBridgeProcessError("stdin-closed", "stdin write failed"));
125
+ });
126
+ return deferred.promise;
127
+ }
128
+ wait() {
129
+ return this.exit.promise;
130
+ }
131
+ async terminate() {
132
+ if (this.child.exitCode !== null || this.child.signalCode !== null)
133
+ return;
134
+ this.child.stdin.end();
135
+ this.child.kill("SIGTERM");
136
+ let timer;
137
+ await Promise.race([
138
+ this.exit.promise,
139
+ new Promise((resolve) => {
140
+ timer = setTimeout(resolve, 1_000);
141
+ timer.unref();
142
+ }),
143
+ ]);
144
+ if (timer !== undefined)
145
+ clearTimeout(timer);
146
+ if (this.child.exitCode === null && this.child.signalCode === null) {
147
+ if (!this.child.kill("SIGKILL")) {
148
+ throw new CursorBridgeProcessError("termination-failed", "failed to signal child");
149
+ }
150
+ await this.exit.promise;
151
+ }
152
+ }
153
+ dispose() {
154
+ return this.disposal.dispose();
155
+ }
156
+ [Symbol.asyncDispose]() {
157
+ return this.disposal.dispose();
158
+ }
159
+ }
160
+ async function defaultSpawnBridge(input, signal) {
161
+ const child = spawn(input.executable, [...input.arguments], {
162
+ env: input.env,
163
+ signal,
164
+ stdio: ["pipe", "pipe", "pipe"],
165
+ windowsHide: true,
166
+ });
167
+ await new Promise((resolve, reject) => {
168
+ child.once("spawn", resolve);
169
+ child.once("error", reject);
170
+ });
171
+ return new NodeCursorBridgeProcess(child);
172
+ }
173
+ export function createNodeCursorBridgeProcessFactory(options = {}) {
174
+ const executable = options.nodeExecutable ?? "node";
175
+ const childUrl = options.childUrl ?? new URL("./h2-bridge.js", import.meta.url);
176
+ const env = safeEnvironment(options.env ?? process.env);
177
+ const probeVersion = options.probeVersion ?? ((target, signal) => defaultProbeVersion(target, signal, env));
178
+ const spawnBridge = options.spawnBridge ?? defaultSpawnBridge;
179
+ return {
180
+ async start(signal) {
181
+ if (signal.aborted)
182
+ throw new OperationCancelledError("start-cursor-bridge");
183
+ let version;
184
+ try {
185
+ version = await probeVersion(executable, signal);
186
+ }
187
+ catch (error) {
188
+ if (signal.aborted)
189
+ throw new OperationCancelledError("start-cursor-bridge");
190
+ void error;
191
+ throw new CursorBridgeUnavailableError("node-unavailable");
192
+ }
193
+ const major = parseNodeMajor(version);
194
+ if (major === null)
195
+ throw new CursorBridgeUnavailableError("malformed-node-version");
196
+ if (major < 22)
197
+ throw new CursorBridgeUnavailableError("unsupported-node");
198
+ const childPath = fileURLToPath(childUrl);
199
+ const arguments_ = options.endpoint === undefined ? [childPath] : [childPath, options.endpoint];
200
+ try {
201
+ return await spawnBridge({ executable, arguments: arguments_, env }, signal);
202
+ }
203
+ catch (error) {
204
+ if (signal.aborted)
205
+ throw new OperationCancelledError("start-cursor-bridge");
206
+ void error;
207
+ throw new CursorBridgeUnavailableError("spawn-failed");
208
+ }
209
+ },
210
+ };
211
+ }
@@ -0,0 +1,68 @@
1
+ export { sanitizeBridgeEvent } from "./bridge-event-sanitize";
2
+ export { MAX_BRIDGE_BASE64_CHARACTERS, MAX_BRIDGE_BINARY_BYTES, MAX_BRIDGE_LINE_LENGTH, } from "./bridge-limits";
3
+ export { serializeBridgeCommand, serializeBridgeEvent } from "./bridge-serialize";
4
+ export { parseBridgeCommandLine, parseBridgeEventLine } from "./bridge-wire";
5
+ export type BridgeCommand = {
6
+ readonly kind: "open";
7
+ readonly id: string;
8
+ readonly accessToken: string;
9
+ readonly path: string;
10
+ readonly headers: Readonly<Record<string, string>>;
11
+ } | {
12
+ readonly kind: "write-frame";
13
+ readonly id: string;
14
+ readonly payload: Uint8Array;
15
+ } | {
16
+ readonly kind: "abort";
17
+ readonly id: string;
18
+ } | {
19
+ readonly kind: "close";
20
+ readonly id: string;
21
+ };
22
+ export type BridgeEvent = {
23
+ readonly kind: "opened";
24
+ readonly id: string;
25
+ } | {
26
+ readonly kind: "headers";
27
+ readonly id: string;
28
+ readonly status: number;
29
+ readonly headers: Readonly<Record<string, string>>;
30
+ } | {
31
+ readonly kind: "data";
32
+ readonly id: string;
33
+ readonly payload: Uint8Array;
34
+ } | {
35
+ readonly kind: "trailers";
36
+ readonly id: string;
37
+ readonly headers: Readonly<Record<string, string>>;
38
+ } | {
39
+ readonly kind: "end";
40
+ readonly id: string;
41
+ } | {
42
+ readonly kind: "error";
43
+ readonly id: string;
44
+ readonly code: string;
45
+ readonly message: string;
46
+ };
47
+ export type BridgeEventSerializationContext = {
48
+ readonly accessToken: string;
49
+ };
50
+ export type CursorBridgeProtocolErrorCode = "malformed-json" | "invalid-message" | "invalid-base64" | "line-too-long" | "incomplete-line";
51
+ export declare class CursorBridgeProtocolError extends Error {
52
+ readonly code: CursorBridgeProtocolErrorCode;
53
+ readonly name = "CursorBridgeProtocolError";
54
+ constructor(code: CursorBridgeProtocolErrorCode);
55
+ toJSON(): {
56
+ readonly name: string;
57
+ readonly code: CursorBridgeProtocolErrorCode;
58
+ };
59
+ }
60
+ export type BridgeLineDecoderOptions = {
61
+ readonly maximumLineLength?: number;
62
+ };
63
+ export interface BridgeLineDecoder<T> {
64
+ push(chunk: string): readonly T[];
65
+ finish(): readonly T[];
66
+ }
67
+ export declare function createBridgeCommandLineDecoder(options?: BridgeLineDecoderOptions): BridgeLineDecoder<BridgeCommand>;
68
+ export declare function createBridgeEventLineDecoder(options?: BridgeLineDecoderOptions): BridgeLineDecoder<BridgeEvent>;
@@ -0,0 +1,49 @@
1
+ import { MAX_BRIDGE_LINE_LENGTH } from "./bridge-limits";
2
+ import { parseBridgeCommandLine, parseBridgeEventLine } from "./bridge-wire";
3
+ export { sanitizeBridgeEvent } from "./bridge-event-sanitize";
4
+ export { MAX_BRIDGE_BASE64_CHARACTERS, MAX_BRIDGE_BINARY_BYTES, MAX_BRIDGE_LINE_LENGTH, } from "./bridge-limits";
5
+ export { serializeBridgeCommand, serializeBridgeEvent } from "./bridge-serialize";
6
+ export { parseBridgeCommandLine, parseBridgeEventLine } from "./bridge-wire";
7
+ export class CursorBridgeProtocolError extends Error {
8
+ code;
9
+ name = "CursorBridgeProtocolError";
10
+ constructor(code) {
11
+ super("cursor bridge protocol error");
12
+ this.code = code;
13
+ }
14
+ toJSON() {
15
+ return { name: this.name, code: this.code };
16
+ }
17
+ }
18
+ function createBridgeLineDecoder(options, parseLine) {
19
+ const maximumLineLength = options.maximumLineLength ?? MAX_BRIDGE_LINE_LENGTH;
20
+ let buffered = "";
21
+ const parseLines = (lines) => lines.map((line) => {
22
+ if (line.length > maximumLineLength) {
23
+ throw new CursorBridgeProtocolError("line-too-long");
24
+ }
25
+ return parseLine(line);
26
+ });
27
+ return {
28
+ push(chunk) {
29
+ const lines = `${buffered}${chunk}`.split("\n");
30
+ buffered = lines.pop() ?? "";
31
+ if (buffered.length > maximumLineLength) {
32
+ throw new CursorBridgeProtocolError("line-too-long");
33
+ }
34
+ return parseLines(lines);
35
+ },
36
+ finish() {
37
+ if (buffered.length > 0) {
38
+ throw new CursorBridgeProtocolError("incomplete-line");
39
+ }
40
+ return [];
41
+ },
42
+ };
43
+ }
44
+ export function createBridgeCommandLineDecoder(options = {}) {
45
+ return createBridgeLineDecoder(options, parseBridgeCommandLine);
46
+ }
47
+ export function createBridgeEventLineDecoder(options = {}) {
48
+ return createBridgeLineDecoder(options, parseBridgeEventLine);
49
+ }
@@ -0,0 +1,3 @@
1
+ import { type BridgeCommand, type BridgeEvent, type BridgeEventSerializationContext } from "./bridge-protocol";
2
+ export declare function serializeBridgeCommand(command: BridgeCommand): string;
3
+ export declare function serializeBridgeEvent(event: BridgeEvent, context: BridgeEventSerializationContext): string;