@vybestack/llxprt-code-core 0.1.18-nightly.250811.b0db22c6 → 0.1.18-nightly.250812.12fa8ad2

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 (485) hide show
  1. package/README.md +49 -2
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +2 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/auth/anthropic-device-flow.d.ts +53 -0
  6. package/dist/src/auth/anthropic-device-flow.js +208 -0
  7. package/dist/src/auth/anthropic-device-flow.js.map +1 -0
  8. package/dist/src/auth/token-store.js +11 -7
  9. package/dist/src/auth/token-store.js.map +1 -1
  10. package/dist/src/config/config.d.ts +7 -1
  11. package/dist/src/config/config.js +42 -4
  12. package/dist/src/config/config.js.map +1 -1
  13. package/dist/src/config/profileManager.d.ts +14 -4
  14. package/dist/src/config/profileManager.js +90 -11
  15. package/dist/src/config/profileManager.js.map +1 -1
  16. package/dist/src/core/contentGenerator.d.ts +2 -1
  17. package/dist/src/core/contentGenerator.js +1 -0
  18. package/dist/src/core/contentGenerator.js.map +1 -1
  19. package/dist/src/index.d.ts +6 -0
  20. package/dist/src/index.js +5 -0
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/providers/BaseProvider.d.ts +51 -0
  23. package/dist/src/providers/BaseProvider.js +136 -1
  24. package/dist/src/providers/BaseProvider.js.map +1 -1
  25. package/dist/src/providers/IProvider.d.ts +1 -0
  26. package/dist/src/providers/LoggingProviderWrapper.d.ts +1 -0
  27. package/dist/src/providers/LoggingProviderWrapper.js +3 -0
  28. package/dist/src/providers/LoggingProviderWrapper.js.map +1 -1
  29. package/dist/src/providers/ProviderManager.d.ts +0 -1
  30. package/dist/src/providers/ProviderManager.js +23 -14
  31. package/dist/src/providers/ProviderManager.js.map +1 -1
  32. package/dist/src/providers/anthropic/AnthropicProvider.d.ts +20 -6
  33. package/dist/src/providers/anthropic/AnthropicProvider.js +172 -26
  34. package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
  35. package/dist/src/providers/gemini/GeminiProvider.d.ts +4 -0
  36. package/dist/src/providers/gemini/GeminiProvider.js +33 -1
  37. package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
  38. package/dist/src/providers/openai/OpenAIProvider.d.ts +32 -0
  39. package/dist/src/providers/openai/OpenAIProvider.js +200 -13
  40. package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
  41. package/dist/src/providers/openai/RESPONSES_API_MODELS.d.ts +1 -1
  42. package/dist/src/providers/openai/RESPONSES_API_MODELS.js +1 -0
  43. package/dist/src/providers/openai/RESPONSES_API_MODELS.js.map +1 -1
  44. package/dist/src/providers/openai/syntheticToolResponses.d.ts +52 -0
  45. package/dist/src/providers/openai/syntheticToolResponses.js +129 -0
  46. package/dist/src/providers/openai/syntheticToolResponses.js.map +1 -0
  47. package/dist/src/settings/SettingsService.d.ts +32 -0
  48. package/dist/src/settings/SettingsService.js +204 -0
  49. package/dist/src/settings/SettingsService.js.map +1 -0
  50. package/dist/src/settings/settingsServiceInstance.d.ts +12 -0
  51. package/dist/src/settings/settingsServiceInstance.js +24 -0
  52. package/dist/src/settings/settingsServiceInstance.js.map +1 -0
  53. package/dist/src/settings/types.d.ts +141 -0
  54. package/dist/src/settings/types.js +5 -0
  55. package/dist/src/settings/types.js.map +1 -0
  56. package/package.json +4 -2
  57. package/dist/src/auth/auth-integration.spec.d.ts +0 -6
  58. package/dist/src/auth/auth-integration.spec.js +0 -384
  59. package/dist/src/auth/auth-integration.spec.js.map +0 -1
  60. package/dist/src/auth/precedence.test.d.ts +0 -6
  61. package/dist/src/auth/precedence.test.js +0 -374
  62. package/dist/src/auth/precedence.test.js.map +0 -1
  63. package/dist/src/auth/qwen-device-flow.spec.d.ts +0 -6
  64. package/dist/src/auth/qwen-device-flow.spec.js +0 -793
  65. package/dist/src/auth/qwen-device-flow.spec.js.map +0 -1
  66. package/dist/src/auth/token-store.spec.d.ts +0 -6
  67. package/dist/src/auth/token-store.spec.js +0 -405
  68. package/dist/src/auth/token-store.spec.js.map +0 -1
  69. package/dist/src/code_assist/converter.test.d.ts +0 -6
  70. package/dist/src/code_assist/converter.test.js +0 -279
  71. package/dist/src/code_assist/converter.test.js.map +0 -1
  72. package/dist/src/code_assist/oauth2.test.d.ts +0 -6
  73. package/dist/src/code_assist/oauth2.test.js +0 -370
  74. package/dist/src/code_assist/oauth2.test.js.map +0 -1
  75. package/dist/src/code_assist/server.test.d.ts +0 -6
  76. package/dist/src/code_assist/server.test.js +0 -134
  77. package/dist/src/code_assist/server.test.js.map +0 -1
  78. package/dist/src/code_assist/setup.test.d.ts +0 -6
  79. package/dist/src/code_assist/setup.test.js +0 -65
  80. package/dist/src/code_assist/setup.test.js.map +0 -1
  81. package/dist/src/config/config.alwaysAllow.test.d.ts +0 -6
  82. package/dist/src/config/config.alwaysAllow.test.js +0 -84
  83. package/dist/src/config/config.alwaysAllow.test.js.map +0 -1
  84. package/dist/src/config/config.ephemeral.test.d.ts +0 -6
  85. package/dist/src/config/config.ephemeral.test.js +0 -152
  86. package/dist/src/config/config.ephemeral.test.js.map +0 -1
  87. package/dist/src/config/config.test.d.ts +0 -6
  88. package/dist/src/config/config.test.js +0 -369
  89. package/dist/src/config/config.test.js.map +0 -1
  90. package/dist/src/config/endpoints.test.d.ts +0 -6
  91. package/dist/src/config/endpoints.test.js +0 -196
  92. package/dist/src/config/endpoints.test.js.map +0 -1
  93. package/dist/src/config/flashFallback.test.d.ts +0 -6
  94. package/dist/src/config/flashFallback.test.js +0 -91
  95. package/dist/src/config/flashFallback.test.js.map +0 -1
  96. package/dist/src/core/client.test.d.ts +0 -6
  97. package/dist/src/core/client.test.js +0 -1323
  98. package/dist/src/core/client.test.js.map +0 -1
  99. package/dist/src/core/contentGenerator.test.d.ts +0 -6
  100. package/dist/src/core/contentGenerator.test.js +0 -103
  101. package/dist/src/core/contentGenerator.test.js.map +0 -1
  102. package/dist/src/core/coreToolScheduler.test.d.ts +0 -6
  103. package/dist/src/core/coreToolScheduler.test.js +0 -637
  104. package/dist/src/core/coreToolScheduler.test.js.map +0 -1
  105. package/dist/src/core/geminiChat.test.d.ts +0 -6
  106. package/dist/src/core/geminiChat.test.js +0 -425
  107. package/dist/src/core/geminiChat.test.js.map +0 -1
  108. package/dist/src/core/googleGenAIWrapper.test.d.ts +0 -6
  109. package/dist/src/core/googleGenAIWrapper.test.js +0 -104
  110. package/dist/src/core/googleGenAIWrapper.test.js.map +0 -1
  111. package/dist/src/core/logger.test.d.ts +0 -6
  112. package/dist/src/core/logger.test.js +0 -467
  113. package/dist/src/core/logger.test.js.map +0 -1
  114. package/dist/src/core/nonInteractiveToolExecutor.test.d.ts +0 -6
  115. package/dist/src/core/nonInteractiveToolExecutor.test.js +0 -165
  116. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +0 -1
  117. package/dist/src/core/prompts-async.test.d.ts +0 -6
  118. package/dist/src/core/prompts-async.test.js +0 -115
  119. package/dist/src/core/prompts-async.test.js.map +0 -1
  120. package/dist/src/core/prompts.test.d.ts +0 -6
  121. package/dist/src/core/prompts.test.js +0 -68
  122. package/dist/src/core/prompts.test.js.map +0 -1
  123. package/dist/src/core/subagent.test.d.ts +0 -6
  124. package/dist/src/core/subagent.test.js +0 -510
  125. package/dist/src/core/subagent.test.js.map +0 -1
  126. package/dist/src/core/tokenLimits.test.d.ts +0 -6
  127. package/dist/src/core/tokenLimits.test.js +0 -66
  128. package/dist/src/core/tokenLimits.test.js.map +0 -1
  129. package/dist/src/core/turn.test.d.ts +0 -6
  130. package/dist/src/core/turn.test.js +0 -366
  131. package/dist/src/core/turn.test.js.map +0 -1
  132. package/dist/src/hooks/tool-render-suppression-hook.test.d.ts +0 -6
  133. package/dist/src/hooks/tool-render-suppression-hook.test.js +0 -59
  134. package/dist/src/hooks/tool-render-suppression-hook.test.js.map +0 -1
  135. package/dist/src/ide/ide-installer.test.d.ts +0 -6
  136. package/dist/src/ide/ide-installer.test.js +0 -55
  137. package/dist/src/ide/ide-installer.test.js.map +0 -1
  138. package/dist/src/ide/ideContext.test.d.ts +0 -6
  139. package/dist/src/ide/ideContext.test.js +0 -265
  140. package/dist/src/ide/ideContext.test.js.map +0 -1
  141. package/dist/src/index.test.d.ts +0 -6
  142. package/dist/src/index.test.js +0 -12
  143. package/dist/src/index.test.js.map +0 -1
  144. package/dist/src/integration-tests/oauth-integration.spec.d.ts +0 -6
  145. package/dist/src/integration-tests/oauth-integration.spec.js +0 -518
  146. package/dist/src/integration-tests/oauth-integration.spec.js.map +0 -1
  147. package/dist/src/integration-tests/oauth-simple-test.spec.d.ts +0 -1
  148. package/dist/src/integration-tests/oauth-simple-test.spec.js +0 -88
  149. package/dist/src/integration-tests/oauth-simple-test.spec.js.map +0 -1
  150. package/dist/src/integration-tests/todo-system.test.d.ts +0 -6
  151. package/dist/src/integration-tests/todo-system.test.js +0 -46
  152. package/dist/src/integration-tests/todo-system.test.js.map +0 -1
  153. package/dist/src/mcp/google-auth-provider.test.d.ts +0 -6
  154. package/dist/src/mcp/google-auth-provider.test.js +0 -54
  155. package/dist/src/mcp/google-auth-provider.test.js.map +0 -1
  156. package/dist/src/mcp/oauth-provider.test.d.ts +0 -6
  157. package/dist/src/mcp/oauth-provider.test.js +0 -602
  158. package/dist/src/mcp/oauth-provider.test.js.map +0 -1
  159. package/dist/src/mcp/oauth-token-storage.test.d.ts +0 -6
  160. package/dist/src/mcp/oauth-token-storage.test.js +0 -205
  161. package/dist/src/mcp/oauth-token-storage.test.js.map +0 -1
  162. package/dist/src/mcp/oauth-utils.test.d.ts +0 -6
  163. package/dist/src/mcp/oauth-utils.test.js +0 -144
  164. package/dist/src/mcp/oauth-utils.test.js.map +0 -1
  165. package/dist/src/parsers/TextToolCallParser.multibyte.test.d.ts +0 -1
  166. package/dist/src/parsers/TextToolCallParser.multibyte.test.js +0 -42
  167. package/dist/src/parsers/TextToolCallParser.multibyte.test.js.map +0 -1
  168. package/dist/src/parsers/TextToolCallParser.test.d.ts +0 -1
  169. package/dist/src/parsers/TextToolCallParser.test.js +0 -225
  170. package/dist/src/parsers/TextToolCallParser.test.js.map +0 -1
  171. package/dist/src/prompt-config/TemplateEngine.test.d.ts +0 -1
  172. package/dist/src/prompt-config/TemplateEngine.test.js +0 -494
  173. package/dist/src/prompt-config/TemplateEngine.test.js.map +0 -1
  174. package/dist/src/prompt-config/prompt-cache.test.d.ts +0 -6
  175. package/dist/src/prompt-config/prompt-cache.test.js +0 -437
  176. package/dist/src/prompt-config/prompt-cache.test.js.map +0 -1
  177. package/dist/src/prompt-config/prompt-installer.test.d.ts +0 -7
  178. package/dist/src/prompt-config/prompt-installer.test.js +0 -503
  179. package/dist/src/prompt-config/prompt-installer.test.js.map +0 -1
  180. package/dist/src/prompt-config/prompt-loader.test.d.ts +0 -5
  181. package/dist/src/prompt-config/prompt-loader.test.js +0 -413
  182. package/dist/src/prompt-config/prompt-loader.test.js.map +0 -1
  183. package/dist/src/prompt-config/prompt-resolver.test.d.ts +0 -1
  184. package/dist/src/prompt-config/prompt-resolver.test.js +0 -529
  185. package/dist/src/prompt-config/prompt-resolver.test.js.map +0 -1
  186. package/dist/src/prompt-config/prompt-service.test.d.ts +0 -1
  187. package/dist/src/prompt-config/prompt-service.test.js +0 -811
  188. package/dist/src/prompt-config/prompt-service.test.js.map +0 -1
  189. package/dist/src/providers/BaseProvider.test.d.ts +0 -6
  190. package/dist/src/providers/BaseProvider.test.js +0 -472
  191. package/dist/src/providers/BaseProvider.test.js.map +0 -1
  192. package/dist/src/providers/ProviderManager.gemini-switch.test.d.ts +0 -6
  193. package/dist/src/providers/ProviderManager.gemini-switch.test.js +0 -57
  194. package/dist/src/providers/ProviderManager.gemini-switch.test.js.map +0 -1
  195. package/dist/src/providers/ProviderManager.test.d.ts +0 -6
  196. package/dist/src/providers/ProviderManager.test.js +0 -284
  197. package/dist/src/providers/ProviderManager.test.js.map +0 -1
  198. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.d.ts +0 -6
  199. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js +0 -273
  200. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js.map +0 -1
  201. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.d.ts +0 -1
  202. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js +0 -48
  203. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js.map +0 -1
  204. package/dist/src/providers/anthropic/AnthropicProvider.test.d.ts +0 -1
  205. package/dist/src/providers/anthropic/AnthropicProvider.test.js +0 -487
  206. package/dist/src/providers/anthropic/AnthropicProvider.test.js.map +0 -1
  207. package/dist/src/providers/gemini/GeminiProvider.integration.test.d.ts +0 -6
  208. package/dist/src/providers/gemini/GeminiProvider.integration.test.js +0 -126
  209. package/dist/src/providers/gemini/GeminiProvider.integration.test.js.map +0 -1
  210. package/dist/src/providers/gemini/GeminiProvider.test.d.ts +0 -6
  211. package/dist/src/providers/gemini/GeminiProvider.test.js +0 -136
  212. package/dist/src/providers/gemini/GeminiProvider.test.js.map +0 -1
  213. package/dist/src/providers/integration/multi-provider.integration.test.d.ts +0 -6
  214. package/dist/src/providers/integration/multi-provider.integration.test.js +0 -308
  215. package/dist/src/providers/integration/multi-provider.integration.test.js.map +0 -1
  216. package/dist/src/providers/openai/ConversationCache.accumTokens.test.d.ts +0 -1
  217. package/dist/src/providers/openai/ConversationCache.accumTokens.test.js +0 -97
  218. package/dist/src/providers/openai/ConversationCache.accumTokens.test.js.map +0 -1
  219. package/dist/src/providers/openai/ConversationCache.test.d.ts +0 -1
  220. package/dist/src/providers/openai/ConversationCache.test.js +0 -113
  221. package/dist/src/providers/openai/ConversationCache.test.js.map +0 -1
  222. package/dist/src/providers/openai/OpenAIProvider.callResponses.stateless.test.d.ts +0 -1
  223. package/dist/src/providers/openai/OpenAIProvider.callResponses.stateless.test.js +0 -189
  224. package/dist/src/providers/openai/OpenAIProvider.callResponses.stateless.test.js.map +0 -1
  225. package/dist/src/providers/openai/OpenAIProvider.integration.test.d.ts +0 -6
  226. package/dist/src/providers/openai/OpenAIProvider.integration.test.js +0 -125
  227. package/dist/src/providers/openai/OpenAIProvider.integration.test.js.map +0 -1
  228. package/dist/src/providers/openai/OpenAIProvider.responses.test.d.ts +0 -1
  229. package/dist/src/providers/openai/OpenAIProvider.responses.test.js +0 -350
  230. package/dist/src/providers/openai/OpenAIProvider.responses.test.js.map +0 -1
  231. package/dist/src/providers/openai/OpenAIProvider.responsesIntegration.test.d.ts +0 -1
  232. package/dist/src/providers/openai/OpenAIProvider.responsesIntegration.test.js +0 -213
  233. package/dist/src/providers/openai/OpenAIProvider.responsesIntegration.test.js.map +0 -1
  234. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.d.ts +0 -1
  235. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js +0 -59
  236. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js.map +0 -1
  237. package/dist/src/providers/openai/OpenAIProvider.stateful.integration.test.d.ts +0 -6
  238. package/dist/src/providers/openai/OpenAIProvider.stateful.integration.test.js +0 -105
  239. package/dist/src/providers/openai/OpenAIProvider.stateful.integration.test.js.map +0 -1
  240. package/dist/src/providers/openai/OpenAIProvider.switch.test.d.ts +0 -1
  241. package/dist/src/providers/openai/OpenAIProvider.switch.test.js +0 -256
  242. package/dist/src/providers/openai/OpenAIProvider.switch.test.js.map +0 -1
  243. package/dist/src/providers/openai/OpenAIProvider.test.d.ts +0 -16
  244. package/dist/src/providers/openai/OpenAIProvider.test.js +0 -621
  245. package/dist/src/providers/openai/OpenAIProvider.test.js.map +0 -1
  246. package/dist/src/providers/openai/ResponsesContextTrim.integration.test.d.ts +0 -1
  247. package/dist/src/providers/openai/ResponsesContextTrim.integration.test.js +0 -210
  248. package/dist/src/providers/openai/ResponsesContextTrim.integration.test.js.map +0 -1
  249. package/dist/src/providers/openai/__tests__/formatArrayResponse.test.d.ts +0 -1
  250. package/dist/src/providers/openai/__tests__/formatArrayResponse.test.js +0 -65
  251. package/dist/src/providers/openai/__tests__/formatArrayResponse.test.js.map +0 -1
  252. package/dist/src/providers/openai/buildResponsesRequest.stripToolCalls.test.d.ts +0 -1
  253. package/dist/src/providers/openai/buildResponsesRequest.stripToolCalls.test.js +0 -129
  254. package/dist/src/providers/openai/buildResponsesRequest.stripToolCalls.test.js.map +0 -1
  255. package/dist/src/providers/openai/buildResponsesRequest.test.d.ts +0 -1
  256. package/dist/src/providers/openai/buildResponsesRequest.test.js +0 -406
  257. package/dist/src/providers/openai/buildResponsesRequest.test.js.map +0 -1
  258. package/dist/src/providers/openai/buildResponsesRequest.undefined.test.d.ts +0 -1
  259. package/dist/src/providers/openai/buildResponsesRequest.undefined.test.js +0 -50
  260. package/dist/src/providers/openai/buildResponsesRequest.undefined.test.js.map +0 -1
  261. package/dist/src/providers/openai/estimateRemoteTokens.test.d.ts +0 -1
  262. package/dist/src/providers/openai/estimateRemoteTokens.test.js +0 -125
  263. package/dist/src/providers/openai/estimateRemoteTokens.test.js.map +0 -1
  264. package/dist/src/providers/openai/openai-oauth.spec.d.ts +0 -16
  265. package/dist/src/providers/openai/openai-oauth.spec.js +0 -544
  266. package/dist/src/providers/openai/openai-oauth.spec.js.map +0 -1
  267. package/dist/src/providers/openai/parseResponsesStream.responsesToolCalls.test.d.ts +0 -1
  268. package/dist/src/providers/openai/parseResponsesStream.responsesToolCalls.test.js +0 -192
  269. package/dist/src/providers/openai/parseResponsesStream.responsesToolCalls.test.js.map +0 -1
  270. package/dist/src/providers/openai/parseResponsesStream.test.d.ts +0 -1
  271. package/dist/src/providers/openai/parseResponsesStream.test.js +0 -151
  272. package/dist/src/providers/openai/parseResponsesStream.test.js.map +0 -1
  273. package/dist/src/services/fileDiscoveryService.test.d.ts +0 -6
  274. package/dist/src/services/fileDiscoveryService.test.js +0 -143
  275. package/dist/src/services/fileDiscoveryService.test.js.map +0 -1
  276. package/dist/src/services/gitService.test.d.ts +0 -6
  277. package/dist/src/services/gitService.test.js +0 -209
  278. package/dist/src/services/gitService.test.js.map +0 -1
  279. package/dist/src/services/loopDetectionService.test.d.ts +0 -6
  280. package/dist/src/services/loopDetectionService.test.js +0 -484
  281. package/dist/src/services/loopDetectionService.test.js.map +0 -1
  282. package/dist/src/services/shellExecutionService.multibyte.test.d.ts +0 -6
  283. package/dist/src/services/shellExecutionService.multibyte.test.js +0 -72
  284. package/dist/src/services/shellExecutionService.multibyte.test.js.map +0 -1
  285. package/dist/src/services/shellExecutionService.test.d.ts +0 -6
  286. package/dist/src/services/shellExecutionService.test.js +0 -272
  287. package/dist/src/services/shellExecutionService.test.js.map +0 -1
  288. package/dist/src/services/shellExecutionService.windows.multibyte.test.d.ts +0 -6
  289. package/dist/src/services/shellExecutionService.windows.multibyte.test.js +0 -98
  290. package/dist/src/services/shellExecutionService.windows.multibyte.test.js.map +0 -1
  291. package/dist/src/services/shellExecutionService.windows.test.d.ts +0 -6
  292. package/dist/src/services/shellExecutionService.windows.test.js +0 -79
  293. package/dist/src/services/shellExecutionService.windows.test.js.map +0 -1
  294. package/dist/src/services/tool-call-tracker-service.test.d.ts +0 -6
  295. package/dist/src/services/tool-call-tracker-service.test.js +0 -99
  296. package/dist/src/services/tool-call-tracker-service.test.js.map +0 -1
  297. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +0 -6
  298. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +0 -187
  299. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +0 -1
  300. package/dist/src/telemetry/loggers.test.d.ts +0 -6
  301. package/dist/src/telemetry/loggers.test.js +0 -573
  302. package/dist/src/telemetry/loggers.test.js.map +0 -1
  303. package/dist/src/telemetry/metrics.test.d.ts +0 -6
  304. package/dist/src/telemetry/metrics.test.js +0 -212
  305. package/dist/src/telemetry/metrics.test.js.map +0 -1
  306. package/dist/src/telemetry/telemetry.test.d.ts +0 -6
  307. package/dist/src/telemetry/telemetry.test.js +0 -54
  308. package/dist/src/telemetry/telemetry.test.js.map +0 -1
  309. package/dist/src/telemetry/uiTelemetry.test.d.ts +0 -6
  310. package/dist/src/telemetry/uiTelemetry.test.js +0 -518
  311. package/dist/src/telemetry/uiTelemetry.test.js.map +0 -1
  312. package/dist/src/tools/ToolFormatter.test.d.ts +0 -16
  313. package/dist/src/tools/ToolFormatter.test.js +0 -349
  314. package/dist/src/tools/ToolFormatter.test.js.map +0 -1
  315. package/dist/src/tools/ToolFormatter.toResponsesTool.test.d.ts +0 -1
  316. package/dist/src/tools/ToolFormatter.toResponsesTool.test.js +0 -241
  317. package/dist/src/tools/ToolFormatter.toResponsesTool.test.js.map +0 -1
  318. package/dist/src/tools/diffOptions.test.d.ts +0 -6
  319. package/dist/src/tools/diffOptions.test.js +0 -119
  320. package/dist/src/tools/diffOptions.test.js.map +0 -1
  321. package/dist/src/tools/edit.test.d.ts +0 -6
  322. package/dist/src/tools/edit.test.js +0 -689
  323. package/dist/src/tools/edit.test.js.map +0 -1
  324. package/dist/src/tools/glob.test.d.ts +0 -6
  325. package/dist/src/tools/glob.test.js +0 -332
  326. package/dist/src/tools/glob.test.js.map +0 -1
  327. package/dist/src/tools/grep.test.d.ts +0 -6
  328. package/dist/src/tools/grep.test.js +0 -272
  329. package/dist/src/tools/grep.test.js.map +0 -1
  330. package/dist/src/tools/ls.test.d.ts +0 -6
  331. package/dist/src/tools/ls.test.js +0 -357
  332. package/dist/src/tools/ls.test.js.map +0 -1
  333. package/dist/src/tools/mcp-client.test.d.ts +0 -6
  334. package/dist/src/tools/mcp-client.test.js +0 -617
  335. package/dist/src/tools/mcp-client.test.js.map +0 -1
  336. package/dist/src/tools/mcp-tool.test.d.ts +0 -6
  337. package/dist/src/tools/mcp-tool.test.js +0 -501
  338. package/dist/src/tools/mcp-tool.test.js.map +0 -1
  339. package/dist/src/tools/memoryTool.test.d.ts +0 -6
  340. package/dist/src/tools/memoryTool.test.js +0 -266
  341. package/dist/src/tools/memoryTool.test.js.map +0 -1
  342. package/dist/src/tools/modifiable-tool.test.d.ts +0 -6
  343. package/dist/src/tools/modifiable-tool.test.js +0 -193
  344. package/dist/src/tools/modifiable-tool.test.js.map +0 -1
  345. package/dist/src/tools/read-file.test.d.ts +0 -6
  346. package/dist/src/tools/read-file.test.js +0 -319
  347. package/dist/src/tools/read-file.test.js.map +0 -1
  348. package/dist/src/tools/read-many-files.test.d.ts +0 -6
  349. package/dist/src/tools/read-many-files.test.js +0 -644
  350. package/dist/src/tools/read-many-files.test.js.map +0 -1
  351. package/dist/src/tools/shell.multibyte.test.d.ts +0 -6
  352. package/dist/src/tools/shell.multibyte.test.js +0 -75
  353. package/dist/src/tools/shell.multibyte.test.js.map +0 -1
  354. package/dist/src/tools/shell.test.d.ts +0 -6
  355. package/dist/src/tools/shell.test.js +0 -367
  356. package/dist/src/tools/shell.test.js.map +0 -1
  357. package/dist/src/tools/todo-pause.spec.d.ts +0 -6
  358. package/dist/src/tools/todo-pause.spec.js +0 -287
  359. package/dist/src/tools/todo-pause.spec.js.map +0 -1
  360. package/dist/src/tools/todo-read.test.d.ts +0 -6
  361. package/dist/src/tools/todo-read.test.js +0 -162
  362. package/dist/src/tools/todo-read.test.js.map +0 -1
  363. package/dist/src/tools/todo-schemas.test.d.ts +0 -6
  364. package/dist/src/tools/todo-schemas.test.js +0 -341
  365. package/dist/src/tools/todo-schemas.test.js.map +0 -1
  366. package/dist/src/tools/todo-store.test.d.ts +0 -6
  367. package/dist/src/tools/todo-store.test.js +0 -169
  368. package/dist/src/tools/todo-store.test.js.map +0 -1
  369. package/dist/src/tools/todo-write.test.d.ts +0 -6
  370. package/dist/src/tools/todo-write.test.js +0 -226
  371. package/dist/src/tools/todo-write.test.js.map +0 -1
  372. package/dist/src/tools/tool-registry.test.d.ts +0 -6
  373. package/dist/src/tools/tool-registry.test.js +0 -468
  374. package/dist/src/tools/tool-registry.test.js.map +0 -1
  375. package/dist/src/tools/tools.test.d.ts +0 -6
  376. package/dist/src/tools/tools.test.js +0 -117
  377. package/dist/src/tools/tools.test.js.map +0 -1
  378. package/dist/src/tools/web-fetch.integration.test.d.ts +0 -6
  379. package/dist/src/tools/web-fetch.integration.test.js +0 -532
  380. package/dist/src/tools/web-fetch.integration.test.js.map +0 -1
  381. package/dist/src/tools/web-search.test.d.ts +0 -6
  382. package/dist/src/tools/web-search.test.js +0 -230
  383. package/dist/src/tools/web-search.test.js.map +0 -1
  384. package/dist/src/tools/write-file.test.d.ts +0 -6
  385. package/dist/src/tools/write-file.test.js +0 -465
  386. package/dist/src/tools/write-file.test.js.map +0 -1
  387. package/dist/src/utils/bfsFileSearch.test.d.ts +0 -6
  388. package/dist/src/utils/bfsFileSearch.test.js +0 -191
  389. package/dist/src/utils/bfsFileSearch.test.js.map +0 -1
  390. package/dist/src/utils/editCorrector.test.d.ts +0 -6
  391. package/dist/src/utils/editCorrector.test.js +0 -564
  392. package/dist/src/utils/editCorrector.test.js.map +0 -1
  393. package/dist/src/utils/editor.test.d.ts +0 -6
  394. package/dist/src/utils/editor.test.js +0 -445
  395. package/dist/src/utils/editor.test.js.map +0 -1
  396. package/dist/src/utils/environmentContext.test.d.ts +0 -6
  397. package/dist/src/utils/environmentContext.test.js +0 -139
  398. package/dist/src/utils/environmentContext.test.js.map +0 -1
  399. package/dist/src/utils/errorReporting.test.d.ts +0 -6
  400. package/dist/src/utils/errorReporting.test.js +0 -130
  401. package/dist/src/utils/errorReporting.test.js.map +0 -1
  402. package/dist/src/utils/fileUtils.test.d.ts +0 -6
  403. package/dist/src/utils/fileUtils.test.js +0 -363
  404. package/dist/src/utils/fileUtils.test.js.map +0 -1
  405. package/dist/src/utils/filesearch/crawlCache.test.d.ts +0 -6
  406. package/dist/src/utils/filesearch/crawlCache.test.js +0 -103
  407. package/dist/src/utils/filesearch/crawlCache.test.js.map +0 -1
  408. package/dist/src/utils/filesearch/fileSearch.test.d.ts +0 -6
  409. package/dist/src/utils/filesearch/fileSearch.test.js +0 -654
  410. package/dist/src/utils/filesearch/fileSearch.test.js.map +0 -1
  411. package/dist/src/utils/filesearch/ignore.test.d.ts +0 -6
  412. package/dist/src/utils/filesearch/ignore.test.js +0 -57
  413. package/dist/src/utils/filesearch/ignore.test.js.map +0 -1
  414. package/dist/src/utils/filesearch/result-cache.test.d.ts +0 -6
  415. package/dist/src/utils/filesearch/result-cache.test.js +0 -47
  416. package/dist/src/utils/filesearch/result-cache.test.js.map +0 -1
  417. package/dist/src/utils/flashFallback.integration.test.d.ts +0 -6
  418. package/dist/src/utils/flashFallback.integration.test.js +0 -120
  419. package/dist/src/utils/flashFallback.integration.test.js.map +0 -1
  420. package/dist/src/utils/generateContentResponseUtilities.test.d.ts +0 -6
  421. package/dist/src/utils/generateContentResponseUtilities.test.js +0 -273
  422. package/dist/src/utils/generateContentResponseUtilities.test.js.map +0 -1
  423. package/dist/src/utils/getFolderStructure.test.d.ts +0 -6
  424. package/dist/src/utils/getFolderStructure.test.js +0 -282
  425. package/dist/src/utils/getFolderStructure.test.js.map +0 -1
  426. package/dist/src/utils/gitIgnoreParser.test.d.ts +0 -6
  427. package/dist/src/utils/gitIgnoreParser.test.js +0 -154
  428. package/dist/src/utils/gitIgnoreParser.test.js.map +0 -1
  429. package/dist/src/utils/memoryDiscovery.test.d.ts +0 -6
  430. package/dist/src/utils/memoryDiscovery.test.js +0 -181
  431. package/dist/src/utils/memoryDiscovery.test.js.map +0 -1
  432. package/dist/src/utils/memoryImportProcessor.test.d.ts +0 -6
  433. package/dist/src/utils/memoryImportProcessor.test.js +0 -715
  434. package/dist/src/utils/memoryImportProcessor.test.js.map +0 -1
  435. package/dist/src/utils/nextSpeakerChecker.test.d.ts +0 -6
  436. package/dist/src/utils/nextSpeakerChecker.test.js +0 -172
  437. package/dist/src/utils/nextSpeakerChecker.test.js.map +0 -1
  438. package/dist/src/utils/partUtils.test.d.ts +0 -6
  439. package/dist/src/utils/partUtils.test.js +0 -130
  440. package/dist/src/utils/partUtils.test.js.map +0 -1
  441. package/dist/src/utils/paths.test.d.ts +0 -6
  442. package/dist/src/utils/paths.test.js +0 -153
  443. package/dist/src/utils/paths.test.js.map +0 -1
  444. package/dist/src/utils/retry.test.d.ts +0 -6
  445. package/dist/src/utils/retry.test.js +0 -322
  446. package/dist/src/utils/retry.test.js.map +0 -1
  447. package/dist/src/utils/safeJsonStringify.test.d.ts +0 -6
  448. package/dist/src/utils/safeJsonStringify.test.js +0 -61
  449. package/dist/src/utils/safeJsonStringify.test.js.map +0 -1
  450. package/dist/src/utils/sanitization.test.d.ts +0 -6
  451. package/dist/src/utils/sanitization.test.js +0 -81
  452. package/dist/src/utils/sanitization.test.js.map +0 -1
  453. package/dist/src/utils/schemaValidator.test.d.ts +0 -6
  454. package/dist/src/utils/schemaValidator.test.js +0 -146
  455. package/dist/src/utils/schemaValidator.test.js.map +0 -1
  456. package/dist/src/utils/secure-browser-launcher.test.d.ts +0 -6
  457. package/dist/src/utils/secure-browser-launcher.test.js +0 -149
  458. package/dist/src/utils/secure-browser-launcher.test.js.map +0 -1
  459. package/dist/src/utils/shell-utils.shellReplacement.test.d.ts +0 -6
  460. package/dist/src/utils/shell-utils.shellReplacement.test.js +0 -149
  461. package/dist/src/utils/shell-utils.shellReplacement.test.js.map +0 -1
  462. package/dist/src/utils/shell-utils.test.d.ts +0 -6
  463. package/dist/src/utils/shell-utils.test.js +0 -200
  464. package/dist/src/utils/shell-utils.test.js.map +0 -1
  465. package/dist/src/utils/summarizer.test.d.ts +0 -6
  466. package/dist/src/utils/summarizer.test.js +0 -131
  467. package/dist/src/utils/summarizer.test.js.map +0 -1
  468. package/dist/src/utils/systemEncoding.test.d.ts +0 -6
  469. package/dist/src/utils/systemEncoding.test.js +0 -368
  470. package/dist/src/utils/systemEncoding.test.js.map +0 -1
  471. package/dist/src/utils/toolOutputLimiter.test.d.ts +0 -6
  472. package/dist/src/utils/toolOutputLimiter.test.js +0 -164
  473. package/dist/src/utils/toolOutputLimiter.test.js.map +0 -1
  474. package/dist/src/utils/unicodeUtils.test.d.ts +0 -6
  475. package/dist/src/utils/unicodeUtils.test.js +0 -120
  476. package/dist/src/utils/unicodeUtils.test.js.map +0 -1
  477. package/dist/src/utils/user_account.test.d.ts +0 -6
  478. package/dist/src/utils/user_account.test.js +0 -153
  479. package/dist/src/utils/user_account.test.js.map +0 -1
  480. package/dist/src/utils/user_id.test.d.ts +0 -6
  481. package/dist/src/utils/user_id.test.js +0 -21
  482. package/dist/src/utils/user_id.test.js.map +0 -1
  483. package/dist/src/utils/workspaceContext.test.d.ts +0 -6
  484. package/dist/src/utils/workspaceContext.test.js +0 -209
  485. package/dist/src/utils/workspaceContext.test.js.map +0 -1
@@ -1,793 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Vybestack LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
- import { createServer } from 'http';
8
- import { randomBytes, createHash } from 'crypto';
9
- import { QwenDeviceFlow } from './qwen-device-flow.js';
10
- describe('QwenDeviceFlow - Behavioral Tests', () => {
11
- let testServer;
12
- let serverPort;
13
- let deviceFlow;
14
- let config;
15
- beforeEach(async () => {
16
- // Start test HTTP server
17
- testServer = createServer();
18
- await new Promise((resolve) => {
19
- testServer.listen(0, () => {
20
- serverPort = testServer.address().port;
21
- resolve();
22
- });
23
- });
24
- // Configure device flow with test server endpoints
25
- config = {
26
- clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
27
- authorizationEndpoint: `http://localhost:${serverPort}/api/v1/oauth2/device/code`,
28
- tokenEndpoint: `http://localhost:${serverPort}/api/v1/oauth2/token`,
29
- scopes: ['read', 'write'],
30
- };
31
- deviceFlow = new QwenDeviceFlow(config);
32
- });
33
- afterEach(async () => {
34
- if (testServer) {
35
- await new Promise((resolve) => {
36
- testServer.close(() => resolve());
37
- });
38
- }
39
- });
40
- describe('Device Flow Initiation', () => {
41
- /**
42
- * @requirement REQ-002.1
43
- * @scenario Initiate device authorization
44
- * @given Valid Qwen OAuth config
45
- * @when initiateDeviceFlow() is called
46
- * @then Returns device code and verification URI
47
- * @and Response includes user code for display
48
- */
49
- it('should initiate device flow and return required fields', async () => {
50
- const mockResponse = {
51
- device_code: 'GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS',
52
- user_code: 'WDJB-MJHT',
53
- verification_uri: 'https://chat.qwen.ai/activate',
54
- verification_uri_complete: 'https://chat.qwen.ai/activate?user_code=WDJB-MJHT',
55
- expires_in: 900, // 15 minutes
56
- interval: 5, // 5 seconds
57
- };
58
- testServer.removeAllListeners('request');
59
- testServer.on('request', (req, res) => {
60
- expect(req.method).toBe('POST');
61
- expect(req.url).toBe('/api/v1/oauth2/device/code');
62
- let body = '';
63
- req.on('data', (chunk) => {
64
- body += chunk;
65
- });
66
- req.on('end', () => {
67
- const params = new URLSearchParams(body);
68
- expect(params.get('client_id')).toBe('f0304373b74a44d2b584a3fb70ca9e56');
69
- expect(params.get('scope')).toBe('read write');
70
- res.writeHead(200, { 'Content-Type': 'application/json' });
71
- res.end(JSON.stringify(mockResponse));
72
- });
73
- });
74
- const result = await deviceFlow.initiateDeviceFlow();
75
- expect(result).toMatchObject(mockResponse);
76
- });
77
- /**
78
- * @requirement REQ-002.3
79
- * @scenario Correct authorization endpoint
80
- * @given Qwen device flow instance
81
- * @when initiateDeviceFlow() makes request
82
- * @then Uses https://chat.qwen.ai/api/v1/oauth2/device/code
83
- */
84
- it('should use correct Qwen authorization endpoint', async () => {
85
- const realConfig = {
86
- clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
87
- authorizationEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
88
- tokenEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/token',
89
- scopes: ['read'],
90
- };
91
- const realDeviceFlow = new QwenDeviceFlow(realConfig);
92
- // This will fail with a real network request, which is expected
93
- await expect(realDeviceFlow.initiateDeviceFlow()).rejects.toThrow('HTTP 400: Bad Request');
94
- // Verify the configuration contains the correct endpoint
95
- expect(realConfig.authorizationEndpoint).toBe('https://chat.qwen.ai/api/v1/oauth2/device/code');
96
- });
97
- /**
98
- * @requirement REQ-002.4
99
- * @scenario Uses correct client ID
100
- * @given Device flow request
101
- * @when sent to Qwen
102
- * @then Includes client_id: f0304373b74a44d2b584a3fb70ca9e56
103
- */
104
- it('should include correct Qwen client ID in request', async () => {
105
- testServer.removeAllListeners('request');
106
- testServer.on('request', (req, res) => {
107
- let body = '';
108
- req.on('data', (chunk) => {
109
- body += chunk;
110
- });
111
- req.on('end', () => {
112
- const params = new URLSearchParams(body);
113
- expect(params.get('client_id')).toBe('f0304373b74a44d2b584a3fb70ca9e56');
114
- res.writeHead(200, { 'Content-Type': 'application/json' });
115
- res.end(JSON.stringify({
116
- device_code: 'test',
117
- user_code: 'TEST',
118
- verification_uri: 'https://test',
119
- expires_in: 900,
120
- interval: 5,
121
- }));
122
- });
123
- });
124
- const result = await deviceFlow.initiateDeviceFlow();
125
- expect(result).toMatchObject({
126
- device_code: 'test',
127
- user_code: 'TEST',
128
- verification_uri: 'https://test',
129
- expires_in: 900,
130
- interval: 5,
131
- });
132
- });
133
- /**
134
- * @requirement REQ-002.1
135
- * @scenario Device code response validation
136
- * @given Response from authorization endpoint
137
- * @when parsing response
138
- * @then Validates all required fields present
139
- */
140
- it('should validate device code response contains all required fields', async () => {
141
- const incompleteResponse = {
142
- device_code: 'test_device_code',
143
- // Missing user_code, verification_uri, expires_in, interval
144
- };
145
- testServer.removeAllListeners('request');
146
- testServer.on('request', (req, res) => {
147
- res.writeHead(200, { 'Content-Type': 'application/json' });
148
- res.end(JSON.stringify(incompleteResponse));
149
- });
150
- // Should throw validation error due to missing required fields
151
- await expect(deviceFlow.initiateDeviceFlow()).rejects.toThrow();
152
- });
153
- });
154
- describe('PKCE Security', () => {
155
- /**
156
- * @requirement REQ-002.2
157
- * @scenario PKCE code challenge generation
158
- * @given Device flow initiation
159
- * @when PKCE is generated
160
- * @then Creates SHA-256 challenge from verifier
161
- * @and Verifier is cryptographically random
162
- */
163
- it('should generate cryptographically random PKCE verifier and SHA-256 challenge', async () => {
164
- // Test the cryptographic operations directly since implementation is not ready
165
- const verifier1 = randomBytes(32).toString('base64url');
166
- const verifier2 = randomBytes(32).toString('base64url');
167
- // Verifiers should be different (random)
168
- expect(verifier1).not.toBe(verifier2);
169
- expect(verifier1).toHaveLength(43); // 32 bytes base64url = 43 chars
170
- // Challenge should be SHA-256 of verifier
171
- const challenge1 = createHash('sha256')
172
- .update(verifier1)
173
- .digest('base64url');
174
- const challenge2 = createHash('sha256')
175
- .update(verifier2)
176
- .digest('base64url');
177
- expect(challenge1).not.toBe(challenge2);
178
- expect(challenge1).toHaveLength(43); // SHA-256 base64url = 43 chars
179
- // Verify reproducible challenge generation
180
- const sameChallengeAgain = createHash('sha256')
181
- .update(verifier1)
182
- .digest('base64url');
183
- expect(challenge1).toBe(sameChallengeAgain);
184
- // The PKCE generation logic is tested above with real crypto functions.
185
- // The actual implementation works correctly.
186
- expect(challenge1).toHaveLength(43); // This was already tested above
187
- });
188
- /**
189
- * @requirement REQ-002.2
190
- * @scenario PKCE parameters in device request
191
- * @given Device flow initiation with PKCE
192
- * @when request is made
193
- * @then Includes code_challenge and code_challenge_method=S256
194
- */
195
- it('should include PKCE parameters in device authorization request', async () => {
196
- testServer.removeAllListeners('request');
197
- testServer.on('request', (req, res) => {
198
- let body = '';
199
- req.on('data', (chunk) => {
200
- body += chunk;
201
- });
202
- req.on('end', () => {
203
- const params = new URLSearchParams(body);
204
- expect(params.get('code_challenge')).toBeDefined();
205
- expect(params.get('code_challenge_method')).toBe('S256');
206
- expect(params.get('code_challenge')).toHaveLength(43); // SHA-256 base64url length
207
- res.writeHead(200, { 'Content-Type': 'application/json' });
208
- res.end(JSON.stringify({
209
- device_code: 'test',
210
- user_code: 'TEST',
211
- verification_uri: 'https://test',
212
- expires_in: 900,
213
- interval: 5,
214
- }));
215
- });
216
- });
217
- const result = await deviceFlow.initiateDeviceFlow();
218
- expect(result).toMatchObject({
219
- device_code: 'test',
220
- user_code: 'TEST',
221
- verification_uri: 'https://test',
222
- expires_in: 900,
223
- interval: 5,
224
- });
225
- });
226
- /**
227
- * @requirement REQ-002.2
228
- * @scenario PKCE verifier storage
229
- * @given Device flow initiated with PKCE
230
- * @when polling for token
231
- * @then Uses same verifier for token exchange
232
- */
233
- it('should store PKCE verifier for later token exchange', async () => {
234
- testServer.removeAllListeners('request');
235
- let storedChallenge;
236
- testServer.on('request', (req, res) => {
237
- if (req.url?.includes('device/code')) {
238
- let body = '';
239
- req.on('data', (chunk) => {
240
- body += chunk;
241
- });
242
- req.on('end', () => {
243
- const params = new URLSearchParams(body);
244
- storedChallenge = params.get('code_challenge') || undefined;
245
- res.writeHead(200, { 'Content-Type': 'application/json' });
246
- res.end(JSON.stringify({
247
- device_code: 'test_device',
248
- user_code: 'TEST',
249
- verification_uri: 'https://test',
250
- expires_in: 900,
251
- interval: 5,
252
- }));
253
- });
254
- }
255
- else if (req.url?.includes('token')) {
256
- let body = '';
257
- req.on('data', (chunk) => {
258
- body += chunk;
259
- });
260
- req.on('end', () => {
261
- const params = new URLSearchParams(body);
262
- const verifier = params.get('code_verifier');
263
- // Verify that the verifier produces the same challenge
264
- if (verifier && storedChallenge) {
265
- const expectedChallenge = createHash('sha256')
266
- .update(verifier)
267
- .digest('base64url');
268
- expect(expectedChallenge).toBe(storedChallenge);
269
- }
270
- res.writeHead(200, { 'Content-Type': 'application/json' });
271
- res.end(JSON.stringify({
272
- access_token: 'test_token',
273
- token_type: 'Bearer',
274
- expires_in: 3600,
275
- }));
276
- });
277
- }
278
- });
279
- // Test the requirement by initiating the flow then polling
280
- const deviceResult = await deviceFlow.initiateDeviceFlow();
281
- expect(deviceResult.device_code).toBe('test_device');
282
- // The verifier verification happens in the mock server above
283
- // This will timeout eventually, but the verifier matching is tested in the mock
284
- try {
285
- await deviceFlow.pollForToken('test_device');
286
- }
287
- catch (error) {
288
- // Expected to timeout or get a token - both are valid outcomes
289
- expect(error).toBeDefined();
290
- }
291
- });
292
- });
293
- describe('Token Polling', () => {
294
- /**
295
- * @requirement REQ-002.1
296
- * @scenario Poll for authorization completion
297
- * @given Device code from initiation
298
- * @when pollForToken() called repeatedly
299
- * @then Continues until user authorizes
300
- * @and Returns access token on success
301
- */
302
- it('should poll for token until authorization completes', { timeout: 20000 }, async () => {
303
- let pollCount = 0;
304
- const mockToken = {
305
- access_token: 'qwen_access_token_12345',
306
- token_type: 'Bearer',
307
- expiry: Math.floor(Date.now() / 1000) + 3600,
308
- refresh_token: 'qwen_refresh_token_67890',
309
- scope: 'read write',
310
- };
311
- testServer.removeAllListeners('request');
312
- testServer.on('request', (req, res) => {
313
- if (req.url?.includes('token')) {
314
- pollCount++;
315
- let body = '';
316
- req.on('data', (chunk) => {
317
- body += chunk;
318
- });
319
- req.on('end', () => {
320
- const params = new URLSearchParams(body);
321
- expect(params.get('grant_type')).toBe('urn:ietf:params:oauth:grant-type:device_code');
322
- expect(params.get('device_code')).toBe('test_device_code');
323
- expect(params.get('client_id')).toBe('f0304373b74a44d2b584a3fb70ca9e56');
324
- if (pollCount < 3) {
325
- // First few attempts return pending
326
- res.writeHead(400, { 'Content-Type': 'application/json' });
327
- res.end(JSON.stringify({ error: 'authorization_pending' }));
328
- }
329
- else {
330
- // Eventually return success
331
- res.writeHead(200, { 'Content-Type': 'application/json' });
332
- res.end(JSON.stringify({
333
- access_token: mockToken.access_token,
334
- token_type: mockToken.token_type,
335
- expires_in: 3600,
336
- refresh_token: mockToken.refresh_token,
337
- scope: mockToken.scope,
338
- }));
339
- }
340
- });
341
- }
342
- });
343
- // This will actually poll and succeed after the third attempt
344
- const result = await deviceFlow.pollForToken('test_device_code');
345
- expect(result).toMatchObject({
346
- access_token: mockToken.access_token,
347
- token_type: 'Bearer',
348
- scope: mockToken.scope,
349
- refresh_token: mockToken.refresh_token,
350
- });
351
- });
352
- /**
353
- * @requirement REQ-002.3
354
- * @scenario Token endpoint usage
355
- * @given Device code for polling
356
- * @when requesting token
357
- * @then Uses https://chat.qwen.ai/api/v1/oauth2/token
358
- */
359
- it('should use correct Qwen token endpoint', async () => {
360
- const realConfig = {
361
- clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
362
- authorizationEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
363
- tokenEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/token',
364
- scopes: ['read'],
365
- };
366
- const realDeviceFlow = new QwenDeviceFlow(realConfig);
367
- // This will fail with a real network request, which is expected
368
- await expect(realDeviceFlow.pollForToken('test_device')).rejects.toThrow('HTTP 400: Bad Request');
369
- // Verify the configuration contains the correct endpoint
370
- expect(realConfig.tokenEndpoint).toBe('https://chat.qwen.ai/api/v1/oauth2/token');
371
- });
372
- /**
373
- * @requirement REQ-002.1
374
- * @scenario Respect polling interval
375
- * @given Server specifies 5 second interval
376
- * @when polling for token
377
- * @then Waits at least 5 seconds between requests
378
- */
379
- it('should respect server-specified polling interval', { timeout: 30000 }, async () => {
380
- const timestamps = [];
381
- let requestCount = 0;
382
- testServer.removeAllListeners('request');
383
- testServer.on('request', (req, res) => {
384
- timestamps.push(Date.now());
385
- requestCount++;
386
- // Return success after 3 requests to avoid timeout
387
- if (requestCount >= 3) {
388
- res.writeHead(200, { 'Content-Type': 'application/json' });
389
- res.end(JSON.stringify({
390
- access_token: 'test_token',
391
- token_type: 'Bearer',
392
- expires_in: 3600,
393
- }));
394
- }
395
- else {
396
- res.writeHead(400, { 'Content-Type': 'application/json' });
397
- res.end(JSON.stringify({ error: 'authorization_pending' }));
398
- }
399
- });
400
- // This test verifies the requirement for interval handling
401
- // Should succeed after 3 requests and we can verify intervals
402
- const result = await deviceFlow.pollForToken('test_device');
403
- expect(result.access_token).toBe('test_token');
404
- // Verify we made multiple requests with proper intervals
405
- expect(timestamps.length).toBeGreaterThanOrEqual(3);
406
- // Verify the intervals are at least close to 5 seconds (allowing some variance)
407
- if (timestamps.length > 1) {
408
- const intervals = timestamps
409
- .slice(1)
410
- .map((t, i) => t - timestamps[i]);
411
- intervals.forEach((interval) => expect(interval).toBeGreaterThanOrEqual(4000)); // Allow some variance
412
- }
413
- });
414
- /**
415
- * @requirement REQ-002.1
416
- * @scenario Token response validation
417
- * @given Token response from endpoint
418
- * @when parsing token
419
- * @then Validates access_token and expiry
420
- */
421
- it('should validate token response contains required fields', async () => {
422
- const invalidTokenResponse = {
423
- // Missing access_token
424
- token_type: 'Bearer',
425
- expires_in: 3600,
426
- };
427
- testServer.removeAllListeners('request');
428
- testServer.on('request', (req, res) => {
429
- res.writeHead(200, { 'Content-Type': 'application/json' });
430
- res.end(JSON.stringify(invalidTokenResponse));
431
- });
432
- // Should throw validation error due to missing access_token
433
- await expect(deviceFlow.pollForToken('test_device')).rejects.toThrow();
434
- });
435
- });
436
- describe('Token Refresh', () => {
437
- /**
438
- * @requirement REQ-002.5
439
- * @scenario Refresh token before expiry
440
- * @given Token expires in 30 seconds
441
- * @when refresh requested
442
- * @then Obtains new access token
443
- * @and Uses refresh token grant type
444
- */
445
- it('should refresh token using refresh grant type', async () => {
446
- const newToken = {
447
- access_token: 'new_access_token_12345',
448
- token_type: 'Bearer',
449
- expiry: Math.floor(Date.now() / 1000) + 3600,
450
- refresh_token: 'new_refresh_token_67890',
451
- scope: 'read write',
452
- };
453
- testServer.removeAllListeners('request');
454
- testServer.on('request', (req, res) => {
455
- let body = '';
456
- req.on('data', (chunk) => {
457
- body += chunk;
458
- });
459
- req.on('end', () => {
460
- const params = new URLSearchParams(body);
461
- expect(params.get('grant_type')).toBe('refresh_token');
462
- expect(params.get('refresh_token')).toBe('old_refresh_token');
463
- expect(params.get('client_id')).toBe('f0304373b74a44d2b584a3fb70ca9e56');
464
- res.writeHead(200, { 'Content-Type': 'application/json' });
465
- res.end(JSON.stringify({
466
- access_token: newToken.access_token,
467
- token_type: newToken.token_type,
468
- expires_in: 3600,
469
- refresh_token: newToken.refresh_token,
470
- scope: newToken.scope,
471
- }));
472
- });
473
- });
474
- const result = await deviceFlow.refreshToken('old_refresh_token');
475
- expect(result).toMatchObject({
476
- access_token: newToken.access_token,
477
- token_type: 'Bearer',
478
- scope: newToken.scope,
479
- refresh_token: newToken.refresh_token,
480
- });
481
- });
482
- /**
483
- * @requirement REQ-002.5
484
- * @scenario Automatic refresh buffer
485
- * @given Token with expiry time
486
- * @when checking if refresh needed
487
- * @then Triggers 30 seconds before expiry
488
- */
489
- it('should identify tokens needing refresh with 30-second buffer', () => {
490
- const now = Date.now() / 1000;
491
- // Token expiring in 25 seconds (less than 30-second buffer)
492
- const soonExpiringToken = {
493
- access_token: 'soon_expiring',
494
- token_type: 'Bearer',
495
- expiry: Math.floor(now + 25),
496
- };
497
- // Token expiring in 35 seconds (more than 30-second buffer)
498
- const validToken = {
499
- access_token: 'still_valid',
500
- token_type: 'Bearer',
501
- expiry: Math.floor(now + 35),
502
- };
503
- // Already expired token
504
- const expiredToken = {
505
- access_token: 'expired',
506
- token_type: 'Bearer',
507
- expiry: Math.floor(now - 10),
508
- };
509
- // When implemented, these should help verify refresh logic:
510
- // expect(deviceFlow.needsRefresh(soonExpiringToken)).toBe(true);
511
- // expect(deviceFlow.needsRefresh(validToken)).toBe(false);
512
- // expect(deviceFlow.needsRefresh(expiredToken)).toBe(true);
513
- // For now, just verify the test data is set up correctly
514
- expect(soonExpiringToken.expiry).toBeLessThan(now + 30);
515
- expect(validToken.expiry).toBeGreaterThan(now + 30);
516
- expect(expiredToken.expiry).toBeLessThan(now);
517
- });
518
- });
519
- describe('Error Handling', () => {
520
- /**
521
- * @requirement REQ-002.1
522
- * @scenario Handle authorization denial
523
- * @given User denies authorization
524
- * @when polling for token
525
- * @then Returns specific denial error
526
- */
527
- it('should handle user authorization denial', async () => {
528
- testServer.removeAllListeners('request');
529
- testServer.on('request', (req, res) => {
530
- res.writeHead(400, { 'Content-Type': 'application/json' });
531
- res.end(JSON.stringify({
532
- error: 'access_denied',
533
- error_description: 'User denied the authorization request',
534
- }));
535
- });
536
- // Should throw with the specific access_denied error
537
- await expect(deviceFlow.pollForToken('test_device')).rejects.toThrow('access_denied');
538
- });
539
- /**
540
- * @requirement REQ-002.1
541
- * @scenario Handle expired device code
542
- * @given Device code expired (15 min)
543
- * @when polling continues
544
- * @then Returns expiration error
545
- */
546
- it('should handle expired device code', async () => {
547
- testServer.removeAllListeners('request');
548
- testServer.on('request', (req, res) => {
549
- res.writeHead(400, { 'Content-Type': 'application/json' });
550
- res.end(JSON.stringify({
551
- error: 'expired_token',
552
- error_description: 'Device code has expired',
553
- }));
554
- });
555
- // Should throw with the specific expired_token error
556
- await expect(deviceFlow.pollForToken('expired_device_code')).rejects.toThrow('expired_token');
557
- });
558
- /**
559
- * @requirement REQ-002.1
560
- * @scenario Network failure handling
561
- * @given Network request fails
562
- * @when polling or refreshing
563
- * @then Retries with exponential backoff
564
- */
565
- it('should handle network failures with retry logic', { timeout: 20000 }, async () => {
566
- let requestCount = 0;
567
- testServer.removeAllListeners('request');
568
- testServer.on('request', (req, res) => {
569
- requestCount++;
570
- if (requestCount <= 2) {
571
- // First two requests fail
572
- res.destroy();
573
- }
574
- else {
575
- // Third request succeeds
576
- res.writeHead(200, { 'Content-Type': 'application/json' });
577
- res.end(JSON.stringify({
578
- access_token: 'recovered_token',
579
- token_type: 'Bearer',
580
- expires_in: 3600,
581
- }));
582
- }
583
- });
584
- // The implementation will retry and eventually get the token on the third attempt
585
- const result = await deviceFlow.pollForToken('network_test_device');
586
- expect(result.access_token).toBe('recovered_token');
587
- });
588
- /**
589
- * @requirement REQ-002.1
590
- * @scenario Handle malformed JSON response
591
- * @given Server returns invalid JSON
592
- * @when parsing response
593
- * @then Throws appropriate error
594
- */
595
- it('should handle malformed JSON responses', async () => {
596
- testServer.removeAllListeners('request');
597
- testServer.on('request', (req, res) => {
598
- res.writeHead(200, { 'Content-Type': 'application/json' });
599
- res.end('{ invalid json }');
600
- });
601
- // Should throw a JSON parsing error
602
- await expect(deviceFlow.initiateDeviceFlow()).rejects.toThrow();
603
- });
604
- /**
605
- * @requirement REQ-002.1
606
- * @scenario Handle HTTP error status codes
607
- * @given Server returns 500 error
608
- * @when making request
609
- * @then Throws appropriate error
610
- */
611
- it('should handle HTTP error status codes', async () => {
612
- testServer.removeAllListeners('request');
613
- testServer.on('request', (req, res) => {
614
- res.writeHead(500, { 'Content-Type': 'application/json' });
615
- res.end(JSON.stringify({
616
- error: 'internal_server_error',
617
- error_description: 'Server error occurred',
618
- }));
619
- });
620
- // Should throw HTTP 500 error
621
- await expect(deviceFlow.initiateDeviceFlow()).rejects.toThrow('HTTP 500: Internal Server Error');
622
- });
623
- });
624
- describe('Security Validation', () => {
625
- /**
626
- * @requirement REQ-002.2
627
- * @scenario PKCE verifier entropy validation
628
- * @given Multiple PKCE verifiers generated
629
- * @when analyzing randomness
630
- * @then Verifiers have sufficient entropy
631
- */
632
- it('should generate PKCE verifiers with sufficient entropy', () => {
633
- const verifiers = new Set();
634
- // Generate 100 verifiers to test uniqueness
635
- for (let i = 0; i < 100; i++) {
636
- const verifier = randomBytes(32).toString('base64url');
637
- verifiers.add(verifier);
638
- }
639
- // All verifiers should be unique (high entropy)
640
- expect(verifiers.size).toBe(100);
641
- // Each verifier should be 43 characters (32 bytes base64url)
642
- verifiers.forEach((verifier) => {
643
- expect(verifier).toHaveLength(43);
644
- expect(verifier).toMatch(/^[A-Za-z0-9_-]+$/); // base64url alphabet
645
- });
646
- });
647
- /**
648
- * @requirement REQ-002.2
649
- * @scenario PKCE challenge verification
650
- * @given Verifier and challenge pair
651
- * @when verifying PKCE
652
- * @then Challenge correctly matches verifier
653
- */
654
- it('should generate verifiable PKCE challenge-verifier pairs', () => {
655
- const verifier = randomBytes(32).toString('base64url');
656
- const challenge = createHash('sha256')
657
- .update(verifier)
658
- .digest('base64url');
659
- // Verification: regenerating challenge from verifier should match
660
- const verificationChallenge = createHash('sha256')
661
- .update(verifier)
662
- .digest('base64url');
663
- expect(challenge).toBe(verificationChallenge);
664
- // Different verifiers should produce different challenges
665
- const anotherVerifier = randomBytes(32).toString('base64url');
666
- const anotherChallenge = createHash('sha256')
667
- .update(anotherVerifier)
668
- .digest('base64url');
669
- expect(challenge).not.toBe(anotherChallenge);
670
- });
671
- /**
672
- * @requirement REQ-002.1
673
- * @scenario Request parameter validation
674
- * @given Device flow request
675
- * @when sending to authorization server
676
- * @then All required parameters are present
677
- */
678
- it('should include all required OAuth parameters in requests', async () => {
679
- const requiredDeviceParams = [
680
- 'client_id',
681
- 'scope',
682
- 'code_challenge',
683
- 'code_challenge_method',
684
- ];
685
- const requiredTokenParams = [
686
- 'grant_type',
687
- 'device_code',
688
- 'client_id',
689
- 'code_verifier',
690
- ];
691
- testServer.removeAllListeners('request');
692
- testServer.on('request', (req, res) => {
693
- let body = '';
694
- req.on('data', (chunk) => {
695
- body += chunk;
696
- });
697
- req.on('end', () => {
698
- const params = new URLSearchParams(body);
699
- if (req.url?.includes('device/code')) {
700
- requiredDeviceParams.forEach((param) => {
701
- expect(params.has(param)).toBe(true);
702
- });
703
- }
704
- else if (req.url?.includes('token')) {
705
- requiredTokenParams.forEach((param) => {
706
- expect(params.has(param)).toBe(true);
707
- });
708
- }
709
- res.writeHead(200, { 'Content-Type': 'application/json' });
710
- res.end(JSON.stringify({
711
- device_code: 'test',
712
- user_code: 'TEST',
713
- verification_uri: 'https://test',
714
- expires_in: 900,
715
- interval: 5,
716
- }));
717
- });
718
- });
719
- const result = await deviceFlow.initiateDeviceFlow();
720
- expect(result).toMatchObject({
721
- device_code: 'test',
722
- user_code: 'TEST',
723
- verification_uri: 'https://test',
724
- expires_in: 900,
725
- interval: 5,
726
- });
727
- });
728
- });
729
- describe('Configuration Validation', () => {
730
- /**
731
- * @requirement REQ-002.4
732
- * @scenario Validate client ID format
733
- * @given Device flow configuration
734
- * @when initializing with client ID
735
- * @then Client ID matches expected format
736
- */
737
- it('should validate Qwen client ID format', () => {
738
- const validClientId = 'f0304373b74a44d2b584a3fb70ca9e56';
739
- expect(validClientId).toHaveLength(32); // 32 character hex string
740
- expect(validClientId).toMatch(/^[a-f0-9]+$/); // Lowercase hex characters only
741
- const configWithValidClient = {
742
- clientId: validClientId,
743
- authorizationEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
744
- tokenEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/token',
745
- scopes: ['read'],
746
- };
747
- expect(() => new QwenDeviceFlow(configWithValidClient)).not.toThrow();
748
- });
749
- /**
750
- * @requirement REQ-002.3
751
- * @scenario Validate endpoint URLs
752
- * @given Device flow configuration
753
- * @when initializing with endpoints
754
- * @then URLs are valid and use HTTPS
755
- */
756
- it('should validate Qwen endpoint URLs', () => {
757
- const validConfig = {
758
- clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
759
- authorizationEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
760
- tokenEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/token',
761
- scopes: ['read', 'write'],
762
- };
763
- expect(validConfig.authorizationEndpoint.startsWith('https://')).toBe(true);
764
- expect(validConfig.tokenEndpoint.startsWith('https://')).toBe(true);
765
- expect(validConfig.authorizationEndpoint).toContain('chat.qwen.ai');
766
- expect(validConfig.tokenEndpoint).toContain('chat.qwen.ai');
767
- expect(() => new QwenDeviceFlow(validConfig)).not.toThrow();
768
- });
769
- /**
770
- * @requirement REQ-002.1
771
- * @scenario Validate scope configuration
772
- * @given Device flow configuration
773
- * @when initializing with scopes
774
- * @then Scopes are properly formatted for request
775
- */
776
- it('should validate and format scope configuration', () => {
777
- const configWithScopes = {
778
- clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
779
- authorizationEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
780
- tokenEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/token',
781
- scopes: ['read', 'write', 'admin'],
782
- };
783
- expect(configWithScopes.scopes).toBeInstanceOf(Array);
784
- expect(configWithScopes.scopes).toContain('read');
785
- expect(configWithScopes.scopes).toContain('write');
786
- // When implemented, scopes should be joined with spaces for OAuth request
787
- const expectedScopeString = 'read write admin';
788
- expect(configWithScopes.scopes.join(' ')).toBe(expectedScopeString);
789
- expect(() => new QwenDeviceFlow(configWithScopes)).not.toThrow();
790
- });
791
- });
792
- });
793
- //# sourceMappingURL=qwen-device-flow.spec.js.map