@qodo/sdk 0.13.4 → 2.0.0-next.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 (764) hide show
  1. package/LICENSE +31 -118
  2. package/README.md +133 -121
  3. package/bin/qodo-skills.mjs +13 -0
  4. package/bundled-skills/code-review/SKILL.md +41 -0
  5. package/bundled-skills/pr-summary/SKILL.md +59 -0
  6. package/bundled-skills/test-gen/SKILL.md +47 -0
  7. package/dist/auth/index.browser.d.ts +38 -0
  8. package/dist/auth/index.browser.d.ts.map +1 -0
  9. package/dist/auth/index.browser.js +62 -0
  10. package/dist/auth/index.browser.js.map +1 -0
  11. package/dist/auth/index.d.ts +44 -30
  12. package/dist/auth/index.d.ts.map +1 -1
  13. package/dist/auth/index.js +57 -110
  14. package/dist/auth/index.js.map +1 -1
  15. package/dist/client/AgentsClient.d.ts +33 -0
  16. package/dist/client/AgentsClient.d.ts.map +1 -0
  17. package/dist/client/AgentsClient.js +40 -0
  18. package/dist/client/AgentsClient.js.map +1 -0
  19. package/dist/client/ArtifactsClient.d.ts +43 -0
  20. package/dist/client/ArtifactsClient.d.ts.map +1 -0
  21. package/dist/client/ArtifactsClient.js +54 -0
  22. package/dist/client/ArtifactsClient.js.map +1 -0
  23. package/dist/client/BulletinClient.d.ts +45 -0
  24. package/dist/client/BulletinClient.d.ts.map +1 -0
  25. package/dist/client/BulletinClient.js +51 -0
  26. package/dist/client/BulletinClient.js.map +1 -0
  27. package/dist/client/InfoClient.d.ts +58 -0
  28. package/dist/client/InfoClient.d.ts.map +1 -0
  29. package/dist/client/InfoClient.js +135 -0
  30. package/dist/client/InfoClient.js.map +1 -0
  31. package/dist/client/PipelineClient.d.ts +162 -0
  32. package/dist/client/PipelineClient.d.ts.map +1 -0
  33. package/dist/client/PipelineClient.js +340 -0
  34. package/dist/client/PipelineClient.js.map +1 -0
  35. package/dist/client/QarRegistryClient.d.ts +396 -0
  36. package/dist/client/QarRegistryClient.d.ts.map +1 -0
  37. package/dist/client/QarRegistryClient.js +536 -0
  38. package/dist/client/QarRegistryClient.js.map +1 -0
  39. package/dist/client/QodoClient.d.ts +296 -0
  40. package/dist/client/QodoClient.d.ts.map +1 -0
  41. package/dist/client/QodoClient.js +803 -0
  42. package/dist/client/QodoClient.js.map +1 -0
  43. package/dist/client/SpecsClient.d.ts +121 -0
  44. package/dist/client/SpecsClient.d.ts.map +1 -0
  45. package/dist/client/SpecsClient.js +252 -0
  46. package/dist/client/SpecsClient.js.map +1 -0
  47. package/dist/client/StateClient.d.ts +35 -0
  48. package/dist/client/StateClient.d.ts.map +1 -0
  49. package/dist/client/StateClient.js +36 -0
  50. package/dist/client/StateClient.js.map +1 -0
  51. package/dist/client/TaskClient.d.ts +706 -0
  52. package/dist/client/TaskClient.d.ts.map +1 -0
  53. package/dist/client/TaskClient.js +2522 -0
  54. package/dist/client/TaskClient.js.map +1 -0
  55. package/dist/client/ToolClient.d.ts +278 -0
  56. package/dist/client/ToolClient.d.ts.map +1 -0
  57. package/dist/client/ToolClient.js +1139 -0
  58. package/dist/client/ToolClient.js.map +1 -0
  59. package/dist/client/a2a/index.d.ts +10 -0
  60. package/dist/client/a2a/index.d.ts.map +1 -0
  61. package/dist/client/a2a/index.js +9 -0
  62. package/dist/client/a2a/index.js.map +1 -0
  63. package/dist/client/a2a/registerA2A.d.ts +170 -0
  64. package/dist/client/a2a/registerA2A.d.ts.map +1 -0
  65. package/dist/client/a2a/registerA2A.js +85 -0
  66. package/dist/client/a2a/registerA2A.js.map +1 -0
  67. package/dist/client/connection.d.ts +893 -0
  68. package/dist/client/connection.d.ts.map +1 -0
  69. package/dist/client/connection.js +2189 -0
  70. package/dist/client/connection.js.map +1 -0
  71. package/dist/client/errors.d.ts +735 -0
  72. package/dist/client/errors.d.ts.map +1 -0
  73. package/dist/client/errors.js +921 -0
  74. package/dist/client/errors.js.map +1 -0
  75. package/dist/client/index.d.ts +26 -0
  76. package/dist/client/index.d.ts.map +1 -0
  77. package/dist/client/index.js +20 -0
  78. package/dist/client/index.js.map +1 -0
  79. package/dist/client/inlineGraph.d.ts +66 -0
  80. package/dist/client/inlineGraph.d.ts.map +1 -0
  81. package/dist/client/inlineGraph.js +500 -0
  82. package/dist/client/inlineGraph.js.map +1 -0
  83. package/dist/client/internal/thenable.d.ts +27 -0
  84. package/dist/client/internal/thenable.d.ts.map +1 -0
  85. package/dist/client/internal/thenable.js +31 -0
  86. package/dist/client/internal/thenable.js.map +1 -0
  87. package/dist/client/iterator.d.ts +32 -0
  88. package/dist/client/iterator.d.ts.map +1 -0
  89. package/dist/client/iterator.js +73 -0
  90. package/dist/client/iterator.js.map +1 -0
  91. package/dist/client/mcp/McpClientPool.browser.d.ts +76 -0
  92. package/dist/client/mcp/McpClientPool.browser.d.ts.map +1 -0
  93. package/dist/client/mcp/McpClientPool.browser.js +78 -0
  94. package/dist/client/mcp/McpClientPool.browser.js.map +1 -0
  95. package/dist/client/mcp/McpClientPool.d.ts +236 -0
  96. package/dist/client/mcp/McpClientPool.d.ts.map +1 -0
  97. package/dist/client/mcp/McpClientPool.js +585 -0
  98. package/dist/client/mcp/McpClientPool.js.map +1 -0
  99. package/dist/client/mcp/projection.d.ts +109 -0
  100. package/dist/client/mcp/projection.d.ts.map +1 -0
  101. package/dist/client/mcp/projection.js +446 -0
  102. package/dist/client/mcp/projection.js.map +1 -0
  103. package/dist/client/mcp/substituteEnv.browser.d.ts +18 -0
  104. package/dist/client/mcp/substituteEnv.browser.d.ts.map +1 -0
  105. package/dist/client/mcp/substituteEnv.browser.js +20 -0
  106. package/dist/client/mcp/substituteEnv.browser.js.map +1 -0
  107. package/dist/client/mcp/substituteEnv.d.ts +45 -0
  108. package/dist/client/mcp/substituteEnv.d.ts.map +1 -0
  109. package/dist/client/mcp/substituteEnv.js +63 -0
  110. package/dist/client/mcp/substituteEnv.js.map +1 -0
  111. package/dist/client/observers.d.ts +57 -0
  112. package/dist/client/observers.d.ts.map +1 -0
  113. package/dist/client/observers.js +203 -0
  114. package/dist/client/observers.js.map +1 -0
  115. package/dist/client/options.d.ts +269 -0
  116. package/dist/client/options.d.ts.map +1 -0
  117. package/dist/client/options.js +9 -0
  118. package/dist/client/options.js.map +1 -0
  119. package/dist/client/tools/_readlineApprovalPrompt.browser.d.ts +17 -0
  120. package/dist/client/tools/_readlineApprovalPrompt.browser.d.ts.map +1 -0
  121. package/dist/client/tools/_readlineApprovalPrompt.browser.js +24 -0
  122. package/dist/client/tools/_readlineApprovalPrompt.browser.js.map +1 -0
  123. package/dist/client/tools/_readlineApprovalPrompt.d.ts +33 -0
  124. package/dist/client/tools/_readlineApprovalPrompt.d.ts.map +1 -0
  125. package/dist/client/tools/_readlineApprovalPrompt.js +90 -0
  126. package/dist/client/tools/_readlineApprovalPrompt.js.map +1 -0
  127. package/dist/client/tools/approval.d.ts +280 -0
  128. package/dist/client/tools/approval.d.ts.map +1 -0
  129. package/dist/client/tools/approval.js +229 -0
  130. package/dist/client/tools/approval.js.map +1 -0
  131. package/dist/client/tools/bindFunctionToolDefs.d.ts +156 -0
  132. package/dist/client/tools/bindFunctionToolDefs.d.ts.map +1 -0
  133. package/dist/client/tools/bindFunctionToolDefs.js +360 -0
  134. package/dist/client/tools/bindFunctionToolDefs.js.map +1 -0
  135. package/dist/client/tools/defineFunctionTool.d.ts +277 -0
  136. package/dist/client/tools/defineFunctionTool.d.ts.map +1 -0
  137. package/dist/client/tools/defineFunctionTool.js +190 -0
  138. package/dist/client/tools/defineFunctionTool.js.map +1 -0
  139. package/dist/client/transport.browser.d.ts +20 -0
  140. package/dist/client/transport.browser.d.ts.map +1 -0
  141. package/dist/client/transport.browser.js +29 -0
  142. package/dist/client/transport.browser.js.map +1 -0
  143. package/dist/client/transport.d.ts +47 -0
  144. package/dist/client/transport.d.ts.map +1 -0
  145. package/dist/client/transport.js +102 -0
  146. package/dist/client/transport.js.map +1 -0
  147. package/dist/client/transport.shared.d.ts +30 -0
  148. package/dist/client/transport.shared.d.ts.map +1 -0
  149. package/dist/client/transport.shared.js +40 -0
  150. package/dist/client/transport.shared.js.map +1 -0
  151. package/dist/client/uuid.d.ts +32 -0
  152. package/dist/client/uuid.d.ts.map +1 -0
  153. package/dist/client/uuid.js +65 -0
  154. package/dist/client/uuid.js.map +1 -0
  155. package/dist/index.d.ts +88 -39
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js +166 -43
  158. package/dist/index.js.map +1 -1
  159. package/dist/observability/attributes.d.ts +136 -0
  160. package/dist/observability/attributes.d.ts.map +1 -0
  161. package/dist/observability/attributes.js +184 -0
  162. package/dist/observability/attributes.js.map +1 -0
  163. package/dist/observability/index.d.ts +14 -0
  164. package/dist/observability/index.d.ts.map +1 -0
  165. package/dist/observability/index.js +11 -0
  166. package/dist/observability/index.js.map +1 -0
  167. package/dist/observability/resolveOTel.browser.d.ts +13 -0
  168. package/dist/observability/resolveOTel.browser.d.ts.map +1 -0
  169. package/dist/observability/resolveOTel.browser.js +14 -0
  170. package/dist/observability/resolveOTel.browser.js.map +1 -0
  171. package/dist/observability/resolveOTel.d.ts +28 -0
  172. package/dist/observability/resolveOTel.d.ts.map +1 -0
  173. package/dist/observability/resolveOTel.js +74 -0
  174. package/dist/observability/resolveOTel.js.map +1 -0
  175. package/dist/observability/spans.d.ts +198 -0
  176. package/dist/observability/spans.d.ts.map +1 -0
  177. package/dist/observability/spans.js +300 -0
  178. package/dist/observability/spans.js.map +1 -0
  179. package/dist/observability/traceContext.d.ts +51 -0
  180. package/dist/observability/traceContext.d.ts.map +1 -0
  181. package/dist/observability/traceContext.js +151 -0
  182. package/dist/observability/traceContext.js.map +1 -0
  183. package/dist/observability/transportMetrics.d.ts +58 -0
  184. package/dist/observability/transportMetrics.d.ts.map +1 -0
  185. package/dist/observability/transportMetrics.js +55 -0
  186. package/dist/observability/transportMetrics.js.map +1 -0
  187. package/dist/qar/agentSpec.d.ts +93 -0
  188. package/dist/qar/agentSpec.d.ts.map +1 -0
  189. package/dist/qar/agentSpec.js +184 -0
  190. package/dist/qar/agentSpec.js.map +1 -0
  191. package/dist/qar/clientEvents.d.ts +86 -0
  192. package/dist/qar/clientEvents.d.ts.map +1 -0
  193. package/dist/qar/clientEvents.js +36 -0
  194. package/dist/qar/clientEvents.js.map +1 -0
  195. package/dist/qar/envelopes.d.ts +227 -0
  196. package/dist/qar/envelopes.d.ts.map +1 -0
  197. package/dist/qar/envelopes.js +67 -0
  198. package/dist/qar/envelopes.js.map +1 -0
  199. package/dist/qar/generated/envelope.d.ts +332 -0
  200. package/dist/qar/generated/envelope.d.ts.map +1 -0
  201. package/dist/qar/generated/envelope.js +15 -0
  202. package/dist/qar/generated/envelope.js.map +1 -0
  203. package/dist/qar/generated/qar-info.d.ts +76 -0
  204. package/dist/qar/generated/qar-info.d.ts.map +1 -0
  205. package/dist/qar/generated/qar-info.js +15 -0
  206. package/dist/qar/generated/qar-info.js.map +1 -0
  207. package/dist/qar/generated/qodo-task-start-payload.d.ts +54 -0
  208. package/dist/qar/generated/qodo-task-start-payload.d.ts.map +1 -0
  209. package/dist/qar/generated/qodo-task-start-payload.js +15 -0
  210. package/dist/qar/generated/qodo-task-start-payload.js.map +1 -0
  211. package/dist/qar/ids.d.ts +19 -0
  212. package/dist/qar/ids.d.ts.map +1 -0
  213. package/dist/qar/ids.js +11 -0
  214. package/dist/qar/ids.js.map +1 -0
  215. package/dist/qar/index.d.ts +24 -0
  216. package/dist/qar/index.d.ts.map +1 -0
  217. package/dist/qar/index.js +16 -0
  218. package/dist/qar/index.js.map +1 -0
  219. package/dist/qar/info.d.ts +37 -0
  220. package/dist/qar/info.d.ts.map +1 -0
  221. package/dist/qar/info.js +17 -0
  222. package/dist/qar/info.js.map +1 -0
  223. package/dist/qar/json.d.ts +14 -0
  224. package/dist/qar/json.d.ts.map +1 -0
  225. package/dist/qar/json.js +9 -0
  226. package/dist/qar/json.js.map +1 -0
  227. package/dist/qar/payloads.d.ts +480 -0
  228. package/dist/qar/payloads.d.ts.map +1 -0
  229. package/dist/qar/payloads.js +37 -0
  230. package/dist/qar/payloads.js.map +1 -0
  231. package/dist/qar/specs.d.ts +604 -0
  232. package/dist/qar/specs.d.ts.map +1 -0
  233. package/dist/qar/specs.js +29 -0
  234. package/dist/qar/specs.js.map +1 -0
  235. package/dist/qar/taskEvents.d.ts +25 -0
  236. package/dist/qar/taskEvents.d.ts.map +1 -0
  237. package/dist/qar/taskEvents.js +22 -0
  238. package/dist/qar/taskEvents.js.map +1 -0
  239. package/dist/qar/trace.d.ts +12 -0
  240. package/dist/qar/trace.d.ts.map +1 -0
  241. package/dist/qar/trace.js +12 -0
  242. package/dist/qar/trace.js.map +1 -0
  243. package/dist/skills/activation.d.ts +177 -0
  244. package/dist/skills/activation.d.ts.map +1 -0
  245. package/dist/skills/activation.js +428 -0
  246. package/dist/skills/activation.js.map +1 -0
  247. package/dist/skills/cli/index.browser.d.ts +18 -0
  248. package/dist/skills/cli/index.browser.d.ts.map +1 -0
  249. package/dist/skills/cli/index.browser.js +27 -0
  250. package/dist/skills/cli/index.browser.js.map +1 -0
  251. package/dist/skills/cli/index.d.ts +37 -0
  252. package/dist/skills/cli/index.d.ts.map +1 -0
  253. package/dist/skills/cli/index.js +494 -0
  254. package/dist/skills/cli/index.js.map +1 -0
  255. package/dist/skills/events.d.ts +255 -0
  256. package/dist/skills/events.d.ts.map +1 -0
  257. package/dist/skills/events.js +224 -0
  258. package/dist/skills/events.js.map +1 -0
  259. package/dist/skills/index.d.ts +45 -0
  260. package/dist/skills/index.d.ts.map +1 -0
  261. package/dist/skills/index.js +34 -0
  262. package/dist/skills/index.js.map +1 -0
  263. package/dist/skills/inject.d.ts +57 -0
  264. package/dist/skills/inject.d.ts.map +1 -0
  265. package/dist/skills/inject.js +162 -0
  266. package/dist/skills/inject.js.map +1 -0
  267. package/dist/skills/lockfile.browser.d.ts +56 -0
  268. package/dist/skills/lockfile.browser.d.ts.map +1 -0
  269. package/dist/skills/lockfile.browser.js +55 -0
  270. package/dist/skills/lockfile.browser.js.map +1 -0
  271. package/dist/skills/lockfile.d.ts +137 -0
  272. package/dist/skills/lockfile.d.ts.map +1 -0
  273. package/dist/skills/lockfile.js +423 -0
  274. package/dist/skills/lockfile.js.map +1 -0
  275. package/dist/skills/manager.browser.d.ts +94 -0
  276. package/dist/skills/manager.browser.d.ts.map +1 -0
  277. package/dist/skills/manager.browser.js +159 -0
  278. package/dist/skills/manager.browser.js.map +1 -0
  279. package/dist/skills/manager.d.ts +362 -0
  280. package/dist/skills/manager.d.ts.map +1 -0
  281. package/dist/skills/manager.js +1386 -0
  282. package/dist/skills/manager.js.map +1 -0
  283. package/dist/skills/mcp/index.d.ts +15 -0
  284. package/dist/skills/mcp/index.d.ts.map +1 -0
  285. package/dist/skills/mcp/index.js +12 -0
  286. package/dist/skills/mcp/index.js.map +1 -0
  287. package/dist/skills/mcp/path.browser.d.ts +27 -0
  288. package/dist/skills/mcp/path.browser.d.ts.map +1 -0
  289. package/dist/skills/mcp/path.browser.js +33 -0
  290. package/dist/skills/mcp/path.browser.js.map +1 -0
  291. package/dist/skills/mcp/path.d.ts +57 -0
  292. package/dist/skills/mcp/path.d.ts.map +1 -0
  293. package/dist/skills/mcp/path.js +150 -0
  294. package/dist/skills/mcp/path.js.map +1 -0
  295. package/dist/skills/mcp/server.browser.d.ts +32 -0
  296. package/dist/skills/mcp/server.browser.d.ts.map +1 -0
  297. package/dist/skills/mcp/server.browser.js +53 -0
  298. package/dist/skills/mcp/server.browser.js.map +1 -0
  299. package/dist/skills/mcp/server.d.ts +144 -0
  300. package/dist/skills/mcp/server.d.ts.map +1 -0
  301. package/dist/skills/mcp/server.js +841 -0
  302. package/dist/skills/mcp/server.js.map +1 -0
  303. package/dist/skills/mcp/types.d.ts +72 -0
  304. package/dist/skills/mcp/types.d.ts.map +1 -0
  305. package/dist/skills/mcp/types.js +20 -0
  306. package/dist/skills/mcp/types.js.map +1 -0
  307. package/dist/skills/mcp/wireDefs.d.ts +58 -0
  308. package/dist/skills/mcp/wireDefs.d.ts.map +1 -0
  309. package/dist/skills/mcp/wireDefs.js +141 -0
  310. package/dist/skills/mcp/wireDefs.js.map +1 -0
  311. package/dist/skills/parser.d.ts +63 -0
  312. package/dist/skills/parser.d.ts.map +1 -0
  313. package/dist/skills/parser.js +755 -0
  314. package/dist/skills/parser.js.map +1 -0
  315. package/dist/skills/prefilter.d.ts +104 -0
  316. package/dist/skills/prefilter.d.ts.map +1 -0
  317. package/dist/skills/prefilter.js +398 -0
  318. package/dist/skills/prefilter.js.map +1 -0
  319. package/dist/skills/preprocess.d.ts +169 -0
  320. package/dist/skills/preprocess.d.ts.map +1 -0
  321. package/dist/skills/preprocess.js +535 -0
  322. package/dist/skills/preprocess.js.map +1 -0
  323. package/dist/skills/render.d.ts +83 -0
  324. package/dist/skills/render.d.ts.map +1 -0
  325. package/dist/skills/render.js +397 -0
  326. package/dist/skills/render.js.map +1 -0
  327. package/dist/skills/sources/index.browser.d.ts +29 -0
  328. package/dist/skills/sources/index.browser.d.ts.map +1 -0
  329. package/dist/skills/sources/index.browser.js +16 -0
  330. package/dist/skills/sources/index.browser.js.map +1 -0
  331. package/dist/skills/sources/index.d.ts +59 -0
  332. package/dist/skills/sources/index.d.ts.map +1 -0
  333. package/dist/skills/sources/index.js +471 -0
  334. package/dist/skills/sources/index.js.map +1 -0
  335. package/dist/skills/sources/walk.browser.d.ts +17 -0
  336. package/dist/skills/sources/walk.browser.d.ts.map +1 -0
  337. package/dist/skills/sources/walk.browser.js +19 -0
  338. package/dist/skills/sources/walk.browser.js.map +1 -0
  339. package/dist/skills/sources/walk.d.ts +68 -0
  340. package/dist/skills/sources/walk.d.ts.map +1 -0
  341. package/dist/skills/sources/walk.js +264 -0
  342. package/dist/skills/sources/walk.js.map +1 -0
  343. package/dist/skills/substitute.d.ts +87 -0
  344. package/dist/skills/substitute.d.ts.map +1 -0
  345. package/dist/skills/substitute.js +322 -0
  346. package/dist/skills/substitute.js.map +1 -0
  347. package/dist/skills/testing/SkillKit.browser.d.ts +62 -0
  348. package/dist/skills/testing/SkillKit.browser.d.ts.map +1 -0
  349. package/dist/skills/testing/SkillKit.browser.js +41 -0
  350. package/dist/skills/testing/SkillKit.browser.js.map +1 -0
  351. package/dist/skills/testing/SkillKit.d.ts +130 -0
  352. package/dist/skills/testing/SkillKit.d.ts.map +1 -0
  353. package/dist/skills/testing/SkillKit.js +316 -0
  354. package/dist/skills/testing/SkillKit.js.map +1 -0
  355. package/dist/skills/testing/index.d.ts +9 -0
  356. package/dist/skills/testing/index.d.ts.map +1 -0
  357. package/dist/skills/testing/index.js +8 -0
  358. package/dist/skills/testing/index.js.map +1 -0
  359. package/dist/skills/trust.d.ts +72 -0
  360. package/dist/skills/trust.d.ts.map +1 -0
  361. package/dist/skills/trust.js +183 -0
  362. package/dist/skills/trust.js.map +1 -0
  363. package/dist/skills/types.d.ts +627 -0
  364. package/dist/skills/types.d.ts.map +1 -0
  365. package/dist/skills/types.js +85 -0
  366. package/dist/skills/types.js.map +1 -0
  367. package/dist/skills/validator.d.ts +95 -0
  368. package/dist/skills/validator.d.ts.map +1 -0
  369. package/dist/skills/validator.js +486 -0
  370. package/dist/skills/validator.js.map +1 -0
  371. package/dist/tracing/PipelineTracer.d.ts +35 -22
  372. package/dist/tracing/PipelineTracer.d.ts.map +1 -1
  373. package/dist/tracing/PipelineTracer.js +106 -61
  374. package/dist/tracing/PipelineTracer.js.map +1 -1
  375. package/dist/tracing/SdkTracer.d.ts +63 -61
  376. package/dist/tracing/SdkTracer.d.ts.map +1 -1
  377. package/dist/tracing/SdkTracer.js +185 -177
  378. package/dist/tracing/SdkTracer.js.map +1 -1
  379. package/dist/tracing/index.d.ts +10 -1
  380. package/dist/tracing/index.d.ts.map +1 -1
  381. package/dist/tracing/index.js +9 -0
  382. package/dist/tracing/index.js.map +1 -1
  383. package/dist/tracing/types.d.ts +89 -16
  384. package/dist/tracing/types.d.ts.map +1 -1
  385. package/dist/tracing/types.js +17 -4
  386. package/dist/tracing/types.js.map +1 -1
  387. package/dist/types.d.ts +6 -1
  388. package/dist/types.d.ts.map +1 -1
  389. package/dist/types.js +4 -0
  390. package/dist/types.js.map +1 -1
  391. package/dist/version.d.ts.map +1 -1
  392. package/dist/version.js +10 -20
  393. package/dist/version.js.map +1 -1
  394. package/package.json +53 -39
  395. package/.claude/skills/qodo-agent/SKILL.md +0 -974
  396. package/.claude/skills/qodo-agent/assets/programmatic-agent.ts +0 -407
  397. package/.claude/skills/qodo-agent/references/builtin-tools.md +0 -342
  398. package/.claude/skills/qodo-agent/references/common-issues.md +0 -537
  399. package/bin/rg +0 -0
  400. package/dist/api/agent.d.ts +0 -105
  401. package/dist/api/agent.d.ts.map +0 -1
  402. package/dist/api/agent.js +0 -963
  403. package/dist/api/agent.js.map +0 -1
  404. package/dist/api/analytics.d.ts +0 -43
  405. package/dist/api/analytics.d.ts.map +0 -1
  406. package/dist/api/analytics.js +0 -163
  407. package/dist/api/analytics.js.map +0 -1
  408. package/dist/api/http.d.ts +0 -5
  409. package/dist/api/http.d.ts.map +0 -1
  410. package/dist/api/http.js +0 -62
  411. package/dist/api/http.js.map +0 -1
  412. package/dist/api/index.d.ts +0 -12
  413. package/dist/api/index.d.ts.map +0 -1
  414. package/dist/api/index.js +0 -17
  415. package/dist/api/index.js.map +0 -1
  416. package/dist/api/taskTracking.d.ts +0 -54
  417. package/dist/api/taskTracking.d.ts.map +0 -1
  418. package/dist/api/taskTracking.js +0 -208
  419. package/dist/api/taskTracking.js.map +0 -1
  420. package/dist/api/types.d.ts +0 -93
  421. package/dist/api/types.d.ts.map +0 -1
  422. package/dist/api/types.js +0 -2
  423. package/dist/api/types.js.map +0 -1
  424. package/dist/api/utils.d.ts +0 -8
  425. package/dist/api/utils.d.ts.map +0 -1
  426. package/dist/api/utils.js +0 -63
  427. package/dist/api/utils.js.map +0 -1
  428. package/dist/api/websocket.d.ts +0 -203
  429. package/dist/api/websocket.d.ts.map +0 -1
  430. package/dist/api/websocket.js +0 -1166
  431. package/dist/api/websocket.js.map +0 -1
  432. package/dist/bin/install-skill.d.ts +0 -14
  433. package/dist/bin/install-skill.d.ts.map +0 -1
  434. package/dist/bin/install-skill.js +0 -125
  435. package/dist/bin/install-skill.js.map +0 -1
  436. package/dist/bin/run-helpers.d.ts +0 -34
  437. package/dist/bin/run-helpers.d.ts.map +0 -1
  438. package/dist/bin/run-helpers.js +0 -186
  439. package/dist/bin/run-helpers.js.map +0 -1
  440. package/dist/bin/run.d.ts +0 -13
  441. package/dist/bin/run.d.ts.map +0 -1
  442. package/dist/bin/run.js +0 -57
  443. package/dist/bin/run.js.map +0 -1
  444. package/dist/clients/index.d.ts +0 -10
  445. package/dist/clients/index.d.ts.map +0 -1
  446. package/dist/clients/index.js +0 -8
  447. package/dist/clients/index.js.map +0 -1
  448. package/dist/clients/info/InfoClient.d.ts +0 -37
  449. package/dist/clients/info/InfoClient.d.ts.map +0 -1
  450. package/dist/clients/info/InfoClient.js +0 -69
  451. package/dist/clients/info/InfoClient.js.map +0 -1
  452. package/dist/clients/info/index.d.ts +0 -4
  453. package/dist/clients/info/index.d.ts.map +0 -1
  454. package/dist/clients/info/index.js +0 -2
  455. package/dist/clients/info/index.js.map +0 -1
  456. package/dist/clients/info/types.d.ts +0 -21
  457. package/dist/clients/info/types.d.ts.map +0 -1
  458. package/dist/clients/info/types.js +0 -2
  459. package/dist/clients/info/types.js.map +0 -1
  460. package/dist/clients/sessions/SessionsClient.d.ts +0 -34
  461. package/dist/clients/sessions/SessionsClient.d.ts.map +0 -1
  462. package/dist/clients/sessions/SessionsClient.js +0 -71
  463. package/dist/clients/sessions/SessionsClient.js.map +0 -1
  464. package/dist/clients/sessions/index.d.ts +0 -4
  465. package/dist/clients/sessions/index.d.ts.map +0 -1
  466. package/dist/clients/sessions/index.js +0 -2
  467. package/dist/clients/sessions/index.js.map +0 -1
  468. package/dist/clients/sessions/types.d.ts +0 -20
  469. package/dist/clients/sessions/types.d.ts.map +0 -1
  470. package/dist/clients/sessions/types.js +0 -2
  471. package/dist/clients/sessions/types.js.map +0 -1
  472. package/dist/clients/tools/ToolsClient.d.ts +0 -39
  473. package/dist/clients/tools/ToolsClient.d.ts.map +0 -1
  474. package/dist/clients/tools/ToolsClient.js +0 -95
  475. package/dist/clients/tools/ToolsClient.js.map +0 -1
  476. package/dist/clients/tools/index.d.ts +0 -4
  477. package/dist/clients/tools/index.d.ts.map +0 -1
  478. package/dist/clients/tools/index.js +0 -2
  479. package/dist/clients/tools/index.js.map +0 -1
  480. package/dist/clients/tools/types.d.ts +0 -14
  481. package/dist/clients/tools/types.d.ts.map +0 -1
  482. package/dist/clients/tools/types.js +0 -2
  483. package/dist/clients/tools/types.js.map +0 -1
  484. package/dist/config/ConfigManager.d.ts +0 -43
  485. package/dist/config/ConfigManager.d.ts.map +0 -1
  486. package/dist/config/ConfigManager.js +0 -472
  487. package/dist/config/ConfigManager.js.map +0 -1
  488. package/dist/config/index.d.ts +0 -6
  489. package/dist/config/index.d.ts.map +0 -1
  490. package/dist/config/index.js +0 -7
  491. package/dist/config/index.js.map +0 -1
  492. package/dist/config/urlConfig.d.ts +0 -15
  493. package/dist/config/urlConfig.d.ts.map +0 -1
  494. package/dist/config/urlConfig.js +0 -75
  495. package/dist/config/urlConfig.js.map +0 -1
  496. package/dist/constants/errors.d.ts +0 -2
  497. package/dist/constants/errors.d.ts.map +0 -1
  498. package/dist/constants/errors.js +0 -2
  499. package/dist/constants/errors.js.map +0 -1
  500. package/dist/constants/index.d.ts +0 -7
  501. package/dist/constants/index.d.ts.map +0 -1
  502. package/dist/constants/index.js +0 -11
  503. package/dist/constants/index.js.map +0 -1
  504. package/dist/constants/tools.d.ts +0 -4
  505. package/dist/constants/tools.d.ts.map +0 -1
  506. package/dist/constants/tools.js +0 -4
  507. package/dist/constants/tools.js.map +0 -1
  508. package/dist/constants/versions.d.ts +0 -2
  509. package/dist/constants/versions.d.ts.map +0 -1
  510. package/dist/constants/versions.js +0 -2
  511. package/dist/constants/versions.js.map +0 -1
  512. package/dist/context/buildUserContext.d.ts +0 -18
  513. package/dist/context/buildUserContext.d.ts.map +0 -1
  514. package/dist/context/buildUserContext.js +0 -34
  515. package/dist/context/buildUserContext.js.map +0 -1
  516. package/dist/context/index.d.ts +0 -9
  517. package/dist/context/index.d.ts.map +0 -1
  518. package/dist/context/index.js +0 -9
  519. package/dist/context/index.js.map +0 -1
  520. package/dist/context/messageManager.d.ts +0 -42
  521. package/dist/context/messageManager.d.ts.map +0 -1
  522. package/dist/context/messageManager.js +0 -322
  523. package/dist/context/messageManager.js.map +0 -1
  524. package/dist/context/taskFocus.d.ts +0 -2
  525. package/dist/context/taskFocus.d.ts.map +0 -1
  526. package/dist/context/taskFocus.js +0 -26
  527. package/dist/context/taskFocus.js.map +0 -1
  528. package/dist/context/userInput.d.ts +0 -3
  529. package/dist/context/userInput.d.ts.map +0 -1
  530. package/dist/context/userInput.js +0 -20
  531. package/dist/context/userInput.js.map +0 -1
  532. package/dist/mcp/MCPManager.d.ts +0 -109
  533. package/dist/mcp/MCPManager.d.ts.map +0 -1
  534. package/dist/mcp/MCPManager.js +0 -592
  535. package/dist/mcp/MCPManager.js.map +0 -1
  536. package/dist/mcp/approvedTools.d.ts +0 -4
  537. package/dist/mcp/approvedTools.d.ts.map +0 -1
  538. package/dist/mcp/approvedTools.js +0 -19
  539. package/dist/mcp/approvedTools.js.map +0 -1
  540. package/dist/mcp/baseServer.d.ts +0 -75
  541. package/dist/mcp/baseServer.d.ts.map +0 -1
  542. package/dist/mcp/baseServer.js +0 -107
  543. package/dist/mcp/baseServer.js.map +0 -1
  544. package/dist/mcp/builtinServers.d.ts +0 -15
  545. package/dist/mcp/builtinServers.d.ts.map +0 -1
  546. package/dist/mcp/builtinServers.js +0 -141
  547. package/dist/mcp/builtinServers.js.map +0 -1
  548. package/dist/mcp/dynamicBEServer.d.ts +0 -20
  549. package/dist/mcp/dynamicBEServer.d.ts.map +0 -1
  550. package/dist/mcp/dynamicBEServer.js +0 -52
  551. package/dist/mcp/dynamicBEServer.js.map +0 -1
  552. package/dist/mcp/index.d.ts +0 -18
  553. package/dist/mcp/index.d.ts.map +0 -1
  554. package/dist/mcp/index.js +0 -23
  555. package/dist/mcp/index.js.map +0 -1
  556. package/dist/mcp/mcpInitialization.d.ts +0 -2
  557. package/dist/mcp/mcpInitialization.d.ts.map +0 -1
  558. package/dist/mcp/mcpInitialization.js +0 -56
  559. package/dist/mcp/mcpInitialization.js.map +0 -1
  560. package/dist/mcp/servers/filesystem.d.ts +0 -44
  561. package/dist/mcp/servers/filesystem.d.ts.map +0 -1
  562. package/dist/mcp/servers/filesystem.js +0 -776
  563. package/dist/mcp/servers/filesystem.js.map +0 -1
  564. package/dist/mcp/servers/git.d.ts +0 -18
  565. package/dist/mcp/servers/git.d.ts.map +0 -1
  566. package/dist/mcp/servers/git.js +0 -441
  567. package/dist/mcp/servers/git.js.map +0 -1
  568. package/dist/mcp/servers/ripgrep.d.ts +0 -39
  569. package/dist/mcp/servers/ripgrep.d.ts.map +0 -1
  570. package/dist/mcp/servers/ripgrep.js +0 -550
  571. package/dist/mcp/servers/ripgrep.js.map +0 -1
  572. package/dist/mcp/servers/shell.d.ts +0 -20
  573. package/dist/mcp/servers/shell.d.ts.map +0 -1
  574. package/dist/mcp/servers/shell.js +0 -519
  575. package/dist/mcp/servers/shell.js.map +0 -1
  576. package/dist/mcp/serversRegistry.d.ts +0 -55
  577. package/dist/mcp/serversRegistry.d.ts.map +0 -1
  578. package/dist/mcp/serversRegistry.js +0 -416
  579. package/dist/mcp/serversRegistry.js.map +0 -1
  580. package/dist/mcp/toolProcessor.d.ts +0 -82
  581. package/dist/mcp/toolProcessor.d.ts.map +0 -1
  582. package/dist/mcp/toolProcessor.js +0 -392
  583. package/dist/mcp/toolProcessor.js.map +0 -1
  584. package/dist/mcp/types.d.ts +0 -29
  585. package/dist/mcp/types.d.ts.map +0 -1
  586. package/dist/mcp/types.js +0 -2
  587. package/dist/mcp/types.js.map +0 -1
  588. package/dist/messages/index.d.ts +0 -8
  589. package/dist/messages/index.d.ts.map +0 -1
  590. package/dist/messages/index.js +0 -7
  591. package/dist/messages/index.js.map +0 -1
  592. package/dist/messages/openai.d.ts +0 -26
  593. package/dist/messages/openai.d.ts.map +0 -1
  594. package/dist/messages/openai.js +0 -55
  595. package/dist/messages/openai.js.map +0 -1
  596. package/dist/messages/types.d.ts +0 -73
  597. package/dist/messages/types.d.ts.map +0 -1
  598. package/dist/messages/types.js +0 -78
  599. package/dist/messages/types.js.map +0 -1
  600. package/dist/parser/index.d.ts +0 -72
  601. package/dist/parser/index.d.ts.map +0 -1
  602. package/dist/parser/index.js +0 -967
  603. package/dist/parser/index.js.map +0 -1
  604. package/dist/parser/types.d.ts +0 -153
  605. package/dist/parser/types.d.ts.map +0 -1
  606. package/dist/parser/types.js +0 -6
  607. package/dist/parser/types.js.map +0 -1
  608. package/dist/parser/utils.d.ts +0 -18
  609. package/dist/parser/utils.d.ts.map +0 -1
  610. package/dist/parser/utils.js +0 -64
  611. package/dist/parser/utils.js.map +0 -1
  612. package/dist/sdk/QodoSDK.d.ts +0 -218
  613. package/dist/sdk/QodoSDK.d.ts.map +0 -1
  614. package/dist/sdk/QodoSDK.js +0 -1115
  615. package/dist/sdk/QodoSDK.js.map +0 -1
  616. package/dist/sdk/artifacts.d.ts +0 -156
  617. package/dist/sdk/artifacts.d.ts.map +0 -1
  618. package/dist/sdk/artifacts.js +0 -166
  619. package/dist/sdk/artifacts.js.map +0 -1
  620. package/dist/sdk/bootstrap.d.ts +0 -16
  621. package/dist/sdk/bootstrap.d.ts.map +0 -1
  622. package/dist/sdk/bootstrap.js +0 -28
  623. package/dist/sdk/bootstrap.js.map +0 -1
  624. package/dist/sdk/builders.d.ts +0 -54
  625. package/dist/sdk/builders.d.ts.map +0 -1
  626. package/dist/sdk/builders.js +0 -117
  627. package/dist/sdk/builders.js.map +0 -1
  628. package/dist/sdk/defaults.d.ts +0 -11
  629. package/dist/sdk/defaults.d.ts.map +0 -1
  630. package/dist/sdk/defaults.js +0 -39
  631. package/dist/sdk/defaults.js.map +0 -1
  632. package/dist/sdk/discovery.d.ts +0 -2
  633. package/dist/sdk/discovery.d.ts.map +0 -1
  634. package/dist/sdk/discovery.js +0 -25
  635. package/dist/sdk/discovery.js.map +0 -1
  636. package/dist/sdk/events.d.ts +0 -269
  637. package/dist/sdk/events.d.ts.map +0 -1
  638. package/dist/sdk/events.js +0 -69
  639. package/dist/sdk/events.js.map +0 -1
  640. package/dist/sdk/exit-expression.d.ts +0 -13
  641. package/dist/sdk/exit-expression.d.ts.map +0 -1
  642. package/dist/sdk/exit-expression.js +0 -35
  643. package/dist/sdk/exit-expression.js.map +0 -1
  644. package/dist/sdk/index.d.ts +0 -17
  645. package/dist/sdk/index.d.ts.map +0 -1
  646. package/dist/sdk/index.js +0 -17
  647. package/dist/sdk/index.js.map +0 -1
  648. package/dist/sdk/middleware.d.ts +0 -59
  649. package/dist/sdk/middleware.d.ts.map +0 -1
  650. package/dist/sdk/middleware.js +0 -69
  651. package/dist/sdk/middleware.js.map +0 -1
  652. package/dist/sdk/pipeline/PipelineBuilder.d.ts +0 -79
  653. package/dist/sdk/pipeline/PipelineBuilder.d.ts.map +0 -1
  654. package/dist/sdk/pipeline/PipelineBuilder.js +0 -129
  655. package/dist/sdk/pipeline/PipelineBuilder.js.map +0 -1
  656. package/dist/sdk/pipeline/PipelineRunner.d.ts +0 -28
  657. package/dist/sdk/pipeline/PipelineRunner.d.ts.map +0 -1
  658. package/dist/sdk/pipeline/PipelineRunner.js +0 -326
  659. package/dist/sdk/pipeline/PipelineRunner.js.map +0 -1
  660. package/dist/sdk/pipeline/compiler.d.ts +0 -24
  661. package/dist/sdk/pipeline/compiler.d.ts.map +0 -1
  662. package/dist/sdk/pipeline/compiler.js +0 -199
  663. package/dist/sdk/pipeline/compiler.js.map +0 -1
  664. package/dist/sdk/pipeline/declarative.d.ts +0 -34
  665. package/dist/sdk/pipeline/declarative.d.ts.map +0 -1
  666. package/dist/sdk/pipeline/declarative.js +0 -9
  667. package/dist/sdk/pipeline/declarative.js.map +0 -1
  668. package/dist/sdk/pipeline/index.d.ts +0 -20
  669. package/dist/sdk/pipeline/index.d.ts.map +0 -1
  670. package/dist/sdk/pipeline/index.js +0 -19
  671. package/dist/sdk/pipeline/index.js.map +0 -1
  672. package/dist/sdk/pipeline/types.d.ts +0 -93
  673. package/dist/sdk/pipeline/types.d.ts.map +0 -1
  674. package/dist/sdk/pipeline/types.js +0 -10
  675. package/dist/sdk/pipeline/types.js.map +0 -1
  676. package/dist/sdk/policies.d.ts +0 -163
  677. package/dist/sdk/policies.d.ts.map +0 -1
  678. package/dist/sdk/policies.js +0 -243
  679. package/dist/sdk/policies.js.map +0 -1
  680. package/dist/sdk/runner/AgentRunner.d.ts +0 -22
  681. package/dist/sdk/runner/AgentRunner.d.ts.map +0 -1
  682. package/dist/sdk/runner/AgentRunner.js +0 -222
  683. package/dist/sdk/runner/AgentRunner.js.map +0 -1
  684. package/dist/sdk/runner/finalize.d.ts +0 -56
  685. package/dist/sdk/runner/finalize.d.ts.map +0 -1
  686. package/dist/sdk/runner/finalize.js +0 -155
  687. package/dist/sdk/runner/finalize.js.map +0 -1
  688. package/dist/sdk/runner/formats.d.ts +0 -7
  689. package/dist/sdk/runner/formats.d.ts.map +0 -1
  690. package/dist/sdk/runner/formats.js +0 -76
  691. package/dist/sdk/runner/formats.js.map +0 -1
  692. package/dist/sdk/runner/index.d.ts +0 -9
  693. package/dist/sdk/runner/index.d.ts.map +0 -1
  694. package/dist/sdk/runner/index.js +0 -9
  695. package/dist/sdk/runner/index.js.map +0 -1
  696. package/dist/sdk/runner/progress.d.ts +0 -3
  697. package/dist/sdk/runner/progress.d.ts.map +0 -1
  698. package/dist/sdk/runner/progress.js +0 -16
  699. package/dist/sdk/runner/progress.js.map +0 -1
  700. package/dist/sdk/schemas.d.ts +0 -72
  701. package/dist/sdk/schemas.d.ts.map +0 -1
  702. package/dist/sdk/schemas.js +0 -282
  703. package/dist/sdk/schemas.js.map +0 -1
  704. package/dist/sdk/trigger-context.d.ts +0 -24
  705. package/dist/sdk/trigger-context.d.ts.map +0 -1
  706. package/dist/sdk/trigger-context.js +0 -136
  707. package/dist/sdk/trigger-context.js.map +0 -1
  708. package/dist/session/SessionContext.d.ts +0 -89
  709. package/dist/session/SessionContext.d.ts.map +0 -1
  710. package/dist/session/SessionContext.js +0 -410
  711. package/dist/session/SessionContext.js.map +0 -1
  712. package/dist/session/environment.d.ts +0 -52
  713. package/dist/session/environment.d.ts.map +0 -1
  714. package/dist/session/environment.js +0 -27
  715. package/dist/session/environment.js.map +0 -1
  716. package/dist/session/history.d.ts +0 -18
  717. package/dist/session/history.d.ts.map +0 -1
  718. package/dist/session/history.js +0 -68
  719. package/dist/session/history.js.map +0 -1
  720. package/dist/session/index.d.ts +0 -10
  721. package/dist/session/index.d.ts.map +0 -1
  722. package/dist/session/index.js +0 -9
  723. package/dist/session/index.js.map +0 -1
  724. package/dist/session/serverData.d.ts +0 -38
  725. package/dist/session/serverData.d.ts.map +0 -1
  726. package/dist/session/serverData.js +0 -261
  727. package/dist/session/serverData.js.map +0 -1
  728. package/dist/tracing/pipelineHelpers.d.ts +0 -29
  729. package/dist/tracing/pipelineHelpers.d.ts.map +0 -1
  730. package/dist/tracing/pipelineHelpers.js +0 -224
  731. package/dist/tracing/pipelineHelpers.js.map +0 -1
  732. package/dist/tracking/Tracker.d.ts +0 -55
  733. package/dist/tracking/Tracker.d.ts.map +0 -1
  734. package/dist/tracking/Tracker.js +0 -217
  735. package/dist/tracking/Tracker.js.map +0 -1
  736. package/dist/tracking/index.d.ts +0 -8
  737. package/dist/tracking/index.d.ts.map +0 -1
  738. package/dist/tracking/index.js +0 -8
  739. package/dist/tracking/index.js.map +0 -1
  740. package/dist/tracking/schemas.d.ts +0 -292
  741. package/dist/tracking/schemas.d.ts.map +0 -1
  742. package/dist/tracking/schemas.js +0 -91
  743. package/dist/tracking/schemas.js.map +0 -1
  744. package/dist/utils/extractSetFlags.d.ts +0 -6
  745. package/dist/utils/extractSetFlags.d.ts.map +0 -1
  746. package/dist/utils/extractSetFlags.js +0 -16
  747. package/dist/utils/extractSetFlags.js.map +0 -1
  748. package/dist/utils/formatTimeAgo.d.ts +0 -2
  749. package/dist/utils/formatTimeAgo.d.ts.map +0 -1
  750. package/dist/utils/formatTimeAgo.js +0 -20
  751. package/dist/utils/formatTimeAgo.js.map +0 -1
  752. package/dist/utils/index.d.ts +0 -12
  753. package/dist/utils/index.d.ts.map +0 -1
  754. package/dist/utils/index.js +0 -12
  755. package/dist/utils/index.js.map +0 -1
  756. package/dist/utils/machineId.d.ts +0 -14
  757. package/dist/utils/machineId.d.ts.map +0 -1
  758. package/dist/utils/machineId.js +0 -66
  759. package/dist/utils/machineId.js.map +0 -1
  760. package/dist/utils/pathUtils.d.ts +0 -22
  761. package/dist/utils/pathUtils.d.ts.map +0 -1
  762. package/dist/utils/pathUtils.js +0 -54
  763. package/dist/utils/pathUtils.js.map +0 -1
  764. package/scripts/download-ripgrep.js +0 -269
@@ -1,1166 +0,0 @@
1
- import WebSocket from "ws";
2
- import { EventEmitter } from "events";
3
- import { v4 as uuid } from "uuid";
4
- import { getAuthConfig } from "../auth/index.js";
5
- import { ServerData } from "../session/index.js";
6
- import { getCurrentEnvironment } from "../session/index.js";
7
- // WebSocket-specific configuration
8
- const WS_CONFIG = {
9
- IDLE_TIMEOUT: 600000,
10
- HEARTBEAT_INTERVAL: 30000,
11
- HEARTBEAT_TIMEOUT: 60000,
12
- CONNECTION_TIMEOUT: 15000,
13
- INITIAL_RECONNECT_DELAY: 1000,
14
- MAX_RECONNECT_DELAY: 30000,
15
- RECONNECT_BACKOFF_FACTOR: 1.5,
16
- MESSAGE_QUEUE_MAX_SIZE: 1000,
17
- READY_TIMEOUT: 300000,
18
- };
19
- export var ConnectionState;
20
- (function (ConnectionState) {
21
- ConnectionState["DISCONNECTED"] = "DISCONNECTED";
22
- ConnectionState["CONNECTING"] = "CONNECTING";
23
- ConnectionState["CONNECTED"] = "CONNECTED";
24
- ConnectionState["RECONNECTING"] = "RECONNECTING";
25
- ConnectionState["DISCONNECTING"] = "DISCONNECTING";
26
- ConnectionState["FAILED"] = "FAILED";
27
- })(ConnectionState || (ConnectionState = {}));
28
- export var ReadyState;
29
- (function (ReadyState) {
30
- ReadyState["IDLE"] = "IDLE";
31
- /**
32
- * Post-connect, waiting for ResumeAck from the server before sending any
33
- * turn. Replaces the old WAITING_INITIAL_READY — the server's authoritative
34
- * view is now the precondition for proceeding, not a bare "Ready" signal.
35
- */
36
- ReadyState["AWAITING_RESUME_ACK"] = "AWAITING_RESUME_ACK";
37
- ReadyState["WAITING_INITIAL_READY"] = "WAITING_INITIAL_READY";
38
- ReadyState["READY"] = "READY";
39
- ReadyState["MESSAGE_SENT"] = "MESSAGE_SENT";
40
- ReadyState["WAITING_READY"] = "WAITING_READY";
41
- ReadyState["CHECKPOINT_RECOVERY"] = "CHECKPOINT_RECOVERY";
42
- })(ReadyState || (ReadyState = {}));
43
- export class WebSocketClient extends EventEmitter {
44
- ws;
45
- shouldDebugLog() {
46
- const env = getCurrentEnvironment();
47
- // In SDK mode, default is silent unless sdkDebug=true or QODO_DEBUG=true.
48
- if (env?.sdkMode) {
49
- return !!env.sdkDebug || process.env.QODO_DEBUG === 'true';
50
- }
51
- return process.env.QODO_DEBUG === 'true';
52
- }
53
- debug(...args) {
54
- if (this.shouldDebugLog()) {
55
- // eslint-disable-next-line no-console
56
- console.debug(...args);
57
- }
58
- }
59
- state = ConnectionState.DISCONNECTED;
60
- sessionId;
61
- requestId;
62
- connectionId;
63
- // Idle management
64
- idleTimer;
65
- autoDisconnected = false;
66
- // Heartbeat management
67
- heartbeatInterval;
68
- lastPongReceived = Date.now();
69
- lastPingSent = 0;
70
- // Reconnection management
71
- reconnectAttempts = 0;
72
- reconnectTimer;
73
- isReconnecting = false;
74
- // Message queue for handling during disconnection
75
- messageQueue = [];
76
- isProcessingQueue = false;
77
- // Ready protocol state management
78
- readyState = ReadyState.IDLE;
79
- latestCheckpointId;
80
- lastSentMessage;
81
- readyTimer;
82
- receivedResponsesSinceMessage = false; // Track if any responses received after sending message
83
- /**
84
- * Protocol-v2 counters. Public read-only via `getMetrics()` — wired into
85
- * SDK telemetry so observability dashboards can alert on e.g. rising
86
- * `reconcile_failures_total` without digging through debug logs.
87
- */
88
- metrics = {
89
- reconnects_total: 0,
90
- turns_sent_total: 0,
91
- turns_acked_total: 0,
92
- turns_replayed_total: 0,
93
- resume_acks_total: 0,
94
- reconcile_failures_total: 0,
95
- stalls_detected_total: 0,
96
- idempotent_replays_total: 0,
97
- };
98
- /** Last time the socket transitioned from CONNECTED to not-CONNECTED; used for downtime metrics. */
99
- lastDisconnectAt;
100
- getMetrics() {
101
- return { ...this.metrics };
102
- }
103
- /**
104
- * Outbox of turns the client has sent (or is about to send) but has not
105
- * received a TurnAck for. Keyed by turn_id so idempotent replay across
106
- * reconnect is an O(1) lookup. Only pruned on TurnAck or ResumeAck.
107
- */
108
- outbox = new Map();
109
- /**
110
- * FIFO order of turn_ids in the outbox. We send one turn at a time — the
111
- * Ready/MESSAGE_SENT ping-pong enforces this — but the order matters for
112
- * replay after reconcile, so we track it explicitly rather than relying on
113
- * Map iteration order across Node versions.
114
- */
115
- outboxOrder = [];
116
- /** SLA timer: Resume must be ack'd within this window or the socket is dead. */
117
- resumeAckTimer;
118
- /** SLA timer: post-ResumeAck, the server must produce forward progress or we surface a stall. */
119
- postResumeProgressTimer;
120
- /**
121
- * Short grace period after a bare Ready arrives while we're awaiting a
122
- * ResumeAck. If no ResumeAck shows up in that window, we assume the
123
- * backend is a pre-v2 deployment that only emits Ready and fall back —
124
- * instead of hanging for 15s until the ResumeAck SLA closes the socket.
125
- */
126
- legacyFallbackTimer;
127
- /**
128
- * Flips true on the first transition to READY and stays true for the life
129
- * of the instance. Represents "initial handshake has completed at least
130
- * once." Used by ``handleClose`` to distinguish startup failures (fail
131
- * fast with a real error) from mid-session drops (enter reconnect loop).
132
- * Decoupling this from specific ReadyState values means new handshake
133
- * states can be added without silently changing close behavior.
134
- */
135
- hasCompletedHandshake = false;
136
- /** Expose current ready state so callers can detect post-await state changes. */
137
- getReadyState() {
138
- return this.readyState;
139
- }
140
- hasReceivedResponsesSinceLastMessage() {
141
- return this.receivedResponsesSinceMessage;
142
- }
143
- // Connection-timeout timer (ensure we clear/unref to avoid keeping event loop alive)
144
- connectionTimeoutTimer;
145
- constructor() {
146
- super();
147
- }
148
- setState(newState) {
149
- if (this.state !== newState) {
150
- const oldState = this.state;
151
- this.state = newState;
152
- this.debug(`[WebSocketClient] Connection state transition: ${oldState} → ${newState} | ` +
153
- `ReadyState: ${this.readyState} | ` +
154
- `Session: ${this.sessionId?.substring(0, 8)}...`);
155
- this.emit('stateChanged', newState);
156
- }
157
- }
158
- setReadyState(newState, context) {
159
- if (this.readyState !== newState) {
160
- const oldState = this.readyState;
161
- this.readyState = newState;
162
- // First entry into READY marks the handshake as complete. Any close
163
- // before this point is a startup failure; any close after is a
164
- // mid-session drop that should trigger the reconnect loop.
165
- if (newState === ReadyState.READY && !this.hasCompletedHandshake) {
166
- this.hasCompletedHandshake = true;
167
- }
168
- // Leaving AWAITING_RESUME_ACK — either we got what we wanted
169
- // (ResumeAck) or we gave up. Either way the legacy-fallback grace
170
- // timer is no longer relevant.
171
- if (oldState === ReadyState.AWAITING_RESUME_ACK) {
172
- this.clearLegacyFallbackTimer();
173
- }
174
- this.debug(`[WebSocketClient] Ready state transition: ${oldState} → ${newState}` +
175
- (context ? ` | Context: ${context}` : '') +
176
- ` | Session: ${this.sessionId?.substring(0, 8)}...` +
177
- ` | Checkpoint: ${this.latestCheckpointId?.substring(0, 8) || 'none'}`);
178
- this.emit('readyStateChanged', { oldState, newState, context });
179
- }
180
- }
181
- /**
182
- * SLA for the Resume→ResumeAck round trip. Tuned to cover a cold graph load
183
- * from postgres with some headroom, but tight enough that a silently dead
184
- * socket reveals itself before the outer timeout layer even notices.
185
- */
186
- static RESUME_ACK_TIMEOUT_MS = 15000;
187
- /**
188
- * SLA for "something must happen after ResumeAck." If the server says it's
189
- * awaiting nothing and we also have nothing to send, we stay in READY (not
190
- * a stall). Otherwise a quiet socket for this long is a stall.
191
- */
192
- static POST_RESUME_PROGRESS_TIMEOUT_MS = 30000;
193
- /**
194
- * Grace period after a bare Ready arrives in AWAITING_RESUME_ACK. Long
195
- * enough to cover the backend's ResumeAck round-trip latency, short
196
- * enough that a true legacy server doesn't hang the SDK startup.
197
- */
198
- static LEGACY_READY_FALLBACK_MS = 2000;
199
- addToOutbox(turn) {
200
- if (this.outbox.has(turn.turn_id))
201
- return;
202
- this.outbox.set(turn.turn_id, turn);
203
- this.outboxOrder.push(turn.turn_id);
204
- this.metrics.turns_sent_total++;
205
- }
206
- removeFromOutbox(turnId) {
207
- if (!this.outbox.delete(turnId))
208
- return false;
209
- const idx = this.outboxOrder.indexOf(turnId);
210
- if (idx >= 0)
211
- this.outboxOrder.splice(idx, 1);
212
- return true;
213
- }
214
- outboxSnapshot() {
215
- return this.outboxOrder
216
- .map(id => this.outbox.get(id))
217
- .filter((t) => t !== undefined);
218
- }
219
- /** Build the client half of a PendingTurn for the Resume envelope. */
220
- pendingTurnDescriptor(turn) {
221
- if (turn.type === 'UserQuery') {
222
- return { turn_id: turn.turn_id, type: 'prompt' };
223
- }
224
- return {
225
- turn_id: turn.turn_id,
226
- type: 'tool_result',
227
- ...(turn.tool_call_id ? { tool_call_id: turn.tool_call_id } : {}),
228
- };
229
- }
230
- clearResumeAckTimer() {
231
- if (this.resumeAckTimer) {
232
- clearTimeout(this.resumeAckTimer);
233
- this.resumeAckTimer = undefined;
234
- }
235
- }
236
- clearPostResumeProgressTimer() {
237
- if (this.postResumeProgressTimer) {
238
- clearTimeout(this.postResumeProgressTimer);
239
- this.postResumeProgressTimer = undefined;
240
- }
241
- }
242
- startResumeAckTimer() {
243
- this.clearResumeAckTimer();
244
- this.resumeAckTimer = setTimeout(() => {
245
- this.debug(`[WebSocketClient] ResumeAck timeout expired | ` +
246
- `State: ${this.readyState} | ` +
247
- `Session: ${this.sessionId?.substring(0, 8)}...`);
248
- // The server didn't reply to Resume — treat the socket as dead and cycle it.
249
- try {
250
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
251
- this.ws.close(4001, 'ResumeAck timeout');
252
- }
253
- }
254
- catch { /* cleanup: forcing close on an already-closing socket is expected to no-op */ }
255
- this.emit('resumeAckTimeout');
256
- }, WebSocketClient.RESUME_ACK_TIMEOUT_MS);
257
- this.resumeAckTimer.unref?.();
258
- }
259
- clearLegacyFallbackTimer() {
260
- if (this.legacyFallbackTimer) {
261
- clearTimeout(this.legacyFallbackTimer);
262
- this.legacyFallbackTimer = undefined;
263
- }
264
- }
265
- /**
266
- * Start the legacy-server fallback grace period.
267
- *
268
- * Called when we receive a bare ``Ready`` while still in
269
- * ``AWAITING_RESUME_ACK``. In the normal v2 flow the server sends Ready
270
- * first and ResumeAck right after — we want to wait for ResumeAck. But if
271
- * the server is a pre-v2 deployment that never emits ResumeAck, waiting
272
- * for the 15s SLA would stall every startup. Instead, we wait a short
273
- * grace period; if no ResumeAck arrives, we treat the Ready we already
274
- * saw as a legacy-protocol signal and transition to READY.
275
- */
276
- startLegacyFallbackTimer() {
277
- // Idempotent — multiple Ready messages shouldn't pile up timers.
278
- if (this.legacyFallbackTimer)
279
- return;
280
- this.legacyFallbackTimer = setTimeout(() => {
281
- this.legacyFallbackTimer = undefined;
282
- if (this.readyState !== ReadyState.AWAITING_RESUME_ACK)
283
- return;
284
- this.debug(`[WebSocketClient] Legacy fallback: Ready seen without ResumeAck, ` +
285
- `assuming pre-v2 backend | outbox: ${this.outbox.size}`);
286
- // Cancel the longer ResumeAck SLA — we've decided the server doesn't speak it.
287
- this.clearResumeAckTimer();
288
- this.setReadyState(ReadyState.READY, 'Legacy fallback after Ready without ResumeAck');
289
- // Drain anything queued. Legacy flow has no TurnAck, so outbox
290
- // entries will linger; a later reconnect (against a v2 backend)
291
- // would reconcile them, but that's out of scope for this path.
292
- void this.processOutbox();
293
- }, WebSocketClient.LEGACY_READY_FALLBACK_MS);
294
- this.legacyFallbackTimer.unref?.();
295
- }
296
- startPostResumeProgressTimer() {
297
- this.clearPostResumeProgressTimer();
298
- this.postResumeProgressTimer = setTimeout(() => {
299
- this.debug(`[WebSocketClient] Post-ResumeAck stall | ` +
300
- `State: ${this.readyState} | ` +
301
- `Outbox size: ${this.outbox.size} | ` +
302
- `Session: ${this.sessionId?.substring(0, 8)}...`);
303
- this.metrics.stalls_detected_total++;
304
- this.emit('stallDetected', {
305
- stage: 'post_resume',
306
- outboxSize: this.outbox.size,
307
- });
308
- }, WebSocketClient.POST_RESUME_PROGRESS_TIMEOUT_MS);
309
- this.postResumeProgressTimer.unref?.();
310
- }
311
- /**
312
- * Send the protocol-v2 Resume envelope. Called on every (re)connect before
313
- * any turn can flow. Gives the backend enough state to reply with an
314
- * authoritative ResumeAck.
315
- */
316
- sendResume() {
317
- if (!this.ws || this.state !== ConnectionState.CONNECTED) {
318
- this.debug('[WebSocketClient] sendResume: socket not connected, skipping');
319
- return;
320
- }
321
- const payload = {
322
- last_seen_checkpoint: this.latestCheckpointId ?? null,
323
- pending_turns: this.outboxSnapshot().map(t => this.pendingTurnDescriptor(t)),
324
- };
325
- const formatted = `Resume ${JSON.stringify(payload)}\n`;
326
- try {
327
- this.ws.send(formatted);
328
- this.debug(`[WebSocketClient] Sent Resume | ` +
329
- `pending_turns: ${payload.pending_turns.length} | ` +
330
- `last_seen_checkpoint: ${(this.latestCheckpointId ?? 'none').toString().substring(0, 8)}`);
331
- this.setReadyState(ReadyState.AWAITING_RESUME_ACK, 'Resume sent');
332
- this.startResumeAckTimer();
333
- }
334
- catch (err) {
335
- this.debug('[WebSocketClient] Error sending Resume:', err);
336
- }
337
- }
338
- /**
339
- * Apply the server's authoritative view. This is the anti-deadlock primitive:
340
- * every reconnect path runs through here and produces an explicit decision
341
- * instead of both sides waiting on each other.
342
- *
343
- * Reconcile only runs on the FIRST ResumeAck of a (re)connect — the one we
344
- * were explicitly waiting for. Any subsequent ResumeAcks (e.g. the server
345
- * re-emits one as a loop-top heartbeat, or replies to our Resume probe) are
346
- * informational; acting on them would double-send turns we've already
347
- * replayed.
348
- */
349
- async handleResumeAck(message) {
350
- const args = message?.data?.tool_args ?? {};
351
- const currentCheckpoint = args.current_checkpoint;
352
- const lastConsumedTurnId = args.last_consumed_turn_id;
353
- const awaiting = args.awaiting ?? { type: 'none' };
354
- const awaitingType = awaiting.type ?? 'none';
355
- const awaitingToolCallId = awaiting.tool_call_id;
356
- this.clearResumeAckTimer();
357
- if (currentCheckpoint && currentCheckpoint !== this.latestCheckpointId) {
358
- this.latestCheckpointId = currentCheckpoint;
359
- }
360
- const isReconcilePhase = this.readyState === ReadyState.AWAITING_RESUME_ACK;
361
- this.metrics.resume_acks_total++;
362
- this.emit('resumeAck', {
363
- current_checkpoint: currentCheckpoint,
364
- last_consumed_turn_id: lastConsumedTurnId,
365
- awaiting: { type: awaitingType, tool_call_id: awaitingToolCallId },
366
- outbox_size: this.outbox.size,
367
- });
368
- if (!isReconcilePhase) {
369
- this.debug(`[WebSocketClient] Informational ResumeAck (already reconciled) | ` +
370
- `State: ${this.readyState}`);
371
- return;
372
- }
373
- // 1) Drop turns the server has already consumed (implicit ack via Resume).
374
- if (lastConsumedTurnId && this.outbox.has(lastConsumedTurnId)) {
375
- this.removeFromOutbox(lastConsumedTurnId);
376
- this.debug(`[WebSocketClient] ResumeAck dropped acked turn from outbox | ` +
377
- `turn_id: ${lastConsumedTurnId}`);
378
- }
379
- // 2) Reconcile what the server is waiting for against what we hold.
380
- let reconcileFailedReason;
381
- let resumeToSend;
382
- if (awaitingType === 'tool_result') {
383
- // Drop any tool_results whose tool_call_id does NOT match what the
384
- // server is now awaiting. The server only advances to "awaiting the
385
- // next tool" after it has ingested the previous tool_result into its
386
- // graph state — so a pending outbox entry for any OTHER tool_call_id
387
- // is already consumed; we just missed the TurnAck across the drop.
388
- //
389
- // This is the production case behind the Apr 19 Slack-bot hang: the
390
- // socket closed between the server's graph advance (which added the
391
- // next ToolRequested to state) and `_commit_turn_consumed`, so the
392
- // client's last_consumed_turn_id guard didn't match. Treating the
393
- // mismatch as a hard failure froze the session until the outer
394
- // 10-min max timer fired. Dropping-as-stale keeps forward progress.
395
- for (const turn of this.outboxSnapshot()) {
396
- if (turn.type === 'IDERetrievalAnswer' && turn.tool_call_id !== awaitingToolCallId) {
397
- this.debug(`[WebSocketClient] ResumeAck dropped stale tool_result | ` +
398
- `turn_id: ${turn.turn_id} | stale tool_call: ${turn.tool_call_id} | ` +
399
- `server awaits: ${awaitingToolCallId ?? 'unspecified'}`);
400
- this.removeFromOutbox(turn.turn_id);
401
- }
402
- }
403
- // If the matching tool_result is still present (real replay), send it.
404
- const candidate = this.outboxSnapshot().find(t => t.type === 'IDERetrievalAnswer' && t.tool_call_id === awaitingToolCallId);
405
- if (candidate)
406
- resumeToSend = candidate;
407
- // Otherwise: outbox is empty. The tool the server wants is either
408
- // executing in the MCP layer now (normal in-flight) or truly lost
409
- // (the outer inactivity timer catches that case).
410
- }
411
- else if (awaitingType === 'prompt' || awaitingType === 'none') {
412
- // Server is idle — any leftover outbox turns are stale consumed or never-delivered
413
- // probes. We keep prompt-style outbox entries (they will flow via normal send),
414
- // but drop any stale tool_results since the graph is no longer at that step.
415
- for (const turn of this.outboxSnapshot()) {
416
- if (turn.type === 'IDERetrievalAnswer') {
417
- this.removeFromOutbox(turn.turn_id);
418
- this.debug(`[WebSocketClient] ResumeAck dropped stale tool_result from outbox | ` +
419
- `turn_id: ${turn.turn_id}`);
420
- }
421
- }
422
- // If we still have a UserQuery queued (client sent a prompt but never saw TurnAck)
423
- // we should replay it.
424
- const promptCandidate = this.outboxSnapshot().find(t => t.type === 'UserQuery');
425
- if (promptCandidate)
426
- resumeToSend = promptCandidate;
427
- }
428
- if (reconcileFailedReason) {
429
- this.debug(`[WebSocketClient] Reconcile failed | ${reconcileFailedReason} | ` +
430
- `outbox: ${this.outbox.size}`);
431
- this.metrics.reconcile_failures_total++;
432
- this.emit('reconcileFailed', { reason: reconcileFailedReason, awaiting });
433
- // Don't lock up — transition to READY so the consumer's own error handling
434
- // can decide what to do. The consumer can still send a new prompt.
435
- this.setReadyState(ReadyState.READY, 'Reconcile failed');
436
- return;
437
- }
438
- // 3) Happy path: transition to READY and replay anything still pending.
439
- this.setReadyState(ReadyState.READY, 'ResumeAck reconciled');
440
- if (resumeToSend) {
441
- this.startPostResumeProgressTimer();
442
- this.metrics.turns_replayed_total++;
443
- await this.sendImmediately({
444
- type: resumeToSend.type,
445
- data: resumeToSend.data,
446
- timestamp: resumeToSend.timestamp,
447
- });
448
- this.receivedResponsesSinceMessage = false;
449
- this.setReadyState(ReadyState.MESSAGE_SENT, `Replayed ${resumeToSend.type} after reconcile`);
450
- this.startReadyTimer();
451
- }
452
- else if (this.outbox.size > 0) {
453
- // No specific replay target, but we have queued work — drain it.
454
- await this.processOutbox();
455
- }
456
- }
457
- handleTurnAck(message) {
458
- const args = message?.data?.tool_args ?? {};
459
- const turnId = args.turn_id;
460
- const checkpointId = args.checkpoint_id;
461
- if (!turnId) {
462
- this.debug('[WebSocketClient] TurnAck received without turn_id, ignoring');
463
- return;
464
- }
465
- const removed = this.removeFromOutbox(turnId);
466
- if (checkpointId)
467
- this.latestCheckpointId = checkpointId;
468
- this.clearPostResumeProgressTimer();
469
- // TurnAck is the v2 completion signal — the in-flight turn is consumed,
470
- // so the TurnAck/Ready SLA started on send is no longer needed.
471
- this.clearReadyTimer();
472
- // Transition out of MESSAGE_SENT so the next queued turn can drain and
473
- // a subsequent legacy-Ready (informational) no longer looks mid-send.
474
- if (this.readyState === ReadyState.MESSAGE_SENT) {
475
- this.setReadyState(ReadyState.READY, 'TurnAck received — turn durably consumed');
476
- // If more turns piled up while we were waiting, drain one now.
477
- void this.processOutbox();
478
- }
479
- this.metrics.turns_acked_total++;
480
- // A TurnAck for a turn we no longer have in the outbox means the server
481
- // re-ACK'd an already-dropped turn (idempotent replay confirmation).
482
- if (!removed)
483
- this.metrics.idempotent_replays_total++;
484
- this.debug(`[WebSocketClient] TurnAck received | ` +
485
- `turn_id: ${turnId} | ` +
486
- `checkpoint: ${checkpointId?.substring(0, 8) || 'none'} | ` +
487
- `outbox_removed: ${removed} | ` +
488
- `outbox_remaining: ${this.outbox.size}`);
489
- this.emit('turnAck', { turn_id: turnId, checkpoint_id: checkpointId });
490
- }
491
- async handleReadyMessage(message) {
492
- const checkpointId = message.data?.tool_args?.checkpoint_id;
493
- const previousCheckpoint = this.latestCheckpointId;
494
- const previousReadyState = this.readyState;
495
- this.debug(`[WebSocketClient] Ready message received | ` +
496
- `State: ${this.readyState} | ` +
497
- `Checkpoint: ${checkpointId?.substring(0, 8) || 'none'} | ` +
498
- `Previous: ${previousCheckpoint?.substring(0, 8) || 'none'}`);
499
- // Update checkpoint if provided and changed
500
- if (checkpointId && checkpointId !== previousCheckpoint) {
501
- this.latestCheckpointId = checkpointId;
502
- this.debug(`[WebSocketClient] Checkpoint ID updated: ${previousCheckpoint?.substring(0, 8) || 'none'} → ` +
503
- `${checkpointId.substring(0, 8)}`);
504
- }
505
- // Handle based on current state
506
- switch (this.readyState) {
507
- case ReadyState.AWAITING_RESUME_ACK:
508
- // In the normal v2 flow the server sends Ready then ResumeAck;
509
- // Ready here is informational and we stay put until ResumeAck.
510
- // Start a short legacy-fallback grace period so that a pre-v2
511
- // backend (Ready only, no ResumeAck) doesn't stall the whole
512
- // 15s ResumeAck SLA before we make progress.
513
- this.debug('[WebSocketClient] Ready received while awaiting ResumeAck — starting legacy fallback grace');
514
- this.startLegacyFallbackTimer();
515
- break;
516
- case ReadyState.WAITING_INITIAL_READY:
517
- this.clearReadyTimer();
518
- this.setReadyState(ReadyState.READY, 'Initial Ready received after connection');
519
- await this.processOutbox();
520
- break;
521
- case ReadyState.WAITING_READY:
522
- this.clearReadyTimer();
523
- this.setReadyState(ReadyState.READY, 'Ready received after responses completed');
524
- await this.processOutbox();
525
- break;
526
- case ReadyState.MESSAGE_SENT:
527
- // Under protocol-v2, ``TurnAck`` is the authoritative signal that our
528
- // message was consumed — not ``Ready``. The backend sends Ready at
529
- // the top of every loop iteration (including between turns and after
530
- // handling a Resume probe), so Ready can legitimately arrive while
531
- // we're still waiting on TurnAck — sometimes even before the graph's
532
- // own output lands, purely due to network ordering. Acting on it
533
- // (the old "server failed to process" path that force-reconnected)
534
- // created a tight infinite loop where every UserQuery triggered a
535
- // spurious reconnect.
536
- //
537
- // Treat Ready here as informational. The timer started in
538
- // ``sendMessage`` / ``processOutbox`` still bounds how long we wait
539
- // for TurnAck, and ``handleTurnAck`` is the real state transition.
540
- this.debug('[WebSocketClient] Ready received in MESSAGE_SENT — ignoring (v2 relies on TurnAck)');
541
- break;
542
- case ReadyState.READY:
543
- this.debug('[WebSocketClient] Ready received while already in READY state (duplicate)');
544
- break;
545
- case ReadyState.IDLE:
546
- this.debug('[WebSocketClient] Ready received while IDLE - transitioning to READY');
547
- this.setReadyState(ReadyState.READY, 'Ready received while idle');
548
- break;
549
- case ReadyState.CHECKPOINT_RECOVERY:
550
- this.debug('[WebSocketClient] Ready received during recovery - resuming normal flow');
551
- this.clearReadyTimer();
552
- this.setReadyState(ReadyState.READY, 'Recovery completed, Ready received');
553
- await this.processOutbox();
554
- break;
555
- }
556
- // Emit event for monitoring.
557
- // Include previous ready state so listeners can distinguish initial Ready
558
- // from completion Ready after MESSAGE_SENT.
559
- this.emit('readyReceived', checkpointId, previousReadyState);
560
- }
561
- async connect(sessionId, requestId) {
562
- // Update session info if provided
563
- if (sessionId)
564
- this.sessionId = sessionId;
565
- if (requestId)
566
- this.requestId = requestId;
567
- if (this.state === ConnectionState.CONNECTED) {
568
- this.resetIdleTimer();
569
- return;
570
- }
571
- // If we auto-disconnected due to idle, reconnect
572
- if (this.autoDisconnected || this.state === ConnectionState.DISCONNECTED) {
573
- this.autoDisconnected = false;
574
- await this.establishConnection();
575
- }
576
- }
577
- async sendMessage(type, data) {
578
- // Reset idle timer on any outgoing message
579
- this.resetIdleTimer();
580
- // Ensure every turn carries a turn_id — the backend idempotency key.
581
- // Accepts a caller-supplied id (rare; only tests need that) and otherwise
582
- // mints one here so existing call sites don't need updates.
583
- const turn_id = (data && typeof data === 'object' && typeof data.turn_id === 'string' && data.turn_id)
584
- ? data.turn_id
585
- : uuid();
586
- const dataWithTurnId = (data && typeof data === 'object')
587
- ? { ...data, turn_id }
588
- : { turn_id, payload: data };
589
- const tool_call_id = type === 'IDERetrievalAnswer'
590
- ? (dataWithTurnId.tool_id ?? dataWithTurnId.tool_call_id)
591
- : undefined;
592
- const turn = {
593
- turn_id,
594
- type,
595
- data: dataWithTurnId,
596
- tool_call_id,
597
- timestamp: Date.now(),
598
- };
599
- this.addToOutbox(turn);
600
- this.debug(`[WebSocketClient] sendMessage called | ` +
601
- `Type: ${type} | ` +
602
- `turn_id: ${turn_id} | ` +
603
- `ReadyState: ${this.readyState} | ` +
604
- `ConnectionState: ${this.state} | ` +
605
- `outbox_size: ${this.outbox.size}`);
606
- // Save as last sent message for potential recovery (legacy path)
607
- this.lastSentMessage = { type, data: dataWithTurnId, timestamp: turn.timestamp };
608
- if (this.readyState === ReadyState.READY && this.ws && this.state === ConnectionState.CONNECTED) {
609
- this.receivedResponsesSinceMessage = false;
610
- await this.sendImmediately({ type, data: dataWithTurnId, timestamp: turn.timestamp });
611
- this.setReadyState(ReadyState.MESSAGE_SENT, `Sent ${type} message`);
612
- this.startReadyTimer();
613
- }
614
- else {
615
- this.debug(`[WebSocketClient] Turn parked in outbox | ` +
616
- `Type: ${type} | ` +
617
- `turn_id: ${turn_id} | ` +
618
- `outbox_size: ${this.outbox.size} | ` +
619
- `Reason: ReadyState=${this.readyState}, Connected=${this.state === ConnectionState.CONNECTED}`);
620
- if (this.state === ConnectionState.DISCONNECTED) {
621
- this.debug('[WebSocketClient] Initiating connection due to queued turn');
622
- await this.connect();
623
- }
624
- }
625
- }
626
- async sendImmediately(msg) {
627
- const formatted = this.formatMessage(msg.type, msg.data);
628
- this.ws.send(formatted);
629
- this.debug(`[WebSocketClient] Message sent immediately | ` +
630
- `Type: ${msg.type} | ` +
631
- `Size: ${formatted.length} bytes`);
632
- }
633
- /**
634
- * Drain the outbox into the socket. Only one turn is in-flight at a time
635
- * (MESSAGE_SENT gate enforces this). Called on ResumeAck (after reconcile)
636
- * and on transitions back to READY.
637
- */
638
- async processOutbox() {
639
- this.debug(`[WebSocketClient] Processing outbox | ` +
640
- `outbox_size: ${this.outbox.size} | ` +
641
- `ReadyState: ${this.readyState}`);
642
- if (this.outbox.size === 0) {
643
- this.debug('[WebSocketClient] Outbox is empty, no messages to process');
644
- return;
645
- }
646
- if (this.readyState !== ReadyState.READY) {
647
- this.debug(`[WebSocketClient] Cannot process outbox | ` +
648
- `ReadyState: ${this.readyState} (expected READY)`);
649
- return;
650
- }
651
- const nextId = this.outboxOrder[0];
652
- const turn = nextId ? this.outbox.get(nextId) : undefined;
653
- if (!turn)
654
- return;
655
- this.debug(`[WebSocketClient] Sending queued turn | ` +
656
- `Type: ${turn.type} | ` +
657
- `turn_id: ${turn.turn_id} | ` +
658
- `Queued at: ${turn.timestamp} | ` +
659
- `Wait: ${Date.now() - turn.timestamp}ms | ` +
660
- `outbox_remaining: ${this.outbox.size}`);
661
- this.receivedResponsesSinceMessage = false;
662
- await this.sendImmediately({ type: turn.type, data: turn.data, timestamp: turn.timestamp });
663
- this.setReadyState(ReadyState.MESSAGE_SENT, `Sent queued ${turn.type} message`);
664
- this.startReadyTimer();
665
- }
666
- startReadyTimer() {
667
- this.clearReadyTimer();
668
- this.readyTimer = setTimeout(async () => {
669
- this.debug(`[WebSocketClient] Ready timeout expired | ` +
670
- `State: ${this.readyState} | ` +
671
- `Last message: ${this.lastSentMessage?.type} | ` +
672
- `Checkpoint: ${this.latestCheckpointId?.substring(0, 8) || 'none'}`);
673
- await this.initiateCheckpointRecovery('Ready timeout');
674
- }, WS_CONFIG.READY_TIMEOUT);
675
- // Do not keep the event loop alive solely because of this timer
676
- this.readyTimer.unref?.();
677
- }
678
- clearReadyTimer() {
679
- if (this.readyTimer) {
680
- clearTimeout(this.readyTimer);
681
- this.readyTimer = undefined;
682
- }
683
- }
684
- /**
685
- * Legacy recovery entry point.
686
- *
687
- * Under protocol v2 the outbox holds every un-ACK'd turn by turn_id and the
688
- * Resume/ResumeAck handshake replays it authoritatively. All we need to do
689
- * here is cycle the socket — the open handler will send Resume, the server
690
- * will reply with ResumeAck, and reconciliation will happen automatically.
691
- */
692
- async initiateCheckpointRecovery(reason) {
693
- this.debug(`[WebSocketClient] Forcing reconnect for recovery | ` +
694
- `Reason: ${reason} | ` +
695
- `Checkpoint: ${this.latestCheckpointId?.substring(0, 8) || 'none'} | ` +
696
- `outbox_size: ${this.outbox.size} | ` +
697
- `State: ${this.readyState}`);
698
- this.emit('checkpointRecovery', { reason, checkpoint: this.latestCheckpointId });
699
- try {
700
- // Close the socket hard. handleClose will schedule reconnection via
701
- // attemptReconnection, and the open handler will send a fresh Resume.
702
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
703
- this.ws.close(4002, `Recovery: ${reason}`);
704
- }
705
- }
706
- catch (error) {
707
- this.debug(`[WebSocketClient] Recovery reconnect failed | ` +
708
- `Error: ${error instanceof Error ? error.message : error}`);
709
- }
710
- }
711
- disconnect() {
712
- // Hold a reference to the current socket to close it safely
713
- const wsRef = this.ws;
714
- // Stop all timers and reconnection attempts
715
- this.clearTimers();
716
- this.autoDisconnected = false;
717
- this.isReconnecting = false;
718
- // Invalidate the current connection so any late events from wsRef are ignored
719
- // Event handlers compare this.connectionId to their captured id
720
- this.connectionId = uuid();
721
- if (wsRef) {
722
- try {
723
- // Attempt a graceful close when open; otherwise force terminate to avoid races
724
- if (wsRef.readyState === WebSocket.OPEN) {
725
- this.setState(ConnectionState.DISCONNECTING);
726
- wsRef.close(1000, 'Normal closure');
727
- }
728
- else if (wsRef.readyState === WebSocket.CONNECTING || wsRef.readyState === WebSocket.CLOSING) {
729
- // Avoid an "open" event racing in after manual disconnect
730
- try {
731
- wsRef.terminate?.();
732
- }
733
- catch { /* cleanup: terminate may fail if already closed */ }
734
- }
735
- }
736
- catch { /* cleanup: WS close/terminate during disconnect must not throw */ }
737
- }
738
- // Explicitly mark as disconnected and reset internal refs
739
- this.setState(ConnectionState.DISCONNECTED);
740
- this.ws = undefined;
741
- this.setReadyState(ReadyState.IDLE, 'Manual disconnect');
742
- this.lastPingSent = 0;
743
- }
744
- getState() {
745
- return this.state;
746
- }
747
- keepAlive() {
748
- if (this.state === ConnectionState.CONNECTED) {
749
- this.resetIdleTimer();
750
- }
751
- }
752
- // === Private Methods ===
753
- async establishConnection() {
754
- if (this.state === ConnectionState.CONNECTING) {
755
- await this.waitForConnection();
756
- return;
757
- }
758
- return new Promise((resolve, reject) => {
759
- try {
760
- this.setState(ConnectionState.CONNECTING);
761
- this.connectionId = uuid();
762
- const currentConnectionId = this.connectionId;
763
- const wsUrl = this.buildWebSocketUrl();
764
- const env = getCurrentEnvironment();
765
- const { token } = env.authProvider
766
- ? env.authProvider.getAuthConfig()
767
- : getAuthConfig();
768
- this.debug(`Connecting to WebSocket: ${wsUrl}`);
769
- const ws = new WebSocket(wsUrl, {
770
- headers: {
771
- 'Authorization': `Bearer ${token}`,
772
- },
773
- handshakeTimeout: WS_CONFIG.CONNECTION_TIMEOUT,
774
- });
775
- this.ws = ws;
776
- // Set up event handlers
777
- ws.on('open', () => {
778
- if (this.connectionId !== currentConnectionId) {
779
- ws.close();
780
- return;
781
- }
782
- // Clear pending connection timeout timer if any
783
- if (this.connectionTimeoutTimer) {
784
- clearTimeout(this.connectionTimeoutTimer);
785
- this.connectionTimeoutTimer = undefined;
786
- }
787
- this.setState(ConnectionState.CONNECTED);
788
- this.reconnectAttempts = 0;
789
- this.emit('connected');
790
- this.debug(`[WebSocketClient] WebSocket connected | ` +
791
- `Session: ${this.sessionId?.substring(0, 8)}... | ` +
792
- `Checkpoint: ${this.latestCheckpointId?.substring(0, 8) || 'none'} | ` +
793
- `outbox: ${this.outbox.size}`);
794
- // Start idle timer and heartbeat immediately so dead sockets surface.
795
- this.startIdleTimer();
796
- this.startHeartbeat();
797
- // Protocol v2: every (re)connect opens with a Resume envelope. The
798
- // server's ResumeAck is the authoritative signal — the old "wait for
799
- // Ready" handshake is left as a fallback for servers that don't yet
800
- // understand Resume (they emit Ready first, which we treat as info).
801
- this.setReadyState(ReadyState.AWAITING_RESUME_ACK, 'Connection opened, sending Resume');
802
- this.sendResume();
803
- this.debug('[WebSocketClient] Connection established, waiting for ResumeAck');
804
- resolve();
805
- });
806
- ws.on('message', (data) => {
807
- if (this.connectionId !== currentConnectionId)
808
- return;
809
- this.resetIdleTimer();
810
- this.lastPongReceived = Date.now(); // any message is also a ping
811
- const message = data.toString();
812
- // Intercept protocol-v2 control messages (ResumeAck, TurnAck, Ready)
813
- // before forwarding to the consumer. These are transport concerns.
814
- try {
815
- const parsed = JSON.parse(message);
816
- const tool = parsed?.data?.tool;
817
- if (tool === 'Ready') {
818
- this.handleReadyMessage(parsed);
819
- return;
820
- }
821
- if (tool === 'ResumeAck') {
822
- this.handleResumeAck(parsed);
823
- return;
824
- }
825
- if (tool === 'TurnAck') {
826
- this.handleTurnAck(parsed);
827
- return;
828
- }
829
- }
830
- catch (e) {
831
- // Not JSON or not a control message — fall through to consumer.
832
- }
833
- // Track that we received a non-Ready message (response)
834
- if (this.readyState === ReadyState.MESSAGE_SENT) {
835
- this.receivedResponsesSinceMessage = true;
836
- }
837
- // A domain event after ResumeAck counts as forward progress — clear the stall timer.
838
- this.clearPostResumeProgressTimer();
839
- // Emit non-Ready messages to AgentAPI
840
- this.emit('message', message);
841
- });
842
- ws.on('close', (code, reason) => {
843
- if (this.connectionId !== currentConnectionId)
844
- return;
845
- // Clear pending connection-timeout timer
846
- if (this.connectionTimeoutTimer) {
847
- clearTimeout(this.connectionTimeoutTimer);
848
- this.connectionTimeoutTimer = undefined;
849
- }
850
- this.handleClose(code, reason.toString());
851
- if (this.state === ConnectionState.CONNECTING) {
852
- reject(new Error(`Connection closed during setup: ${code} ${reason}`));
853
- }
854
- });
855
- ws.on('error', (error) => {
856
- if (this.connectionId !== currentConnectionId)
857
- return;
858
- // Clear pending connection-timeout timer
859
- if (this.connectionTimeoutTimer) {
860
- clearTimeout(this.connectionTimeoutTimer);
861
- this.connectionTimeoutTimer = undefined;
862
- }
863
- this.debug('WebSocket error:', error);
864
- this.emit('error', error);
865
- if (this.state === ConnectionState.CONNECTING) {
866
- reject(error);
867
- }
868
- });
869
- ws.on('pong', () => {
870
- if (this.connectionId === currentConnectionId) {
871
- this.lastPongReceived = Date.now();
872
- this.debug('Pong received, heartbeat OK');
873
- }
874
- });
875
- // Connection timeout
876
- this.connectionTimeoutTimer = setTimeout(() => {
877
- if (this.connectionId === currentConnectionId && this.state === ConnectionState.CONNECTING) {
878
- ws.close();
879
- reject(new Error('Connection timeout'));
880
- }
881
- }, WS_CONFIG.CONNECTION_TIMEOUT);
882
- this.connectionTimeoutTimer.unref?.();
883
- }
884
- catch (error) {
885
- this.setState(ConnectionState.FAILED);
886
- reject(error);
887
- }
888
- });
889
- }
890
- async waitForConnection(timeout = WS_CONFIG.CONNECTION_TIMEOUT) {
891
- const startTime = Date.now();
892
- while (this.state === ConnectionState.CONNECTING || this.state === ConnectionState.RECONNECTING) {
893
- if (Date.now() - startTime > timeout) {
894
- throw new Error('Connection timeout while waiting');
895
- }
896
- await new Promise(resolve => setTimeout(resolve, 100));
897
- }
898
- if (this.state !== ConnectionState.CONNECTED) {
899
- throw new Error('Failed to establish connection');
900
- }
901
- }
902
- buildWebSocketUrl() {
903
- const baseUrl = ServerData.getInstance().getBaseUrl();
904
- const wsUrl = baseUrl.replace(/^http/, 'ws');
905
- const trimmedBase = wsUrl.replace(/\/+$/, '');
906
- const url = new URL(`${trimmedBase}/v2/agentic/ws/connect`);
907
- // Use current session ID, or generate one if not set
908
- const currentSessionId = this.sessionId || uuid();
909
- url.searchParams.set('session_id', currentSessionId);
910
- if (this.requestId) {
911
- url.searchParams.set('request_id', this.requestId);
912
- }
913
- // Include checkpoint_id if available for recovery
914
- if (this.latestCheckpointId && this.readyState === ReadyState.CHECKPOINT_RECOVERY) {
915
- url.searchParams.set('checkpoint_id', this.latestCheckpointId);
916
- this.debug(`[WebSocketClient] Building URL with checkpoint | ` +
917
- `Checkpoint: ${this.latestCheckpointId.substring(0, 8)}...`);
918
- }
919
- else {
920
- this.debug('[WebSocketClient] Building URL without checkpoint (fresh connection)');
921
- }
922
- // SDK always uses agent_type=sdk
923
- url.searchParams.set('agent_type', 'sdk');
924
- return url.toString();
925
- }
926
- formatMessage(type, data) {
927
- return `${type} ${JSON.stringify(data)}\n`;
928
- }
929
- handleClose(code, reason) {
930
- this.clearTimers();
931
- if (this.autoDisconnected) {
932
- this.debug('WebSocket closed due to idle timeout');
933
- this.setState(ConnectionState.DISCONNECTED);
934
- this.emit('disconnected', { reason: 'idle', code });
935
- return;
936
- }
937
- this.debug(`WebSocket closed: ${code} ${reason}`);
938
- // Determine if we should reconnect
939
- if (code === 1000 || code === 1001) {
940
- // Normal closure
941
- this.setState(ConnectionState.DISCONNECTED);
942
- this.emit('disconnected', { reason: 'normal', code });
943
- }
944
- else if (code === 1008) {
945
- // Authentication failure - don't reconnect
946
- this.setState(ConnectionState.FAILED);
947
- this.emit('error', new Error('Authentication failed'));
948
- }
949
- else if (!this.hasCompletedHandshake) {
950
- // No successful handshake has completed on this instance. Treat any
951
- // close here as a startup failure — auth issues, wrong URL, server
952
- // rejecting the protocol, etc. should surface as a real error rather
953
- // than enter an indefinite reconnect loop that hides the root cause.
954
- this.setState(ConnectionState.FAILED);
955
- const errorMessage = this.buildConnectionErrorMessage(code, reason);
956
- this.emit('error', new Error(errorMessage));
957
- }
958
- else {
959
- // Unexpected closure mid-session - attempt reconnect
960
- this.setState(ConnectionState.FAILED);
961
- this.attemptReconnection().catch((error) => {
962
- this.debug('Reconnection attempt failed:', error instanceof Error ? error.message : error);
963
- });
964
- }
965
- }
966
- buildConnectionErrorMessage(code, reason) {
967
- const baseUrl = ServerData.getInstance().getBaseUrl();
968
- const codeDescriptions = {
969
- 1002: 'Protocol error',
970
- 1003: 'Unsupported data type',
971
- 1006: 'Connection closed abnormally (server may have crashed or rejected the connection)',
972
- 1007: 'Invalid message data',
973
- 1008: 'Policy violation',
974
- 1009: 'Message too large',
975
- 1010: 'Extension negotiation failed',
976
- 1011: 'Unexpected server condition',
977
- 1012: 'Service restart',
978
- 1013: 'Try again later',
979
- 1014: 'Bad gateway',
980
- 1015: 'TLS handshake failed',
981
- };
982
- const codeDescription = codeDescriptions[code] || `Unexpected close code ${code}`;
983
- const reasonPart = reason ? `: ${reason}` : '';
984
- return `Failed to connect to Qodo backend at ${baseUrl}. ${codeDescription}${reasonPart}. If this issue persists, please contact Qodo support.`;
985
- }
986
- async attemptReconnection() {
987
- if (this.isReconnecting)
988
- return;
989
- this.isReconnecting = true;
990
- this.setState(ConnectionState.RECONNECTING);
991
- this.reconnectAttempts++;
992
- this.metrics.reconnects_total++;
993
- // Stamp the disconnect time on the first reconnect attempt of a cycle so
994
- // the eventual `reconnected` event can carry an accurate downtime_ms.
995
- if (this.reconnectAttempts === 1 && !this.lastDisconnectAt) {
996
- this.lastDisconnectAt = Date.now();
997
- }
998
- this.emit('reconnecting', { attempt: this.reconnectAttempts });
999
- const delay = this.calculateBackoffDelay(this.reconnectAttempts);
1000
- this.debug(`Attempting reconnection ${this.reconnectAttempts} in ${delay}ms`);
1001
- this.reconnectTimer = setTimeout(async () => {
1002
- try {
1003
- await this.establishConnection();
1004
- this.isReconnecting = false;
1005
- const downtime_ms = this.lastDisconnectAt ? Date.now() - this.lastDisconnectAt : undefined;
1006
- this.lastDisconnectAt = undefined;
1007
- this.emit('reconnected', { downtime_ms });
1008
- }
1009
- catch (error) {
1010
- this.debug('Reconnection failed:', error instanceof Error ? error.message : error);
1011
- this.isReconnecting = false;
1012
- // Infinite retry - always attempt again
1013
- setTimeout(() => this.attemptReconnection(), 1000);
1014
- }
1015
- }, delay);
1016
- this.reconnectTimer.unref?.();
1017
- }
1018
- calculateBackoffDelay(attempt) {
1019
- const delay = WS_CONFIG.INITIAL_RECONNECT_DELAY *
1020
- Math.pow(WS_CONFIG.RECONNECT_BACKOFF_FACTOR, attempt - 1);
1021
- const jitter = delay * 0.25 * (Math.random() - 0.5);
1022
- return Math.min(delay + jitter, WS_CONFIG.MAX_RECONNECT_DELAY);
1023
- }
1024
- // === Idle Timer Management ===
1025
- startIdleTimer() {
1026
- this.clearIdleTimer();
1027
- this.idleTimer = setTimeout(() => {
1028
- this.debug('Connection idle for 10 minutes, disconnecting...');
1029
- this.autoDisconnected = true;
1030
- // Clean disconnect - ready for next request
1031
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
1032
- this.ws.close(1000, 'Idle timeout');
1033
- }
1034
- this.setState(ConnectionState.DISCONNECTED);
1035
- this.emit('disconnected', { reason: 'idle' });
1036
- }, WS_CONFIG.IDLE_TIMEOUT);
1037
- // Let process exit if this is the only pending timer
1038
- this.idleTimer.unref?.();
1039
- }
1040
- clearIdleTimer() {
1041
- if (this.idleTimer) {
1042
- clearTimeout(this.idleTimer);
1043
- this.idleTimer = undefined;
1044
- }
1045
- }
1046
- resetIdleTimer() {
1047
- this.startIdleTimer();
1048
- }
1049
- // === Heartbeat Management ===
1050
- startHeartbeat() {
1051
- if (this.heartbeatInterval) {
1052
- clearInterval(this.heartbeatInterval);
1053
- }
1054
- this.heartbeatInterval = setInterval(() => {
1055
- if (this.state === ConnectionState.CONNECTED && this.ws) {
1056
- const now = Date.now();
1057
- const timeSinceLastPong = now - this.lastPongReceived;
1058
- // If we haven't sent a ping recently, or if it's time to send another one
1059
- if (this.lastPingSent === 0 || (now - this.lastPingSent) >= WS_CONFIG.HEARTBEAT_INTERVAL) {
1060
- try {
1061
- this.ws.ping();
1062
- this.lastPingSent = now;
1063
- this.debug('Ping sent, waiting for pong...');
1064
- }
1065
- catch (error) {
1066
- this.debug('Error sending ping:', error);
1067
- }
1068
- }
1069
- // If we sent a ping and enough time has passed without a pong, timeout
1070
- else if (this.lastPingSent > 0 && timeSinceLastPong > WS_CONFIG.HEARTBEAT_TIMEOUT) {
1071
- this.debug('Heartbeat timeout, closing connection');
1072
- this.ws.close();
1073
- return;
1074
- }
1075
- }
1076
- }, WS_CONFIG.HEARTBEAT_INTERVAL);
1077
- // Allow process to exit if heartbeat is the last thing running
1078
- this.heartbeatInterval.unref?.();
1079
- }
1080
- stopHeartbeat() {
1081
- if (this.heartbeatInterval) {
1082
- clearInterval(this.heartbeatInterval);
1083
- this.heartbeatInterval = undefined;
1084
- }
1085
- }
1086
- async processQueuedMessages() {
1087
- if (this.isProcessingQueue || this.messageQueue.length === 0)
1088
- return;
1089
- this.isProcessingQueue = true;
1090
- this.debug(`Processing ${this.messageQueue.length} queued messages`);
1091
- try {
1092
- while (this.messageQueue.length > 0 && this.state === ConnectionState.CONNECTED) {
1093
- const queuedMessage = this.messageQueue.shift();
1094
- try {
1095
- const message = this.formatMessage(queuedMessage.type, queuedMessage.data);
1096
- this.ws.send(message);
1097
- this.debug(`Sent queued ${queuedMessage.type} message`);
1098
- }
1099
- catch (error) {
1100
- console.error('Error processing queued message:', error);
1101
- if (queuedMessage.retryCount < 3) {
1102
- queuedMessage.retryCount++;
1103
- this.messageQueue.unshift(queuedMessage);
1104
- break;
1105
- }
1106
- }
1107
- }
1108
- }
1109
- finally {
1110
- this.isProcessingQueue = false;
1111
- }
1112
- }
1113
- // === Cleanup ===
1114
- clearTimers() {
1115
- this.clearIdleTimer();
1116
- this.stopHeartbeat();
1117
- this.clearReadyTimer();
1118
- this.clearResumeAckTimer();
1119
- this.clearPostResumeProgressTimer();
1120
- this.clearLegacyFallbackTimer();
1121
- if (this.reconnectTimer) {
1122
- clearTimeout(this.reconnectTimer);
1123
- this.reconnectTimer = undefined;
1124
- }
1125
- if (this.connectionTimeoutTimer) {
1126
- clearTimeout(this.connectionTimeoutTimer);
1127
- this.connectionTimeoutTimer = undefined;
1128
- }
1129
- }
1130
- cleanup() {
1131
- this.debug(`[WebSocketClient] Cleanup called | ` +
1132
- `State: ${this.state} | ` +
1133
- `ReadyState: ${this.readyState} | ` +
1134
- `Queued messages: ${this.messageQueue.length} | ` +
1135
- `Outbox: ${this.outbox.size}`);
1136
- this.clearTimers();
1137
- this.disconnect();
1138
- this.messageQueue = [];
1139
- this.outbox.clear();
1140
- this.outboxOrder.length = 0;
1141
- this.isReconnecting = false;
1142
- this.latestCheckpointId = undefined;
1143
- this.lastSentMessage = undefined;
1144
- this.hasCompletedHandshake = false;
1145
- this.setReadyState(ReadyState.IDLE, 'Cleanup performed');
1146
- this.removeAllListeners();
1147
- this.debug('[WebSocketClient] Cleanup completed');
1148
- }
1149
- // --- Test hooks -----------------------------------------------------------
1150
- // These are intentionally tiny, read-only accessors so the chaos harness
1151
- // can assert on internal state without resorting to `any` casts. They are
1152
- // not part of the public SDK API.
1153
- /** @internal */
1154
- __getOutboxIds() {
1155
- return [...this.outboxOrder];
1156
- }
1157
- /** @internal */
1158
- __getOutboxSize() {
1159
- return this.outbox.size;
1160
- }
1161
- /** @internal */
1162
- __getLatestCheckpointId() {
1163
- return this.latestCheckpointId;
1164
- }
1165
- }
1166
- //# sourceMappingURL=websocket.js.map