@cartanova/qgrid-cli 2.10.10 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) 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-BA7uQ-6c.js +31 -0
  204. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  205. package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
  206. package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
  207. package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
  208. package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
  209. package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
  210. package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
  211. package/bundle/web-dist/client/assets/{services.generated-NP-ValHd.js → services.generated-CefiDXEv.js} +5 -5
  212. package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
  213. package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
  214. package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
  215. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  216. package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
  217. package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
  218. package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
  219. package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
  220. package/bundle/web-dist/client/index.html +6 -6
  221. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  222. package/bundle/web-dist/server/assets/{lazyRouteComponent-CgBdabgd.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
  223. package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
  224. package/bundle/web-dist/server/assets/{monit-ZPt66W5M.js → monit-B2hqorPe.js} +385 -126
  225. package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
  226. package/bundle/web-dist/server/assets/{react-dom-Ds75e4Jl.js → react-dom-BIYQzBqG.js} +2 -129
  227. package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
  228. package/bundle/web-dist/server/assets/{request-model-DjGldb-h.js → request-model-I6OdODSH.js} +15 -6
  229. package/bundle/web-dist/server/assets/{routes-Ct-k7nBA.js → routes-B95YlUv2.js} +760 -213
  230. package/bundle/web-dist/server/assets/{services.generated-BA4AcAf5.js → services.generated-DQATJ6qf.js} +12820 -12194
  231. package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
  232. package/bundle/web-dist/server/assets/{show-LSFIzvO2.js → show-Bxaj3rhH.js} +1350 -418
  233. package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
  234. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  235. package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
  236. package/bundle/web-dist/server/assets/{use-update-token-mutation-pkArIzCP.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
  237. package/bundle/web-dist/server/entry-server.generated.js +4295 -22810
  238. package/dist/cli.js +9 -9
  239. package/package.json +4 -11
  240. package/postinstall.mjs +12 -0
  241. package/skills/qgrid/SKILL.md +1 -0
  242. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  243. package/skills/qgrid/references/decision-rationale.md +23 -0
  244. package/skills/qgrid/references/grok-runtime.md +89 -0
  245. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  246. package/skills/qgrid/references/repo-map.md +10 -0
  247. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  248. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  249. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  250. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  251. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  252. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  253. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  254. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  255. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  256. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  257. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  258. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  259. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  260. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  262. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  263. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  264. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  265. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  266. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  267. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  268. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  269. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  270. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  271. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  272. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  273. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  274. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  275. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  276. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  277. 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
  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/_commonjsHelpers.D26ty3Ew.js +0 -9
  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/benchmark.CX_oY03V.js +0 -41
  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/evaluatedModules.Dg1zASAC.js +0 -19
  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/index.Chj8NDwU.js +0 -202
  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/chunks/index.DdgEv5B1.js +0 -46
  283. 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
  284. 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
  285. 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
  286. 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
  287. package/bundle/dist/testing/setup-mocks.js +0 -16
  288. package/bundle/src/testing/setup-mocks.ts +0 -44
  289. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  290. package/bundle/web-dist/client/assets/index-DZwzUfI-.js +0 -106
  291. package/bundle/web-dist/client/assets/logs-Cog79DU5.js +0 -1
  292. package/bundle/web-dist/client/assets/monit-2auznBys.js +0 -1
  293. package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
  294. package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
  295. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
  296. package/bundle/web-dist/client/assets/routes-B0lTeLK-.js +0 -5
  297. package/bundle/web-dist/client/assets/settings-D8ZxZGSJ.js +0 -1
  298. package/bundle/web-dist/client/assets/show-CFSERlnM.js +0 -2
  299. package/bundle/web-dist/client/assets/tokens-CZXUyI7O.js +0 -1
  300. package/bundle/web-dist/client/assets/use-oauth-login-flow-hboOs3wG.js +0 -1
  301. package/bundle/web-dist/client/assets/use-update-token-mutation-BQHS0byG.js +0 -1
  302. package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
  303. package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
  304. package/bundle/web-dist/server/assets/logs-BMyR98rU.js +0 -509
  305. package/bundle/web-dist/server/assets/plus-BZ9I0VgC.js +0 -19
  306. package/bundle/web-dist/server/assets/refresh-cw-CztCFis-.js +0 -23
  307. package/bundle/web-dist/server/assets/settings-CBUZ47Xx.js +0 -461
  308. package/bundle/web-dist/server/assets/tokens-DxrBW512.js +0 -448
  309. package/bundle/web-dist/server/assets/use-oauth-login-flow-Gn8flMK5.js +0 -178
  310. package/dist/cli.d.ts +0 -10
  311. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  312. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  313. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
@@ -11,12 +11,16 @@
11
11
  // claude-api 스킬 확인: Sonnet 4.6 official id = "claude-sonnet-4-6" (날짜 suffix 없음).
12
12
  // model-cost 테이블에도 "claude-sonnet-4-6" 키 존재
13
13
  export const ANTHROPIC_DEFAULT_MODEL = "claude-sonnet-4-6";
14
+
14
15
  // OpenAI provider 기본값(openai-dispatcher DEFAULT_EFFORT)과 맞춘다. 클라가 effort 미지정 시 안전망.
15
16
  export const ANTHROPIC_DEFAULT_EFFORT = "low";
17
+
16
18
  // project scope cwd (settings.json 격리). 토큰별 격리는 CLAUDE_CONFIG_DIR 로 한다.
17
19
  export const ANTHROPIC_CLAUDE_CWD = "/tmp/qgrid-anthropic";
20
+
18
21
  // per-token CLAUDE_CONFIG_DIR 의 베이스. 실제 경로는 `${BASE}/${tokenId}` (R10 격리).
19
22
  export const ANTHROPIC_CONFIG_DIR_BASE = "/tmp/qgrid-anthropic-config";
23
+
20
24
  // CC 가 자동 활성화하는 deferred 도구 — 토큰 최적화 위해 dispatcher 경로에서 차단.
21
25
  export const ANTHROPIC_DISALLOWED_TOOLS = ["Monitor", "PushNotification", "RemoteTrigger"] as const;
22
26
  const ONE_MILLION_SUFFIX_RE = /\[1m\]$/i;
@@ -35,6 +39,7 @@ export function anthropicConfigDir(tokenId: number): string {
35
39
  export function canonicalAnthropicModel(model?: string): string {
36
40
  const raw = model || ANTHROPIC_DEFAULT_MODEL;
37
41
  const withoutProvider = raw.includes("/") ? raw.split("/").pop()! : raw;
42
+
38
43
  return withoutProvider.replace(ONE_MILLION_SUFFIX_RE, "");
39
44
  }
40
45
 
@@ -58,6 +63,7 @@ const ONE_MILLION_CONTEXT_MODELS = new Set([
58
63
  ]);
59
64
 
60
65
  const CLI_ONE_MILLION_SUFFIX_MODELS = new Set(["claude-sonnet-4-6", "claude-opus-4-6"]);
66
+
61
67
  // Preserve these defaults when thinking is omitted. This is not an off-capability list:
62
68
  // explicit false supports Opus 5, and native extra-body delivery supports Haiku 5.5
63
69
  // (disabled) and Sonnet 5.5 (between_tools). See anthropic-thinking.ts.
@@ -84,6 +90,7 @@ for (const model of CLI_ONE_MILLION_SUFFIX_MODELS) {
84
90
  throw new Error(`[invariant] CLI 1M suffix model not in context set: ${model}`);
85
91
  }
86
92
  }
93
+
87
94
  // Fable 계열은 공식 사양상 1M 기본 컨텍스트 + adaptive thinking 필수다. 새 Fable 버전을 계열 Set
88
95
  // 에만 넣고 나머지를 빠뜨리는 실수를 같은 방식으로 모듈 로드 시점에 잡는다.
89
96
  for (const model of FABLE_FAMILY_MODELS) {
@@ -114,6 +121,7 @@ export function isFableFamilyModel(model?: string): boolean {
114
121
  export function assertSupportedOneMillionSuffix(model?: string): void {
115
122
  if (!hasOneMillionSuffix(model)) return;
116
123
  const canonical = canonicalAnthropicModel(model);
124
+
117
125
  if (!supports1MContext(canonical)) {
118
126
  throw new Error(`Unsupported Anthropic 1M model suffix: ${model}`);
119
127
  }
@@ -7,7 +7,7 @@ import { getLogger } from "@logtape/logtape";
7
7
 
8
8
  import { QuotaThresholdExceededError } from "../../../application/qgrid/qgrid.types";
9
9
  import { TokenModel } from "../../../application/token/token.model";
10
- import { type AnthropicCredentials } from "../../../application/token/token.types";
10
+ import { AnthropicCredentials } from "../../../application/token/token.types";
11
11
  import { getExpiresAt, getRefreshToken } from "../common/credentials";
12
12
  import {
13
13
  type GenerateRequest,
@@ -45,10 +45,18 @@ export class AnthropicDispatcher implements ProviderDispatcher {
45
45
  // NOTIFY는 기존 토큰을 재전송하지 않으므로 시작 시 DB에서 읽는다.
46
46
  const tokens = await TokenModel.findActiveByProvider("A", "anthropic");
47
47
  tokens.forEach((t) => {
48
+ const credentials = AnthropicCredentials.safeParse(t.credentials);
49
+
50
+ if (!credentials.success) {
51
+ logger.warn(`skipping token ${t.name}: credentials are not Anthropic OAuth credentials`);
52
+
53
+ return;
54
+ }
55
+
48
56
  this.tokenPool.set(t.id, {
49
57
  id: t.id,
50
58
  name: t.name,
51
- credentials: t.credentials as AnthropicCredentials,
59
+ credentials: credentials.data,
52
60
  quotaThreshold: t.quota_threshold,
53
61
  weight: t.weight,
54
62
  });
@@ -121,13 +129,16 @@ export class AnthropicDispatcher implements ProviderDispatcher {
121
129
  async selectToken(model: string, preferredTokenId?: number): Promise<PooledToken | null> {
122
130
  const preferred =
123
131
  preferredTokenId === undefined ? undefined : this.tokenPool.get(preferredTokenId);
132
+
124
133
  if (preferredTokenId !== undefined && !preferred) {
125
134
  throw new Error(`Preferred anthropic token ${preferredTokenId} is not available`);
126
135
  }
127
136
 
128
137
  const rows = preferred ? [preferred] : [...this.tokenPool.values()];
138
+
129
139
  if (rows.length === 0) return null;
130
140
  const { eligible, overThresholdTokens } = await this.filterEligibleTokens(rows, model);
141
+
131
142
  if (eligible.length === 0) {
132
143
  logger.warn("quota_threshold gate: all_exceeded", {
133
144
  provider: "anthropic",
@@ -136,9 +147,11 @@ export class AnthropicDispatcher implements ProviderDispatcher {
136
147
  overThresholdTokens,
137
148
  reason: "all_exceeded",
138
149
  });
150
+
139
151
  const details = overThresholdTokens
140
152
  .map((token) => `${token.tokenName} (threshold ${token.threshold}%)`)
141
153
  .join(", ");
154
+
142
155
  throw new QuotaThresholdExceededError(
143
156
  details
144
157
  ? `All anthropic tokens exceeded quota threshold: ${details}`
@@ -149,7 +162,9 @@ export class AnthropicDispatcher implements ProviderDispatcher {
149
162
  if (preferred) return preferred;
150
163
 
151
164
  const selectedId = this.weightedSelector.select(new Set(eligible.map((token) => token.id)));
165
+
152
166
  if (selectedId === null) return null;
167
+
153
168
  return this.tokenPool.get(selectedId) ?? null;
154
169
  }
155
170
 
@@ -161,12 +176,15 @@ export class AnthropicDispatcher implements ProviderDispatcher {
161
176
  overThresholdTokens: Array<{ tokenName: string; threshold: number }>;
162
177
  }> {
163
178
  const thresholded = rows.filter((token) => this.hasQuotaThreshold(token));
179
+
164
180
  if (thresholded.length === 0) return { eligible: rows, overThresholdTokens: [] };
165
181
 
166
182
  const eligibleIds = new Set(
167
- rows.filter((token) => !this.hasQuotaThreshold(token)).map((token) => token.id),
183
+ rows.flatMap((token) => (this.hasQuotaThreshold(token) ? [] : [token.id])),
168
184
  );
185
+
169
186
  const overThresholdTokens: Array<{ tokenName: string; threshold: number }> = [];
187
+
170
188
  const checks = await Promise.allSettled(
171
189
  thresholded.map(async (token) => ({
172
190
  token,
@@ -176,11 +194,14 @@ export class AnthropicDispatcher implements ProviderDispatcher {
176
194
 
177
195
  checks.forEach((check, index) => {
178
196
  const token = check.status === "rejected" ? thresholded[index] : check.value.token;
197
+
179
198
  if (!token) return;
199
+
180
200
  const result =
181
201
  check.status === "fulfilled"
182
202
  ? check.value.result
183
203
  : { kind: "lookup_failed" as const, reason: String(check.reason) };
204
+
184
205
  if (result.kind === "lookup_failed") {
185
206
  logger.warn("quota_threshold gate: lookup_fail_open", {
186
207
  tokenId: token.id,
@@ -191,6 +212,7 @@ export class AnthropicDispatcher implements ProviderDispatcher {
191
212
  lookupReason: result.reason,
192
213
  });
193
214
  eligibleIds.add(token.id);
215
+
194
216
  return;
195
217
  }
196
218
 
@@ -205,6 +227,7 @@ export class AnthropicDispatcher implements ProviderDispatcher {
205
227
  reason: "over_threshold",
206
228
  });
207
229
  overThresholdTokens.push({ tokenName: token.name, threshold: token.quotaThreshold });
230
+
208
231
  return;
209
232
  }
210
233
 
@@ -228,7 +251,7 @@ export class AnthropicDispatcher implements ProviderDispatcher {
228
251
  cb.onThreadId?.(result.threadCoord.threadId);
229
252
  cb.onComplete(result);
230
253
  } catch (e) {
231
- cb.onError(e as Error);
254
+ cb.onError(e instanceof Error ? e : new Error(String(e)));
232
255
  }
233
256
  }
234
257
 
@@ -238,10 +261,12 @@ export class AnthropicDispatcher implements ProviderDispatcher {
238
261
  opts?: { includePartialMessages?: boolean },
239
262
  ): Promise<GenerateResult> {
240
263
  this.inFlight++;
264
+
241
265
  try {
242
266
  if (req.imageGeneration) {
243
267
  throw new Error("image generation is not supported on the Anthropic route");
244
268
  }
269
+
245
270
  assertSupportedOneMillionSuffix(req.model);
246
271
  const model = canonicalAnthropicModel(req.model);
247
272
  const thinking = resolveAnthropicThinking(model, req.thinking, req.effort);
@@ -249,11 +274,13 @@ export class AnthropicDispatcher implements ProviderDispatcher {
249
274
  const jsonSchema = serializeAndValidateDispatchSchema(req.outputSchema, "anthropic");
250
275
 
251
276
  const token = await this.selectToken(model, req.preferredTokenId);
277
+
252
278
  if (!token) throw new Error("No anthropic tokens available");
253
279
 
254
280
  // 만료 직전에 갱신하되 실패하면 기존 토큰으로 진행한다.
255
281
  let accessToken = token.credentials.accessToken;
256
282
  const expiresAt = getExpiresAt(token.credentials);
283
+
257
284
  if (
258
285
  expiresAt &&
259
286
  expiresAt - Date.now() < REFRESH_SAFETY_MS &&
@@ -267,13 +294,16 @@ export class AnthropicDispatcher implements ProviderDispatcher {
267
294
  provider: "anthropic",
268
295
  name: token.name,
269
296
  credentials: token.credentials,
270
- } as Parameters<typeof QgridFrame.refreshToken>[0]);
297
+ });
271
298
  } catch (e) {
272
- logger.warn(`refresh failed for ${token.name}: ${(e as Error).message}`);
299
+ logger.warn(
300
+ `refresh failed for ${token.name}: ${e instanceof Error ? e.message : String(e)}`,
301
+ );
273
302
  }
274
303
  }
275
304
 
276
305
  logger.info(`→ ${token.name} (model: ${model})`);
306
+
277
307
  const session = await runClaudeSession(
278
308
  {
279
309
  tokenId: token.id,
@@ -294,20 +324,25 @@ export class AnthropicDispatcher implements ProviderDispatcher {
294
324
 
295
325
  if (session.quotaExhausted) {
296
326
  invalidateAnthropicQuotaUsage(token.credentials.accessToken);
327
+
297
328
  if (accessToken !== token.credentials.accessToken) {
298
329
  invalidateAnthropicQuotaUsage(accessToken);
299
330
  }
331
+
300
332
  throw new Error(`quota exhausted (${token.name})`);
301
333
  }
334
+
302
335
  if (session.isError) {
303
336
  // 종료 사유를 먼저 표시하고 응답 본문은 진단에 필요한 만큼만 남긴다.
304
337
  const reason =
305
338
  session.subtype ?? session.terminalReason ?? (session.isError ? "is_error" : "unknown");
339
+
306
340
  const body = session.text
307
341
  ? session.text.length > 500
308
342
  ? `${session.text.slice(0, 500)}…(${session.text.length} chars)`
309
343
  : session.text
310
344
  : `empty text, outputTokens=${session.usage.outputTokens}`;
345
+
311
346
  const refusal = session.refusal ? ` refusal=${JSON.stringify(session.refusal)}` : "";
312
347
  throw new Error(`claude error (${token.name}) [${reason}]: ${body}${refusal}`);
313
348
  }
@@ -16,19 +16,23 @@ export async function readAnthropicQuotaUsage(
16
16
  ): Promise<AnthropicQuotaUsageResult> {
17
17
  try {
18
18
  const { data, cachedAt } = await fetchUsageWithMeta(accessToken);
19
+
19
20
  if (data.error) return { kind: "lookup_failed", reason: data.error };
20
21
 
21
22
  const utilizations = [data.five_hour?.utilization];
23
+
22
24
  // Fable 계열(5, 5.1)은 5시간 창과 별개로 usage credits 기반 7일 버킷도 소진될 수 있다.
23
25
  if (isFableFamilyModel(model)) {
24
26
  utilizations.push(data.seven_day_overage_included?.utilization);
25
27
  }
28
+
26
29
  const utilization = Math.max(
27
30
  ...utilizations.filter(
28
- (value): value is number => typeof value === "number" && Number.isFinite(value),
31
+ (value): value is number => value !== null && value !== undefined && Number.isFinite(value),
29
32
  ),
30
33
  );
31
- if (typeof utilization !== "number" || !Number.isFinite(utilization)) {
34
+
35
+ if (!Number.isFinite(utilization)) {
32
36
  return { kind: "lookup_failed", reason: "five_hour utilization unavailable" };
33
37
  }
34
38
 
@@ -38,6 +42,6 @@ export async function readAnthropicQuotaUsage(
38
42
  cacheAgeMs: Math.max(Date.now() - cachedAt, 0),
39
43
  };
40
44
  } catch (e) {
41
- return { kind: "lookup_failed", reason: (e as Error).message };
45
+ return { kind: "lookup_failed", reason: e instanceof Error ? e.message : String(e) };
42
46
  }
43
47
  }
@@ -27,6 +27,7 @@ let extraBodyRuntimeSupported: boolean | undefined;
27
27
  /** These modes were verified through native extra-body delivery on Claude Code 2.1.295. */
28
28
  export function assertAnthropicThinkingRuntime(extraBody: string | undefined): void {
29
29
  if (!extraBody) return;
30
+
30
31
  if (extraBodyRuntimeSupported === undefined) {
31
32
  try {
32
33
  const version = execFileSync("claude", ["--version"], {
@@ -35,6 +36,7 @@ export function assertAnthropicThinkingRuntime(extraBody: string | undefined): v
35
36
  stdio: ["ignore", "pipe", "pipe"],
36
37
  env: { PATH: process.env.PATH, TMPDIR: process.env.TMPDIR },
37
38
  }).match(/^(\d+)\.(\d+)\.(\d+)/);
39
+
38
40
  const [major, minor, patch] = version?.slice(1).map(Number) ?? [];
39
41
  extraBodyRuntimeSupported =
40
42
  major !== undefined &&
@@ -45,6 +47,7 @@ export function assertAnthropicThinkingRuntime(extraBody: string | undefined): v
45
47
  extraBodyRuntimeSupported = false;
46
48
  }
47
49
  }
50
+
48
51
  if (!extraBodyRuntimeSupported) {
49
52
  throw new ThinkingValidationError(
50
53
  "thinking:false for Haiku 5.5 and Sonnet 5.5 requires Claude Code 2.1.295 or later; runtime version could not be verified",
@@ -54,14 +57,17 @@ export function assertAnthropicThinkingRuntime(extraBody: string | undefined): v
54
57
 
55
58
  export function resolveAnthropicThinking(model: string, thinking?: boolean, effort?: string) {
56
59
  const canonical = canonicalAnthropicModel(model);
60
+
57
61
  if (thinking === false && !THINKING_OFF_MODELS.has(canonical)) {
58
62
  const reason = usesAdaptiveThinking(canonical)
59
63
  ? "this model requires thinking"
60
64
  : "thinking-off support has not been verified for this model";
65
+
61
66
  throw new ThinkingValidationError(
62
67
  `thinking:false is not supported for anthropic/${canonical}: ${reason}`,
63
68
  );
64
69
  }
70
+
65
71
  return {
66
72
  // Never accept caller-provided extra body data or inherit it from the host environment.
67
73
  extraBody:
@@ -52,13 +52,16 @@ export async function withSessionLock<T>(sessionId: string, fn: () => Promise<T>
52
52
  const prev = sessionChains.get(sessionId) ?? Promise.resolve();
53
53
  // 이전 turn 의 성패와 무관하게 직렬 체인을 잇는다.
54
54
  const next = prev.then(fn, fn);
55
+
55
56
  // tail: 성패 무관 settle 되는 핸들. 이걸 맵에 두고, finally 에서 "여전히 내가 끝"일 때만 삭제.
56
57
  // (set 직후 undefined 검사로 하면 절대 삭제 안 돼 세션 id 가 누수됨 — tail 일치 검사로 회피.)
57
58
  const tail = next.then(
58
59
  () => {},
59
60
  () => {},
60
61
  );
62
+
61
63
  sessionChains.set(sessionId, tail);
64
+
62
65
  try {
63
66
  return await next;
64
67
  } finally {
@@ -127,10 +130,12 @@ export function ensureConfigDir(tokenId: number): string {
127
130
  mkdirSync(dir, { recursive: true });
128
131
  writeFileSync(`${dir}/.claude.json`, "{}");
129
132
  writeFileSync(`${dir}/settings.json`, "{}");
133
+
130
134
  return dir;
131
135
  }
132
136
 
133
137
  let cwdEnsured = false;
138
+
134
139
  function ensureCwd(): void {
135
140
  if (cwdEnsured) return;
136
141
  mkdirSync(`${ANTHROPIC_CLAUDE_CWD}/.claude`, { recursive: true });
@@ -141,6 +146,7 @@ function ensureCwd(): void {
141
146
  // spawn args 구성. 멀티턴/격리/structured 모드 반영.
142
147
  export function applyOneMillionSuffix(model: string, needsSuffix: boolean): string {
143
148
  const base = canonicalAnthropicModel(model);
149
+
144
150
  return needsSuffix ? `${base}[1m]` : base;
145
151
  }
146
152
 
@@ -152,12 +158,18 @@ export function oneMillionEnv(supported: boolean): { CLAUDE_CODE_DISABLE_1M_CONT
152
158
  // `{rejected}{accepted}` 누적이 AI-SDK 의 JSON.parse 를 깨뜨리므로, retry 자체를 막아 그 경로를
153
159
  // 원천 차단한다. `0` 은 CC query loop(`callsThisQuery >= maxRetries`)가 첫 attempt emit 전에
154
160
  // 실패시키므로(`error_max_structured_output_retries`) 외부 값이 1 미만이어도 1 로 클램프한다.
155
- export function structuredOutputRetriesEnv(raw = process.env.MAX_STRUCTURED_OUTPUT_RETRIES): {
161
+ export interface StructuredOutputRetriesEnv {
156
162
  MAX_STRUCTURED_OUTPUT_RETRIES: string;
157
- } {
163
+ }
164
+
165
+ export function structuredOutputRetriesEnv(
166
+ raw = process.env.MAX_STRUCTURED_OUTPUT_RETRIES,
167
+ ): StructuredOutputRetriesEnv {
158
168
  if (!raw) return { MAX_STRUCTURED_OUTPUT_RETRIES: "1" };
159
169
  const parsed = Number.parseInt(raw, 10);
170
+
160
171
  if (!Number.isFinite(parsed)) return { MAX_STRUCTURED_OUTPUT_RETRIES: "1" };
172
+
161
173
  return { MAX_STRUCTURED_OUTPUT_RETRIES: String(Math.max(parsed, 1)) };
162
174
  }
163
175
 
@@ -201,7 +213,9 @@ export function buildClaudeArgs(opts: {
201
213
  }): Array<string> {
202
214
  const thinking = resolveAnthropicThinking(opts.model, opts.thinking, opts.effort);
203
215
  const useStructured = Boolean(opts.jsonSchema && opts.jsonSchema.length > 0);
216
+
204
217
  if (useStructured) assertAnthropicSchemaArgvSize(opts.jsonSchema!);
218
+
205
219
  // --tools "" 로 전체 차단, structured(jsonSchema 있음) 면 StructuredOutput 만 허용.
206
220
  const toolArgs = useStructured
207
221
  ? ["--tools", "", "--allowed-tools", "StructuredOutput"]
@@ -241,7 +255,9 @@ export function buildClaudeArgs(opts: {
241
255
  "--session-id",
242
256
  opts.sessionId,
243
257
  ];
258
+
244
259
  if (useStructured) args.push("--json-schema", opts.jsonSchema!);
260
+
245
261
  return args;
246
262
  }
247
263
 
@@ -274,6 +290,7 @@ export function runClaudeSession(
274
290
  // 실제 파일 쓰기는 abort 체크 이후(Promise 안)로 미뤄, 이미 취소된 요청엔 쓰지 않는다.
275
291
  const system = req.system ?? "";
276
292
  const useSystemPromptFile = Buffer.byteLength(system, "utf8") > SYSTEM_PROMPT_ARGV_MAX_BYTES;
293
+
277
294
  const systemPromptFile = useSystemPromptFile
278
295
  ? `${configDir}/system-prompt-${sessionId}.txt`
279
296
  : undefined;
@@ -294,44 +311,53 @@ export function runClaudeSession(
294
311
  coldHistory: req.coldHistory,
295
312
  input: req.input,
296
313
  });
314
+
297
315
  const stdinPayload = decorateAndSerialize(inputLines, sessionId);
298
316
 
299
317
  return new Promise<ClaudeSessionResult>((resolve, reject) => {
300
318
  if (req.abortSignal?.aborted) {
301
319
  reject(new Error("aborted"));
320
+
302
321
  return;
303
322
  }
304
323
 
305
324
  // 대형 시스템 프롬프트는 spawn 직전에 파일로 기록(argv E2BIG 회피). 종료 시 정리한다.
306
325
  if (systemPromptFile) writeFileSync(systemPromptFile, system);
307
326
 
327
+ const env: NodeJS.ProcessEnv = {
328
+ PATH: process.env.PATH,
329
+ TMPDIR: process.env.TMPDIR,
330
+ CLAUDE_CODE_OAUTH_TOKEN: req.token,
331
+ CLAUDE_CONFIG_DIR: configDir,
332
+ };
333
+
334
+ if (thinking.extraBody) env.CLAUDE_CODE_EXTRA_BODY = thinking.extraBody;
335
+
336
+ env.CLAUDE_CODE_DISABLE_AUTO_MEMORY = "1";
337
+ Object.assign(env, oneMillionEnv(supportsOneMillion));
338
+ env.CLAUDE_CODE_DISABLE_CLAUDE_MDS = "1";
339
+ env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE = "1";
340
+ env.CLAUDE_CODE_DISABLE_BUNDLED_SKILLS = "1";
341
+ env.CLAUDE_CODE_DISABLE_WORKFLOWS = "1";
342
+ env.CLAUDE_CODE_ATTRIBUTION_HEADER = "0";
343
+
344
+ // structured + 스트리밍일 때만 retry 를 고정한다(SON-495). text 모드와 논스트림
345
+ // generate 는 CC 기본 retry 를 그대로 쓴다.
346
+ if (
347
+ shouldPinStructuredRetries({
348
+ useStructured,
349
+ includePartialMessages: req.includePartialMessages,
350
+ })
351
+ ) {
352
+ Object.assign(env, structuredOutputRetriesEnv());
353
+ }
354
+
308
355
  const child = spawn("claude", args, {
309
356
  // stderr 도 캡처: invalid OAuth / 잘못된 플래그 / CLI 검증 실패가
310
357
  // "closed without result" 로 뭉개지지 않게 close/error 에 stderr 를 실어 보낸다.
311
358
  stdio: ["pipe", "pipe", "pipe"],
312
359
  cwd: ANTHROPIC_CLAUDE_CWD,
313
- env: {
314
- PATH: process.env.PATH,
315
- TMPDIR: process.env.TMPDIR,
316
- CLAUDE_CODE_OAUTH_TOKEN: req.token,
317
- CLAUDE_CONFIG_DIR: configDir,
318
- ...(thinking.extraBody ? { CLAUDE_CODE_EXTRA_BODY: thinking.extraBody } : {}),
319
- CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1",
320
- ...oneMillionEnv(supportsOneMillion),
321
- CLAUDE_CODE_DISABLE_CLAUDE_MDS: "1",
322
- CLAUDE_CODE_DISABLE_TERMINAL_TITLE: "1",
323
- CLAUDE_CODE_DISABLE_BUNDLED_SKILLS: "1",
324
- CLAUDE_CODE_DISABLE_WORKFLOWS: "1",
325
- CLAUDE_CODE_ATTRIBUTION_HEADER: "0",
326
- // structured + 스트리밍일 때만 retry 를 고정한다(SON-495). text 모드와 논스트림
327
- // generate 는 CC 기본 retry 를 그대로 쓴다.
328
- ...(shouldPinStructuredRetries({
329
- useStructured,
330
- includePartialMessages: req.includePartialMessages,
331
- })
332
- ? structuredOutputRetriesEnv()
333
- : {}),
334
- },
360
+ env,
335
361
  });
336
362
 
337
363
  let settled = false;
@@ -346,18 +372,22 @@ export function runClaudeSession(
346
372
  stderrBuf = (stderrBuf + d.toString()).slice(-STDERR_CAP);
347
373
  });
348
374
  const stderrSuffix = () => (stderrBuf.trim() ? ` — stderr: ${stderrBuf.trim()}` : "");
375
+
349
376
  // spawn 시 쓴 임시 시스템 프롬프트 파일 정리(한 번만). 모든 종료 경로에서 호출한다.
350
377
  // 누락돼도 다음 ensureConfigDir 가 디렉토리를 재사용할 뿐이지만, sessionId 별 파일이라
351
378
  // 쌓이면 디스크가 차므로 settle 시 즉시 지운다.
352
379
  const cleanupSpawnFiles = () => {
353
380
  if (!systemPromptFile) return;
381
+
354
382
  try {
355
383
  unlinkSync(systemPromptFile);
356
384
  } catch {
357
385
  // 이미 없거나 권한 문제면 무시 — 정리는 best-effort.
358
386
  }
359
387
  };
388
+
360
389
  let cleanupAbort: (() => void) | undefined;
390
+
361
391
  const timer = setTimeout(() => {
362
392
  if (settled) return;
363
393
  settled = true;
@@ -385,6 +415,7 @@ export function runClaudeSession(
385
415
  child.kill();
386
416
  reject(new Error("aborted"));
387
417
  };
418
+
388
419
  cleanupAbort = () => req.abortSignal?.removeEventListener("abort", onAbort);
389
420
  req.abortSignal?.addEventListener("abort", onAbort, { once: true });
390
421
 
@@ -393,13 +424,16 @@ export function runClaudeSession(
393
424
  buffer += d.toString();
394
425
  const lines = buffer.split("\n");
395
426
  buffer = lines.pop() ?? "";
427
+
396
428
  for (const line of lines) {
397
429
  const result = handleStreamJsonLine(line, onTrackedDelta, {
398
430
  structuredOutput: useStructured,
399
431
  state: streamState,
400
432
  });
433
+
401
434
  if (result) {
402
435
  finish(result);
436
+
403
437
  return;
404
438
  }
405
439
  }
@@ -47,18 +47,22 @@ export function createFenceStripTransform(): FenceStripTransform {
47
47
  return {
48
48
  push(delta: string): string {
49
49
  full += delta;
50
+
50
51
  if (bodyStart < 0) {
51
52
  bodyStart = resolveLeadingOffset(full);
53
+
52
54
  if (bodyStart < 0) return "";
53
55
  }
54
56
 
55
57
  const body = full.slice(bodyStart);
56
58
  const unemitted = body.slice(emitted);
57
59
  const safe = unemitted.length - trailingHoldLength(unemitted);
60
+
58
61
  if (safe <= 0) return "";
59
62
 
60
63
  const out = unemitted.slice(0, safe);
61
64
  emitted += safe;
65
+
62
66
  return out;
63
67
  },
64
68
 
@@ -76,19 +80,25 @@ export function createFenceStripTransform(): FenceStripTransform {
76
80
  */
77
81
  function resolveLeadingOffset(text: string): number {
78
82
  const trimmedStart = text.trimStart();
83
+
79
84
  if (trimmedStart === "") return -1; // 아직 공백뿐 — flush 가 정리한다
80
85
  const ws = text.length - trimmedStart.length;
81
86
 
82
87
  if (!trimmedStart.startsWith("`")) return ws;
88
+
83
89
  if (/^`{1,2}$/.test(trimmedStart)) return -1; // "```" 로 자랄 수 있음
84
90
 
85
91
  const fence = /^```(?:json)?/i.exec(trimmedStart);
92
+
86
93
  if (!fence) return ws; // "`x", "``x" — 펜스가 아니라 본문
94
+
87
95
  if (/^```(?:j|js|jso)$/i.test(trimmedStart)) return -1; // "json" 태그가 자라는 중
88
96
 
89
97
  const afterFence = trimmedStart.slice(fence[0].length);
90
98
  const afterFenceBody = afterFence.trimStart();
99
+
91
100
  if (afterFenceBody === "") return -1; // 펜스 뒤 공백만 — 본문 첫 글자 대기
101
+
92
102
  return ws + fence[0].length + (afterFence.length - afterFenceBody.length);
93
103
  }
94
104
 
@@ -101,5 +111,6 @@ function resolveLeadingOffset(text: string): number {
101
111
  */
102
112
  function trailingHoldLength(unemitted: string): number {
103
113
  const match = /(?:\n?`{1,3})?[\s]*$/.exec(unemitted);
114
+
104
115
  return match ? match[0].length : 0;
105
116
  }