@cartanova/qgrid-cli 2.10.10 → 2.11.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 (302) hide show
  1. package/bundle/dist/_virtual/_rolldown/runtime.js +1 -10
  2. package/bundle/dist/application/monit/log-buffer.js +12 -6
  3. package/bundle/dist/application/monit/monit.frame.js +11 -3
  4. package/bundle/dist/application/monit/monit.types.js +1 -1
  5. package/bundle/dist/application/qgrid/conv-routing.js +9 -6
  6. package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
  7. package/bundle/dist/application/qgrid/oauth.js +31 -4
  8. package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
  9. package/bundle/dist/application/qgrid/qgrid-response-format.js +21 -19
  10. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +40 -33
  11. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
  12. package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
  13. package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
  14. package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
  15. package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
  16. package/bundle/dist/application/qgrid/token-death.js +1 -1
  17. package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
  18. package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
  19. package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
  20. package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
  21. package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
  22. package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
  23. package/bundle/dist/application/request-log/request-log.model.js +83 -70
  24. package/bundle/dist/application/request-log/request-log.types.js +1 -1
  25. package/bundle/dist/application/request-log/zod-code-format.js +1 -1
  26. package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
  27. package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
  28. package/bundle/dist/application/setting/setting.constant.js +1 -1
  29. package/bundle/dist/application/setting/setting.model.js +2 -2
  30. package/bundle/dist/application/setting/setting.store.js +2 -2
  31. package/bundle/dist/application/setting/setting.types.js +1 -1
  32. package/bundle/dist/application/sonamu.generated.js +32 -16
  33. package/bundle/dist/application/sonamu.generated.sso.js +1 -1
  34. package/bundle/dist/application/token/token.model.js +26 -9
  35. package/bundle/dist/application/token/token.types.js +20 -3
  36. package/bundle/dist/i18n/en.js +15 -1
  37. package/bundle/dist/i18n/ko.js +15 -1
  38. package/bundle/dist/i18n/sd.generated.js +1 -1
  39. package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
  40. package/bundle/dist/server-bootstrap.js +4 -2
  41. package/bundle/dist/server-error-handler.js +1 -1
  42. package/bundle/dist/sonamu.config.js +37 -8
  43. package/bundle/dist/startup-migrations.js +17 -7
  44. package/bundle/dist/testing/global.js +1 -1
  45. package/bundle/dist/testing/schema-bench.js +0 -0
  46. package/bundle/dist/testing/test-database-name.js +1 -1
  47. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  48. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
  49. package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
  50. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  51. package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
  52. package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
  53. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
  54. package/bundle/dist/utils/providers/common/credentials.js +5 -1
  55. package/bundle/dist/utils/providers/common/effort.js +3 -3
  56. package/bundle/dist/utils/providers/common/model-cost.js +69 -14
  57. package/bundle/dist/utils/providers/common/provider-types.js +29 -1
  58. package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
  59. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
  60. package/bundle/dist/utils/providers/common/strictifier.js +62 -43
  61. package/bundle/dist/utils/providers/common/thinking.js +3 -2
  62. package/bundle/dist/utils/providers/common/ttft.js +1 -1
  63. package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
  64. package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
  65. package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
  66. package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
  67. package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
  68. package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
  69. package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
  70. package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
  71. package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
  72. package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
  73. package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
  74. package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
  75. package/bundle/dist/utils/providers/grok/index.js +11 -0
  76. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
  77. package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
  78. package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
  79. package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
  80. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
  81. package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
  82. package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
  83. package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
  84. package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
  85. package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
  86. package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
  87. package/bundle/dist/utils/quiet-hours.js +1 -1
  88. package/bundle/dist/utils/slack-notify.js +14 -8
  89. package/bundle/dist/utils/subset-loaders.js +4 -5
  90. package/bundle/src/application/monit/log-buffer.ts +23 -9
  91. package/bundle/src/application/monit/monit.frame.ts +22 -5
  92. package/bundle/src/application/monit/monit.types.ts +6 -0
  93. package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
  94. package/bundle/src/application/qgrid/conv-routing.ts +35 -9
  95. package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
  96. package/bundle/src/application/qgrid/oauth.ts +51 -15
  97. package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
  98. package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
  99. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +19 -0
  100. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +84 -40
  101. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
  102. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
  103. package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
  104. package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
  105. package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
  106. package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
  107. package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
  108. package/bundle/src/application/qgrid/token-death.ts +4 -0
  109. package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
  110. package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
  111. package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
  112. package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
  113. package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
  114. package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
  115. package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
  116. package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
  117. package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
  118. package/bundle/src/application/request-log/request-log.model.ts +277 -146
  119. package/bundle/src/application/request-log/request-log.types.ts +6 -0
  120. package/bundle/src/application/request-log/zod-code-format.ts +11 -0
  121. package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
  122. package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
  123. package/bundle/src/application/setting/setting.constant.ts +9 -0
  124. package/bundle/src/application/setting/setting.model.ts +12 -2
  125. package/bundle/src/application/setting/setting.store.ts +5 -1
  126. package/bundle/src/application/setting/setting.types.ts +8 -0
  127. package/bundle/src/application/sonamu.generated.http +133 -0
  128. package/bundle/src/application/sonamu.generated.sso.ts +2 -0
  129. package/bundle/src/application/sonamu.generated.ts +15 -0
  130. package/bundle/src/application/token/token.identity.test.ts +20 -0
  131. package/bundle/src/application/token/token.model.ts +66 -7
  132. package/bundle/src/application/token/token.types.ts +24 -1
  133. package/bundle/src/i18n/en.ts +19 -0
  134. package/bundle/src/i18n/ko.ts +21 -0
  135. package/bundle/src/i18n/sd.generated.ts +23 -2
  136. package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
  137. package/bundle/src/server-bootstrap.ts +4 -2
  138. package/bundle/src/server-error-handler.ts +1 -0
  139. package/bundle/src/sonamu.config.ts +69 -7
  140. package/bundle/src/startup-migrations.ts +27 -9
  141. package/bundle/src/testing/global.ts +20 -0
  142. package/bundle/src/testing/schema-bench.ts +105 -30
  143. package/bundle/src/testing/test-database-name.ts +2 -0
  144. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
  145. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
  146. package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
  147. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
  148. package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
  149. package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
  150. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
  151. package/bundle/src/utils/providers/common/credentials.ts +8 -0
  152. package/bundle/src/utils/providers/common/effort.ts +9 -2
  153. package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
  154. package/bundle/src/utils/providers/common/model-cost.ts +259 -158
  155. package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
  156. package/bundle/src/utils/providers/common/provider-types.ts +46 -3
  157. package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
  158. package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
  159. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
  160. package/bundle/src/utils/providers/common/strictifier.ts +185 -59
  161. package/bundle/src/utils/providers/common/thinking.ts +2 -2
  162. package/bundle/src/utils/providers/common/ttft.ts +4 -2
  163. package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
  164. package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
  165. package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
  166. package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
  167. package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
  168. package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
  169. package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
  170. package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
  171. package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
  172. package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
  173. package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
  174. package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
  175. package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
  176. package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
  177. package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
  178. package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
  179. package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
  180. package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
  181. package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
  182. package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
  183. package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
  184. package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
  185. package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
  186. package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
  187. package/bundle/src/utils/providers/grok/index.ts +20 -0
  188. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
  189. package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
  190. package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
  191. package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
  192. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
  193. package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
  194. package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
  195. package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
  196. package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
  197. package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
  198. package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
  199. package/bundle/src/utils/quiet-hours.ts +12 -1
  200. package/bundle/src/utils/slack-notify.ts +44 -13
  201. package/bundle/src/utils/subset-loaders.ts +7 -7
  202. package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
  203. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  204. package/bundle/web-dist/client/assets/index-C96h3feE.js +32 -0
  205. package/bundle/web-dist/client/assets/logs-DBM6U0QD.js +1 -0
  206. package/bundle/web-dist/client/assets/monit-BBjXa7vB.js +1 -0
  207. package/bundle/web-dist/client/assets/routes-Crz_PQzi.js +5 -0
  208. package/bundle/web-dist/client/assets/{services.generated-NP-ValHd.js → services.generated-B5lc3aIC.js} +5 -5
  209. package/bundle/web-dist/client/assets/settings-Cdwm3OBB.js +1 -0
  210. package/bundle/web-dist/client/assets/show-DBUhALT1.js +2 -0
  211. package/bundle/web-dist/client/assets/tokens-CVQAVJTo.js +1 -0
  212. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  213. package/bundle/web-dist/client/assets/use-oauth-login-flow-BfxYI4Oh.js +1 -0
  214. package/bundle/web-dist/client/assets/use-update-token-mutation-qKBC2sn7.js +1 -0
  215. package/bundle/web-dist/client/assets/{vendor-tanstack-DJRQAbrY.js → vendor-tanstack-DRPs09ai.js} +1 -1
  216. package/bundle/web-dist/client/index.html +5 -5
  217. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  218. package/bundle/web-dist/server/assets/{lazyRouteComponent-CgBdabgd.js → lazyRouteComponent-AKiHfZWp.js} +129 -2
  219. package/bundle/web-dist/server/assets/{logs-BMyR98rU.js → logs-B7QmGJq3.js} +18 -14
  220. package/bundle/web-dist/server/assets/{monit-ZPt66W5M.js → monit-DFt7x3bh.js} +13 -12
  221. package/bundle/web-dist/server/assets/{plus-BZ9I0VgC.js → plus-DaYQRpBt.js} +1 -1
  222. package/bundle/web-dist/server/assets/{react-dom-Ds75e4Jl.js → react-dom-Cv23mm1K.js} +2 -129
  223. package/bundle/web-dist/server/assets/{refresh-cw-CztCFis-.js → refresh-cw-BpXNsAy-.js} +1 -1
  224. package/bundle/web-dist/server/assets/{request-model-DjGldb-h.js → request-model-eHE6YbaF.js} +1 -1
  225. package/bundle/web-dist/server/assets/{routes-Ct-k7nBA.js → routes-_Y-PJfgO.js} +110 -39
  226. package/bundle/web-dist/server/assets/{services.generated-BA4AcAf5.js → services.generated-CMJ8AHbO.js} +582 -172
  227. package/bundle/web-dist/server/assets/{settings-CBUZ47Xx.js → settings-JwJKxn2e.js} +14 -14
  228. package/bundle/web-dist/server/assets/{show-LSFIzvO2.js → show-BEv6z1v_.js} +90 -60
  229. package/bundle/web-dist/server/assets/{tokens-DxrBW512.js → tokens-CNT4mI-f.js} +162 -50
  230. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  231. package/bundle/web-dist/server/assets/use-oauth-login-flow-jkAkT3X6.js +2345 -0
  232. package/bundle/web-dist/server/assets/{use-update-token-mutation-pkArIzCP.js → use-update-token-mutation-Sm6kh02m.js} +1 -1
  233. package/bundle/web-dist/server/entry-server.generated.js +1644 -21655
  234. package/dist/cli.js +9 -9
  235. package/package.json +4 -11
  236. package/postinstall.mjs +12 -0
  237. package/skills/qgrid/SKILL.md +1 -0
  238. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  239. package/skills/qgrid/references/decision-rationale.md +23 -0
  240. package/skills/qgrid/references/grok-runtime.md +89 -0
  241. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  242. package/skills/qgrid/references/repo-map.md +10 -0
  243. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  244. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  245. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  246. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  247. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  248. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  249. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  250. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  251. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  252. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  253. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  254. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  255. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  256. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  257. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  258. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  259. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  260. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  262. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  263. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  264. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  265. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  266. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  267. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  268. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  269. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  270. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  271. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  272. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  273. package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
  274. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
  275. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
  276. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
  277. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
  278. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
  279. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
  280. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
  281. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
  282. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
  283. package/bundle/dist/testing/setup-mocks.js +0 -16
  284. package/bundle/src/testing/setup-mocks.ts +0 -44
  285. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  286. package/bundle/web-dist/client/assets/index-DZwzUfI-.js +0 -106
  287. package/bundle/web-dist/client/assets/logs-Cog79DU5.js +0 -1
  288. package/bundle/web-dist/client/assets/monit-2auznBys.js +0 -1
  289. package/bundle/web-dist/client/assets/routes-B0lTeLK-.js +0 -5
  290. package/bundle/web-dist/client/assets/settings-D8ZxZGSJ.js +0 -1
  291. package/bundle/web-dist/client/assets/show-CFSERlnM.js +0 -2
  292. package/bundle/web-dist/client/assets/tokens-CZXUyI7O.js +0 -1
  293. package/bundle/web-dist/client/assets/use-oauth-login-flow-hboOs3wG.js +0 -1
  294. package/bundle/web-dist/client/assets/use-update-token-mutation-BQHS0byG.js +0 -1
  295. package/bundle/web-dist/server/assets/use-oauth-login-flow-Gn8flMK5.js +0 -178
  296. package/dist/cli.d.ts +0 -10
  297. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  298. /package/bundle/web-dist/client/assets/{plus-B62CuqT8.js → plus-BsQdY7PS.js} +0 -0
  299. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  300. /package/bundle/web-dist/client/assets/{refresh-cw-NNcU0Cmq.js → refresh-cw-D9IUmT23.js} +0 -0
  301. /package/bundle/web-dist/client/assets/{request-model-CojtinqK.js → request-model-Bpp_rkK8.js} +0 -0
  302. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
@@ -0,0 +1,164 @@
1
+ {
2
+ "source": {
3
+ "binary": "grok-build 1.0.60",
4
+ "buildId": "01a8e1c591c0",
5
+ "capturedAt": "2026-10-16T08:08:47Z",
6
+ "tool": "Proxyman HAR",
7
+ "note": "system prompt and tool list elided; only shapes are pinned"
8
+ },
9
+ "request": {
10
+ "method": "POST",
11
+ "url": "https://cli-chat-proxy.grok.com/v1/responses",
12
+ "headerOrder": [
13
+ "content-type",
14
+ "user-agent",
15
+ "x-grok-client-mode",
16
+ "x-xai-token-auth",
17
+ "x-authenticateresponse",
18
+ "x-compactions-remaining",
19
+ "x-compaction-at",
20
+ "x-grok-client-version",
21
+ "x-grok-user-id",
22
+ "x-grok-conv-group-id",
23
+ "x-grok-client-identifier",
24
+ "authorization",
25
+ "traceparent",
26
+ "x-grok-conv-id",
27
+ "x-grok-req-id",
28
+ "x-grok-model-override",
29
+ "x-grok-session-id",
30
+ "x-grok-agent-id",
31
+ "x-grok-turn-idx",
32
+ "accept",
33
+ "x-grok-doom-loop-check",
34
+ "x-grok-exact-repetition-check",
35
+ "content-encoding",
36
+ "accept-encoding"
37
+ ],
38
+ "headers": {
39
+ "content-type": "application/json",
40
+ "user-agent": "grok-shell/1.0.60 (macos; aarch64)",
41
+ "x-grok-client-mode": "headless",
42
+ "x-xai-token-auth": "xai-grok-cli",
43
+ "x-authenticateresponse": "authenticate-response",
44
+ "x-compactions-remaining": "1",
45
+ "x-compaction-at": "204800",
46
+ "x-grok-client-version": "1.0.60",
47
+ "x-grok-user-id": "<user-id>",
48
+ "x-grok-conv-group-id": "<conv-group-id>",
49
+ "x-grok-client-identifier": "grok-shell",
50
+ "authorization": "Bearer <redacted>",
51
+ "traceparent": "<traceparent>",
52
+ "x-grok-conv-id": "<conv-id>",
53
+ "x-grok-req-id": "<req-id>",
54
+ "x-grok-model-override": "grok-4.7",
55
+ "x-grok-session-id": "<session-id>",
56
+ "x-grok-agent-id": "<agent-id>",
57
+ "x-grok-turn-idx": "1",
58
+ "accept": "text/event-stream",
59
+ "x-grok-doom-loop-check": "1024",
60
+ "x-grok-exact-repetition-check": "64",
61
+ "content-encoding": "zstd",
62
+ "accept-encoding": "gzip, br, deflate"
63
+ },
64
+ "bodyKeys": [
65
+ "include",
66
+ "input",
67
+ "model",
68
+ "prompt_cache_key",
69
+ "reasoning",
70
+ "store",
71
+ "stream",
72
+ "tools"
73
+ ],
74
+ "body": {
75
+ "include": ["reasoning.encrypted_content", "no_inline_citations"],
76
+ "model": "grok-4.7",
77
+ "prompt_cache_key": "<conv-id>",
78
+ "reasoning": {
79
+ "effort": "high",
80
+ "summary": "concise"
81
+ },
82
+ "store": false,
83
+ "stream": true,
84
+ "inputShape": [
85
+ {
86
+ "type": "message",
87
+ "role": "system",
88
+ "contentType": "string"
89
+ },
90
+ {
91
+ "type": "message",
92
+ "role": "user",
93
+ "contentType": "string"
94
+ },
95
+ {
96
+ "type": "message",
97
+ "role": "user",
98
+ "contentType": "string"
99
+ },
100
+ {
101
+ "type": "message",
102
+ "role": "user",
103
+ "contentType": "string"
104
+ },
105
+ {
106
+ "type": "message",
107
+ "role": "user",
108
+ "contentType": "string"
109
+ }
110
+ ],
111
+ "toolTypes": ["function", "x_search"],
112
+ "toolCount": 26
113
+ }
114
+ },
115
+ "response": {
116
+ "status": 200,
117
+ "headers": {
118
+ "content-type": "text/event-stream",
119
+ "x-zero-data-retention": "true",
120
+ "x-ratelimit-limit-tokens": "53000000",
121
+ "x-ratelimit-remaining-tokens": "53000000",
122
+ "x-ratelimit-limit-requests": "8300",
123
+ "x-ratelimit-remaining-requests": "8300",
124
+ "x-request-id": "19bfa1b2-a163-9e0c-8de1-832a73e2695e",
125
+ "x-data-retention": "zdr",
126
+ "x-models-etag": "\"4849638883941606653\"",
127
+ "x-grok-context-window": "256000"
128
+ },
129
+ "terminalUsage": {
130
+ "input_tokens": 27150,
131
+ "input_tokens_details": {
132
+ "cached_tokens": 6528
133
+ },
134
+ "output_tokens": 336,
135
+ "output_tokens_details": {
136
+ "reasoning_tokens": 335
137
+ },
138
+ "total_tokens": 27486,
139
+ "num_sources_used": 0,
140
+ "num_server_side_tools_used": 0,
141
+ "cost_in_usd_ticks": 465240000,
142
+ "context_details": {
143
+ "input_tokens": 27150,
144
+ "output_tokens": 344
145
+ }
146
+ },
147
+ "eventTypes": [
148
+ "response.created",
149
+ "response.in_progress",
150
+ "response.output_item.added",
151
+ "response.reasoning_summary_part.added",
152
+ "response.reasoning_summary_text.delta",
153
+ "response.reasoning_summary_text.done",
154
+ "response.reasoning_summary_part.done",
155
+ "response.output_item.done",
156
+ "response.content_part.added",
157
+ "response.output_text.delta",
158
+ "response.output_text.done",
159
+ "response.content_part.done",
160
+ "response.completed"
161
+ ],
162
+ "endsWithDone": false
163
+ }
164
+ }
@@ -0,0 +1,325 @@
1
+ import { zstdDecompressSync } from "node:zlib";
2
+
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ import golden from "./__fixtures__/golden-responses-1.0.60.json";
6
+ import {
7
+ buildGrokResponsesRequest,
8
+ classifyGrokHttpError,
9
+ encodeGrokRequestBody,
10
+ encodeGrokRequestBodyPlain,
11
+ normalizeGrokEvent,
12
+ normalizeGrokSSE,
13
+ parseGrokSSE,
14
+ readGrokResponseHeaders,
15
+ type GrokNormalizedEvent,
16
+ } from "./grok-backend-protocol";
17
+
18
+ function streamOf(...chunks: string[]): ReadableStream<Uint8Array> {
19
+ const encoder = new TextEncoder();
20
+ return new ReadableStream({
21
+ start(controller) {
22
+ for (const chunk of chunks) controller.enqueue(encoder.encode(chunk));
23
+ controller.close();
24
+ },
25
+ });
26
+ }
27
+
28
+ function sse(type: string, payload: Record<string, unknown> = {}): string {
29
+ return `event: ${type}\ndata: ${JSON.stringify({ type, ...payload })}\n\n`;
30
+ }
31
+
32
+ async function collect(body: ReadableStream<Uint8Array>): Promise<GrokNormalizedEvent[]> {
33
+ const events: GrokNormalizedEvent[] = [];
34
+ for await (const event of normalizeGrokSSE(body)) events.push(event);
35
+ return events;
36
+ }
37
+
38
+ describe("buildGrokResponsesRequest", () => {
39
+ it("emits the captured body keys in fixture order", () => {
40
+ const body = buildGrokResponsesRequest({
41
+ model: "grok-4.7",
42
+ systemPrompt: "system",
43
+ history: [{ type: "message", role: "user", content: "hi" }],
44
+ promptCacheKey: "conv-1",
45
+ effort: "high",
46
+ tools: [{ type: "function", name: "f", parameters: { type: "object" }, strict: true }],
47
+ });
48
+ expect(Object.keys(body)).toEqual(golden.request.bodyKeys);
49
+ expect(body.include).toEqual(golden.request.body.include);
50
+ expect(body.reasoning).toEqual(golden.request.body.reasoning);
51
+ expect(body.store).toBe(golden.request.body.store);
52
+ expect(body.stream).toBe(golden.request.body.stream);
53
+ expect(body.prompt_cache_key).toBe("conv-1");
54
+ expect(body.input[0]).toEqual({ type: "message", role: "system", content: "system" });
55
+ });
56
+
57
+ it("replays full history, appends optional keys in order and never sends server state", () => {
58
+ const body = buildGrokResponsesRequest({
59
+ model: "grok-4.5",
60
+ history: [
61
+ {
62
+ type: "message",
63
+ role: "user",
64
+ content: [
65
+ { type: "input_text", text: "what colour?" },
66
+ { type: "input_image", image_url: "data:image/png;base64,AAAA" },
67
+ ],
68
+ },
69
+ { type: "reasoning", id: "rs_1", encrypted_content: "enc" },
70
+ { type: "reasoning", id: "rs_foreign", summary: [{ type: "summary_text", text: "x" }] },
71
+ { type: "function_call", call_id: "c1", name: "f", arguments: "{}" },
72
+ { type: "function_call_output", call_id: "c1", output: "ok" },
73
+ { type: "message", role: "assistant", content: "Red." },
74
+ ],
75
+ promptCacheKey: "conv-2",
76
+ effort: "xhigh",
77
+ outputSchema: { name: "pong", schema: { type: "object" } },
78
+ tools: [{ type: "web_search" }, { type: "x_search" }],
79
+ toolChoice: "auto",
80
+ maxOutputTokens: 256,
81
+ });
82
+ expect(Object.keys(body)).toEqual([
83
+ "include",
84
+ "input",
85
+ "model",
86
+ "prompt_cache_key",
87
+ "reasoning",
88
+ "store",
89
+ "stream",
90
+ "text",
91
+ "tools",
92
+ "tool_choice",
93
+ "max_output_tokens",
94
+ ]);
95
+ expect(body.input.map((item) => item.type)).toEqual([
96
+ "message",
97
+ "reasoning",
98
+ "function_call",
99
+ "function_call_output",
100
+ "message",
101
+ ]);
102
+ expect(body.input[1]).toEqual({
103
+ type: "reasoning",
104
+ id: "rs_1",
105
+ summary: [],
106
+ encrypted_content: "enc",
107
+ });
108
+ expect(body.text).toEqual({
109
+ format: { type: "json_schema", name: "pong", strict: true, schema: { type: "object" } },
110
+ });
111
+ for (const key of ["instructions", "previous_response_id", "conversation"])
112
+ expect(body).not.toHaveProperty(key);
113
+ });
114
+
115
+ it("rejects invalid options", () => {
116
+ const base = { model: "grok-4.7", history: [], promptCacheKey: "k", effort: "high" } as const;
117
+ expect(() => buildGrokResponsesRequest({ ...base, promptCacheKey: "" })).toThrow(TypeError);
118
+ expect(() => buildGrokResponsesRequest({ ...base, maxOutputTokens: 0 })).toThrow(TypeError);
119
+ });
120
+ });
121
+
122
+ describe("Grok body encoding", () => {
123
+ const body = buildGrokResponsesRequest({
124
+ model: "grok-4.7",
125
+ history: [{ type: "message", role: "user", content: "ping" }],
126
+ promptCacheKey: "k",
127
+ effort: "low",
128
+ });
129
+
130
+ it("zstd-compresses JSON that round-trips", async () => {
131
+ const encoded = await encodeGrokRequestBody(body);
132
+ expect(encoded.contentEncoding).toBe("zstd");
133
+ expect(JSON.parse(zstdDecompressSync(encoded.bytes).toString("utf8"))).toEqual(body);
134
+ });
135
+
136
+ it("has a plain variant", () => {
137
+ const encoded = encodeGrokRequestBodyPlain(body);
138
+ expect(encoded.contentEncoding).toBeUndefined();
139
+ expect(JSON.parse(new TextDecoder().decode(encoded.bytes))).toEqual(body);
140
+ });
141
+ });
142
+
143
+ describe("normalizeGrokEvent / normalizeGrokSSE", () => {
144
+ it("accepts every captured event type and ends at response.completed without [DONE]", async () => {
145
+ expect(golden.response.endsWithDone).toBe(false);
146
+ const chunks = golden.response.eventTypes.map((type) => {
147
+ if (type === "response.created") return sse(type, { response: { id: "resp_1" } });
148
+ if (type.endsWith(".delta")) return sse(type, { item_id: "it", delta: "x" });
149
+ if (type.startsWith("response.output_item."))
150
+ return sse(type, { item: { type: "message", id: "it" } });
151
+ if (type === "response.completed")
152
+ return sse(type, {
153
+ response: { id: "resp_1", model: "grok-4.7", usage: golden.response.terminalUsage },
154
+ });
155
+ return sse(type, { item_id: "it" });
156
+ });
157
+ // Split mid-way through a block and a CRLF to exercise chunk boundaries.
158
+ const joined = chunks.join("").replace("\n\n", "\r\n\r\n");
159
+ const events = await collect(streamOf(joined.slice(0, 37), joined.slice(37, 38), joined.slice(38)));
160
+ expect(events.map((event) => event.type)).toEqual([
161
+ "created",
162
+ "output-item",
163
+ "reasoning-summary-delta",
164
+ "output-item",
165
+ "text-delta",
166
+ "completed",
167
+ ]);
168
+ expect(events.at(-1)).toEqual({
169
+ type: "completed",
170
+ terminal: true,
171
+ responseId: "resp_1",
172
+ model: "grok-4.7",
173
+ usage: {
174
+ inputTokens: 27150,
175
+ cachedInputTokens: 6528,
176
+ outputTokens: 336,
177
+ reasoningTokens: 335,
178
+ totalTokens: 27486,
179
+ numSourcesUsed: 0,
180
+ numServerSideToolsUsed: 0,
181
+ costInUsdTicks: 465240000,
182
+ contextInputTokens: 27150,
183
+ contextOutputTokens: 344,
184
+ },
185
+ });
186
+ });
187
+
188
+ it("treats incomplete and failed as terminal", async () => {
189
+ const incomplete = await collect(
190
+ streamOf(
191
+ sse("response.incomplete", {
192
+ response: { id: "r", incomplete_details: { reason: "max_output_tokens" } },
193
+ }),
194
+ sse("response.output_text.delta", { delta: "ignored after terminal" }),
195
+ ),
196
+ );
197
+ expect(incomplete).toEqual([
198
+ { type: "incomplete", terminal: true, responseId: "r", reason: "max_output_tokens" },
199
+ ]);
200
+ const failed = normalizeGrokEvent({
201
+ data: JSON.stringify({
202
+ type: "response.failed",
203
+ response: { error: { code: "server_error", message: "boom" } },
204
+ }),
205
+ });
206
+ expect(failed).toMatchObject({ type: "error", terminal: true, error: { code: "server_error" } });
207
+ });
208
+
209
+ it("uses the SSE event name when the data has no type and tolerates [DONE]", () => {
210
+ expect(
211
+ normalizeGrokEvent({ event: "response.output_text.delta", data: '{"delta":"hi"}' }),
212
+ ).toEqual({ type: "text-delta", text: "hi" });
213
+ expect(normalizeGrokEvent({ data: "[DONE]" })).toBeUndefined();
214
+ });
215
+
216
+ it("rejects a stream that closes before a terminal event and invalid JSON", async () => {
217
+ await expect(collect(streamOf(sse("response.created", {})))).rejects.toThrow(
218
+ /closed before a terminal event/,
219
+ );
220
+ expect(() => normalizeGrokEvent({ data: "{" })).toThrow(/Invalid Grok SSE JSON/);
221
+ });
222
+
223
+ it("parses event names, comments and a BOM", async () => {
224
+ const blocks = [];
225
+ for await (const block of parseGrokSSE(streamOf("\uFEFF: ping\n\nevent: a\ndata: 1\ndata: 2\n\n")))
226
+ blocks.push(block);
227
+ expect(blocks).toEqual([{ event: "a", data: "1\n2" }]);
228
+ });
229
+ });
230
+
231
+ describe("readGrokResponseHeaders", () => {
232
+ it("reads the captured response headers", () => {
233
+ expect(readGrokResponseHeaders(new Headers(golden.response.headers))).toEqual({
234
+ contextWindow: 256000,
235
+ modelsEtag: '"4849638883941606653"',
236
+ requestId: "19bfa1b2-a163-9e0c-8de1-832a73e2695e",
237
+ rateLimitLimitTokens: 53000000,
238
+ rateLimitRemainingTokens: 53000000,
239
+ rateLimitLimitRequests: 8300,
240
+ rateLimitRemainingRequests: 8300,
241
+ zeroDataRetention: true,
242
+ });
243
+ });
244
+
245
+ it("reads x-zero-data-retention only as an explicit boolean", () => {
246
+ expect(readGrokResponseHeaders({ "X-Zero-Data-Retention": "TRUE" })).toEqual({
247
+ zeroDataRetention: true,
248
+ });
249
+ expect(readGrokResponseHeaders({ "x-zero-data-retention": "false" })).toEqual({
250
+ zeroDataRetention: false,
251
+ });
252
+ expect(readGrokResponseHeaders({ "x-zero-data-retention": "zdr" })).toEqual({});
253
+ expect(readGrokResponseHeaders({})).toEqual({});
254
+ });
255
+ });
256
+
257
+ describe("classifyGrokHttpError", () => {
258
+ it("classifies the U0 426 body as a version gate and parses the minimum version", () => {
259
+ const body = JSON.stringify({
260
+ error:
261
+ "Your Grok CLI version (0.0.1) is outdated. Please update to version 1.0.13 or later to continue.",
262
+ });
263
+ expect(classifyGrokHttpError(426, body, {})).toMatchObject({
264
+ kind: "version_gate",
265
+ status: 426,
266
+ minClientVersion: "1.0.13",
267
+ });
268
+ });
269
+
270
+ it("classifies a 400 invalid_image body", () => {
271
+ const body = JSON.stringify({
272
+ code: "invalid_image",
273
+ error: "Image dimensions must be at least 8 pixels on each side",
274
+ });
275
+ expect(classifyGrokHttpError(400, body, {})).toEqual({
276
+ kind: "invalid_request",
277
+ status: 400,
278
+ code: "invalid_image",
279
+ message: "Image dimensions must be at least 8 pixels on each side",
280
+ });
281
+ });
282
+
283
+ it("separates rate limiting from subscription exhaustion", () => {
284
+ expect(
285
+ classifyGrokHttpError(429, "slow down", new Headers({ "retry-after": "17" })),
286
+ ).toMatchObject({ kind: "rate_limited", retryAfterSec: 17 });
287
+ expect(
288
+ classifyGrokHttpError(
289
+ 429,
290
+ JSON.stringify({ error: "Too many requests: subscription:free-usage-exhausted" }),
291
+ { "Retry-After": "60" },
292
+ ),
293
+ ).toMatchObject({ kind: "quota_exhausted", code: "subscription:free-usage-exhausted" });
294
+ });
295
+
296
+ it("parses an HTTP-date Retry-After", () => {
297
+ const date = new Date(Date.now() + 30_000).toUTCString();
298
+ const result = classifyGrokHttpError(429, "", { "retry-after": date });
299
+ expect(result.retryAfterSec).toBeGreaterThanOrEqual(28);
300
+ expect(result.retryAfterSec).toBeLessThanOrEqual(31);
301
+ });
302
+
303
+ it.each([
304
+ [401, "auth"],
305
+ [403, "entitlement"],
306
+ [422, "invalid_request"],
307
+ [404, "permanent"],
308
+ [408, "transient"],
309
+ [500, "transient"],
310
+ [503, "transient"],
311
+ [0, "transient"],
312
+ ] as const)("maps %i to %s", (status, kind) => {
313
+ expect(classifyGrokHttpError(status, "", {}).kind).toBe(kind);
314
+ });
315
+
316
+ it("exposes x-should-retry overrides", () => {
317
+ expect(classifyGrokHttpError(500, "", { "x-should-retry": "false" }).shouldRetry).toBe(false);
318
+ expect(classifyGrokHttpError(409, "", { "x-should-retry": "true" }).shouldRetry).toBe(true);
319
+ expect(classifyGrokHttpError(500, "", {})).not.toHaveProperty("shouldRetry");
320
+ });
321
+
322
+ it("caps the surfaced message length", () => {
323
+ expect(classifyGrokHttpError(500, "x".repeat(5000), {}).message).toHaveLength(500);
324
+ });
325
+ });