cartethyia 2.7.4 → 2.7.5

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 (553) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
  5. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
  6. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
  10. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
  11. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
  12. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
  14. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
  15. package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
  16. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
  44. package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
  45. package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
  46. package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
  47. package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
  52. package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
  53. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  54. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  55. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  56. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  57. package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
  58. package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
  59. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
  60. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
  61. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
  64. package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
  65. package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
  68. package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
  69. package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
  70. package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
  71. package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
  72. package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
  74. package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
  75. package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
  78. package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
  79. package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
  84. package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
  85. package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
  87. package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
  88. package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
  89. package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
  90. package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
  91. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  92. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  93. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  94. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  95. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  96. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  97. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  98. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  99. package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
  100. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  101. package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
  102. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  103. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  104. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  105. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  106. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  107. package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
  108. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  109. package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
  110. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  111. package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
  112. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  113. package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
  114. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  115. package/dist/dashboard/console-backgrounds.jpg +0 -0
  116. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  117. package/dist/dashboard/index.html +2 -2
  118. package/dist/dashboard/index.html.gz +0 -0
  119. package/dist/dashboard/precompressed-assets.json +56 -55
  120. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  121. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  122. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  123. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  124. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  125. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  126. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  127. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  128. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  129. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  130. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  131. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  132. package/package.json +4 -6
  133. package/scripts/cli/update.ts +15 -41
  134. package/src/boot/app.ts +58 -2
  135. package/src/boot/dependencies.ts +786 -732
  136. package/src/boot/lifecycle.ts +11 -12
  137. package/src/config/cooldowns.ts +34 -55
  138. package/src/config/network.ts +1 -1
  139. package/src/config/package-paths.ts +1 -1
  140. package/src/config/providers.ts +13 -14
  141. package/src/config/resources.ts +0 -5
  142. package/src/config/runtime.ts +2 -5
  143. package/src/config/spec.ts +26 -6
  144. package/src/console/api-keys/ban-constants.ts +38 -0
  145. package/src/console/api-keys/contracts.ts +71 -62
  146. package/src/console/api-keys/routes.ts +48 -12
  147. package/src/console/auth/access.ts +4 -4
  148. package/src/console/auth/account-reset.ts +1 -1
  149. package/src/console/auth/audit-recorder.ts +1 -1
  150. package/src/console/auth/lockout.ts +7 -3
  151. package/src/console/auth/row-coercion.ts +57 -12
  152. package/src/console/auth/session-resolver.ts +1 -1
  153. package/src/console/auth/session-service.ts +8 -2
  154. package/src/console/auth/session.ts +37 -31
  155. package/src/console/auth/setup-service.ts +4 -3
  156. package/src/console/auth/user-store.ts +1 -1
  157. package/src/console/backup/9router-map.ts +0 -3
  158. package/src/console/backup/contracts.ts +9 -9
  159. package/src/console/backup/export-endpoint.ts +5 -6
  160. package/src/console/backup/nine-router.ts +1 -7
  161. package/src/console/backup/routes.ts +29 -33
  162. package/src/console/backup/service.ts +468 -468
  163. package/src/console/backup/store.ts +47 -29
  164. package/src/console/backup/validate.ts +11 -1
  165. package/src/console/cli-tools/contracts.ts +7 -7
  166. package/src/console/cli-tools/injectors/cline.ts +110 -110
  167. package/src/console/cli-tools/injectors/codex.ts +181 -181
  168. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  169. package/src/console/cli-tools/injectors/driver.ts +247 -247
  170. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  171. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  172. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  173. package/src/console/cli-tools/routes.ts +1 -1
  174. package/src/console/cli-tools/service.ts +1 -1
  175. package/src/console/cli-tools/store.ts +2 -2
  176. package/src/console/console-router.ts +32 -0
  177. package/src/console/dashboard-assets.ts +9 -9
  178. package/src/console/domain-registration.ts +16 -2
  179. package/src/console/inferhub/client.ts +0 -7
  180. package/src/console/inferhub/key-store.ts +1 -1
  181. package/src/console/inferhub/normalize.ts +2 -2
  182. package/src/console/inferhub/routes.ts +1 -1
  183. package/src/console/inferhub/types.ts +1 -1
  184. package/src/console/observability/contracts.ts +1 -1
  185. package/src/console/observability/live.ts +31 -18
  186. package/src/console/observability/logs.ts +1 -1
  187. package/src/console/observability/sse.ts +62 -8
  188. package/src/console/observability/store.ts +20 -4
  189. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  190. package/src/console/providers/catalog/contracts.ts +39 -0
  191. package/src/console/providers/catalog/model-operations.ts +1 -1
  192. package/src/console/providers/catalog/provider-operations.ts +95 -17
  193. package/src/console/providers/catalog/public-model-store.ts +0 -0
  194. package/src/console/providers/catalog/routes.ts +27 -3
  195. package/src/console/providers/catalog/store.ts +147 -8
  196. package/src/console/providers/detail/routes.ts +1 -1
  197. package/src/console/providers/oauth/callback-listener.ts +100 -18
  198. package/src/console/providers/oauth/routes.ts +92 -13
  199. package/src/console/quota/account-quota-global.ts +41 -3
  200. package/src/console/quota/account-quota-shared.ts +10 -3
  201. package/src/console/quota/account-quota-tenant.ts +259 -66
  202. package/src/console/quota/daily-growth-job.ts +308 -0
  203. package/src/console/quota/native-identity.ts +2 -2
  204. package/src/console/quota/quota-view.ts +1 -1
  205. package/src/console/remote-support/routes.ts +1 -1
  206. package/src/console/remote-support/service.ts +2 -2
  207. package/src/console/routing/model/contracts.ts +1 -1
  208. package/src/console/routing/pools/contracts.ts +2 -2
  209. package/src/console/routing/pools/import-parse.ts +3 -3
  210. package/src/console/routing/pools/relay-deploy.ts +3 -3
  211. package/src/console/settings/contracts.ts +29 -2
  212. package/src/console/settings/store.ts +20 -0
  213. package/src/console/share/share-router.ts +100 -32
  214. package/src/console/share/share-stats.ts +4 -4
  215. package/src/console/share/share-usage.ts +1 -1
  216. package/src/console/shared/errors.ts +2 -2
  217. package/src/console/shared/object.ts +18 -0
  218. package/src/console/shared/read-through-cache.ts +4 -4
  219. package/src/console/shared/transaction.ts +14 -0
  220. package/src/console/system-prompt/contracts.ts +89 -12
  221. package/src/console/system-prompt/routes.ts +98 -45
  222. package/src/console/updates/apply-update.ts +244 -0
  223. package/src/console/updates/routes.ts +252 -97
  224. package/src/main.ts +11 -5
  225. package/src/network/http2-bidi.ts +1 -1
  226. package/src/network/ip-utils.ts +298 -0
  227. package/src/network/outbound-fetch.ts +1 -1
  228. package/src/network/pool/agent.ts +7 -6
  229. package/src/network/pool/byte-accounting.ts +1 -1
  230. package/src/network/pool/resolver.ts +16 -12
  231. package/src/network/pool/selector.ts +150 -136
  232. package/src/network/pool-health-machine.ts +1 -1
  233. package/src/network/rate-limit-verdict.ts +1 -1
  234. package/src/network/retry.ts +1 -1
  235. package/src/network/ssrf.ts +20 -71
  236. package/src/observability/event-log.ts +2 -2
  237. package/src/observability/event-query.ts +59 -291
  238. package/src/observability/log-sanitize.ts +1 -1
  239. package/src/observability/metrics.ts +4 -4
  240. package/src/observability/payload-capture.ts +6 -5
  241. package/src/observability/payload-store.ts +1 -1
  242. package/src/observability/runtime-metrics.ts +1 -1
  243. package/src/observability/telemetry-buffer.ts +12 -3
  244. package/src/observability/telemetry-reconciliation.ts +3 -3
  245. package/src/observability/token-speed.ts +1 -1
  246. package/src/persistence/connection-url.ts +1 -1
  247. package/src/persistence/db-handle.ts +1 -1
  248. package/src/persistence/db-pg.ts +2 -2
  249. package/src/persistence/db-sqlite.ts +3 -3
  250. package/src/persistence/dialect.ts +5 -1
  251. package/src/persistence/readiness.ts +1 -1
  252. package/src/persistence/redis.ts +1 -1
  253. package/src/persistence/schema.ts +113 -40
  254. package/src/persistence/shared-cache.ts +2 -2
  255. package/src/persistence/sort-order.ts +1 -1
  256. package/src/persistence/stores/api-key-store.ts +10 -1
  257. package/src/persistence/stores/share-store.ts +20 -8
  258. package/src/persistence/system-prompt-store.ts +63 -18
  259. package/src/persistence/tenant-preferences.ts +1 -1
  260. package/src/persistence/ttl-cache.ts +3 -3
  261. package/src/persistence/usage-flush.ts +7 -2
  262. package/src/protocol/canonical-model.ts +1 -1
  263. package/src/protocol/codecs.ts +6 -10
  264. package/src/protocol/dsml.ts +3 -49
  265. package/src/protocol/image-clamp.ts +2 -2
  266. package/src/protocol/reasoning-text.ts +1 -1
  267. package/src/protocol/reasoning.ts +7 -52
  268. package/src/protocol/registry.ts +50 -15
  269. package/src/protocol/request/chat.ts +46 -19
  270. package/src/protocol/request/codex.ts +1 -1
  271. package/src/protocol/request/messages.ts +46 -14
  272. package/src/protocol/request/responses.ts +19 -10
  273. package/src/protocol/response/chat.ts +25 -10
  274. package/src/protocol/response/codex.ts +1 -1
  275. package/src/protocol/response/messages.ts +1 -1
  276. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  277. package/src/protocol/response/responses.ts +1 -1
  278. package/src/protocol/sse-decoder.ts +50 -1
  279. package/src/protocol/stop-reason.ts +2 -2
  280. package/src/protocol/think-split.ts +347 -0
  281. package/src/protocol/translation/attachment-integrity.ts +3 -3
  282. package/src/protocol/translation/cache-controls.ts +8 -20
  283. package/src/protocol/translation/capabilities.ts +6 -6
  284. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  285. package/src/protocol/translation/dialect/inband.ts +39 -0
  286. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  287. package/src/protocol/translation/dialect/qwen.ts +114 -0
  288. package/src/protocol/translation/dialect/resolver.ts +83 -0
  289. package/src/protocol/translation/dialect/rules.ts +93 -0
  290. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  291. package/src/protocol/translation/dialect/types.ts +58 -0
  292. package/src/protocol/translation/quirks.ts +18 -4
  293. package/src/protocol/translation/thinking.ts +12 -252
  294. package/src/protocol/translation/tool-id.ts +3 -3
  295. package/src/protocol/translation/tool-repair.ts +1 -1
  296. package/src/protocol/upstream/post-json.ts +6 -1
  297. package/src/providers/adapters/compatible-adapter.ts +42 -3
  298. package/src/providers/authentication/jwt-validator.ts +0 -5
  299. package/src/providers/authentication/oauth-client.ts +254 -253
  300. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  301. package/src/providers/bundled-discovery-providers.ts +6 -30
  302. package/src/providers/configured-openai-providers.ts +82 -97
  303. package/src/providers/default-registry.ts +23 -35
  304. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  305. package/src/providers/discovery/discovery-types.ts +0 -1
  306. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  307. package/src/providers/discovery/probe-phases.ts +48 -13
  308. package/src/providers/discovery/probing-service.ts +6 -8
  309. package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
  310. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  311. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  312. package/src/providers/integrations/antigravity/antigravity.ts +2 -2
  313. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  314. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  315. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  316. package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
  317. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  318. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  319. package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
  320. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  321. package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
  322. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  323. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  324. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  325. package/src/providers/integrations/cline/cline.ts +1 -1
  326. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  327. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  328. package/src/providers/integrations/commandcode/commandcode.ts +75 -115
  329. package/src/providers/integrations/commandcode/quota.ts +131 -51
  330. package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
  331. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  332. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  333. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  334. package/src/providers/integrations/cursor/cursor.ts +38 -5
  335. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  336. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  337. package/src/providers/integrations/factory/factory.ts +9 -9
  338. package/src/providers/integrations/github/github-discovery.ts +55 -10
  339. package/src/providers/integrations/github/github-oauth.ts +6 -5
  340. package/src/providers/integrations/github/github.ts +41 -14
  341. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  342. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  343. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  344. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  345. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  346. package/src/providers/integrations/grok/grok.ts +86 -36
  347. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  348. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  349. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  350. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  351. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  352. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  353. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  354. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  355. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  356. package/src/providers/integrations/kiro/kiro.ts +81 -68
  357. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  358. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  359. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  360. package/src/providers/integrations/opencode/provider.ts +17 -24
  361. package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
  362. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  363. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  364. package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
  365. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  366. package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
  367. package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
  368. package/src/providers/integrations/qoder/qoder.ts +354 -62
  369. package/src/providers/integrations/shared/connect.ts +0 -54
  370. package/src/providers/integrations/shared/hash.ts +15 -0
  371. package/src/providers/integrations/shared/session-cache.ts +136 -0
  372. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  373. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  374. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  375. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  376. package/src/providers/integrations/trae/trae.ts +53 -10
  377. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  378. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  379. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  380. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  381. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  382. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  383. package/src/providers/operations/account-error-classification.ts +131 -116
  384. package/src/providers/operations/account-health-service.ts +31 -39
  385. package/src/providers/operations/account-reset-service.ts +58 -1
  386. package/src/providers/operations/cli-platform.ts +31 -5
  387. package/src/providers/operations/client-version-resolver.ts +4 -6
  388. package/src/providers/operations/client-versions.ts +10 -7
  389. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  390. package/src/providers/operations/provider-catalog-service.ts +18 -2
  391. package/src/providers/operations/provider-credential-service.ts +19 -2
  392. package/src/providers/provider-contracts.ts +18 -7
  393. package/src/providers/provider-metadata.ts +17 -2
  394. package/src/providers/provider-model-definition.ts +22 -1
  395. package/src/providers/provider-probe.ts +4 -2
  396. package/src/providers/provider-usage.ts +81 -16
  397. package/src/providers/quota/cache.ts +29 -0
  398. package/src/providers/quota/quota-contracts.ts +4 -0
  399. package/src/providers/quota/refresh.ts +27 -4
  400. package/src/providers/quota/snapshot.ts +94 -0
  401. package/src/providers/search/search-provider.ts +1 -3
  402. package/src/providers/search/search-providers.ts +2 -1
  403. package/src/security/abuse.ts +4 -4
  404. package/src/security/admission/service.ts +2 -2
  405. package/src/security/admission/ttl.ts +61 -61
  406. package/src/security/api-key-auth.ts +16 -4
  407. package/src/security/client-router-fingerprint.ts +4 -4
  408. package/src/security/credential-codec.ts +3 -3
  409. package/src/security/csrf.ts +2 -2
  410. package/src/security/ip-boundary.ts +16 -189
  411. package/src/security/model-access-rule.ts +1 -1
  412. package/src/security/outbound-headers.ts +18 -0
  413. package/src/shared/invoke-guard.ts +47 -0
  414. package/src/transport/contracts.ts +13 -4
  415. package/src/transport/dispatch/attempt-finalize.ts +1 -1
  416. package/src/transport/dispatch/capture-policy.ts +34 -37
  417. package/src/transport/dispatch/empty-stream.ts +23 -20
  418. package/src/transport/dispatch/generation.ts +25 -45
  419. package/src/transport/dispatch/native-shared.ts +127 -0
  420. package/src/transport/dispatch/proxy-request.ts +3 -1
  421. package/src/transport/dispatch/responses-compact.ts +25 -46
  422. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  423. package/src/transport/dispatch/streaming/finalize.ts +2 -2
  424. package/src/transport/dispatch/streaming/stream.ts +7 -3
  425. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  426. package/src/transport/dispatch/systemone.ts +20 -48
  427. package/src/transport/dispatch/token-count.ts +41 -38
  428. package/src/transport/dispatch/websearch.ts +19 -45
  429. package/src/transport/drain-endpoint.ts +1 -1
  430. package/src/transport/failure-policy.ts +6 -0
  431. package/src/transport/guards/auth-guard.ts +0 -6
  432. package/src/transport/guards/body-policy.ts +3 -3
  433. package/src/transport/guards/headroom-guard.ts +1 -1
  434. package/src/transport/guards/pipeline.ts +1 -1
  435. package/src/transport/guards/request-context.ts +12 -17
  436. package/src/transport/request/preparer.ts +286 -7
  437. package/src/transport/request/rtk/compress-request.ts +3 -3
  438. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  439. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  440. package/src/transport/request/state.ts +1 -13
  441. package/src/transport/request/system-prompt-injection.ts +74 -11
  442. package/src/transport/request/tenant-preferences.ts +22 -0
  443. package/src/transport/routing/candidate-index.ts +2 -2
  444. package/src/transport/routing/round-robin.ts +1 -1
  445. package/src/transport/routing/route-catalog.ts +17 -18
  446. package/src/transport/routing/route-model.ts +126 -33
  447. package/src/transport/routing/router.ts +152 -37
  448. package/src/transport/shutdown-notice.ts +2 -2
  449. package/src/transport/surface/adapters.ts +3 -3
  450. package/src/transport/surface/chat/encode.ts +7 -7
  451. package/src/transport/surface/chat/parse.ts +7 -7
  452. package/src/transport/surface/completion.ts +2 -2
  453. package/src/transport/surface/content-parts.ts +1 -1
  454. package/src/transport/surface/dialects.ts +2 -2
  455. package/src/transport/surface/messages/parse.ts +3 -3
  456. package/src/transport/surface/responses/adapter.ts +1 -1
  457. package/src/transport/surface/responses/errors.ts +0 -9
  458. package/src/transport/vision-handoff-cache.ts +58 -0
  459. package/src/transport/vision-handoff.ts +376 -0
  460. package/src/workers/account-identity-sweep.ts +2 -2
  461. package/src/workers/buddy-growth-tasks.ts +392 -346
  462. package/src/workers/daily-checkin.ts +102 -49
  463. package/src/workers/maintenance-lease.ts +2 -35
  464. package/src/workers/oauth-refresh-sweep.ts +8 -1
  465. package/src/workers/quota-refresh-sweep.ts +120 -82
  466. package/src/workers/scheduler.ts +67 -4
  467. package/src/workers/sweep-runner.ts +24 -5
  468. package/src/workers/zcode-gift-claim.ts +108 -0
  469. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  470. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  471. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  472. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  473. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  474. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
  475. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  476. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
  477. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  478. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  479. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
  480. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  481. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  482. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  483. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
  484. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  485. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
  486. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  487. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  488. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  489. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
  490. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  491. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  492. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
  493. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  494. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
  495. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  496. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  497. package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
  498. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  499. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  500. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
  501. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  502. package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
  503. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  504. package/dist/dashboard/assets/app-a159k0ub.css +0 -2
  505. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  506. package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
  507. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  508. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  509. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  510. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  511. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
  512. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  513. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  514. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  515. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  516. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  517. package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
  518. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  519. package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
  520. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  521. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  522. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  523. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  524. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  525. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  526. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  527. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  528. package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
  529. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  530. package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
  531. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  532. package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
  533. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  534. package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
  535. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  536. package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
  537. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  538. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  539. package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
  540. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  541. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  542. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  543. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  544. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  545. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  546. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  547. package/src/network/response-headers.ts +0 -39
  548. package/src/protocol/response/dsml.ts +0 -38
  549. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  550. /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
  551. /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  552. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  553. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -1,153 +1,153 @@
1
- import type {} from "../contracts";
2
- import { ensureV1Suffix, homeDir, join, readJsonFile, writeJsonFile } from "../fs-ops";
3
- import type { InjectorSpec } from "../contracts";
4
-
5
-
6
- // OpenCode injector spec.
7
- interface OpencodeModel {
8
- name: string;
9
- modalities: { input: string[]; output: string[] };
10
- }
11
-
12
- interface OpencodeProvider {
13
- npm: string;
14
- options: { baseURL?: string; apiKey?: string };
15
- models: Record<string, OpencodeModel>;
16
- }
17
-
18
- interface OpencodeConfig {
19
- provider?: Record<string, OpencodeProvider>;
20
- model?: string;
21
- agent?: {
22
- explorer?: {
23
- description?: string;
24
- mode?: string;
25
- model?: string;
26
- };
27
- [k: string]: unknown;
28
- };
29
- [k: string]: unknown;
30
- }
31
-
32
- function buildOpencodeModels(models: readonly string[]): Record<string, OpencodeModel> {
33
- const map: Record<string, OpencodeModel> = {};
34
- for (const m of models) {
35
- if (!m) continue;
36
- map[m] = { name: m, modalities: { input: ["text", "image"], output: ["text"] } };
37
- }
38
- return map;
39
- }
40
-
41
- export const opencodeSpec: InjectorSpec = {
42
- toolId: "opencode",
43
- displayName: "OpenCode",
44
- binary: "opencode",
45
- resolvePath: () => join(homeDir(), ".config", "opencode", "opencode.json"),
46
- resolveDir: () => join(homeDir(), ".config", "opencode"),
47
-
48
- async readStatus(path) {
49
- const config = (await readJsonFile(path)) as OpencodeConfig | null;
50
- if (!config) {
51
- return { configured: false, currentEndpoint: null, rawApiKey: null, currentModels: null };
52
- }
53
- const provider = config.provider?.cartethyia;
54
- const endpoint = provider?.options?.baseURL ?? null;
55
- const models = provider?.models ? Object.keys(provider.models) : null;
56
- const active =
57
- typeof config.model === "string" && config.model.startsWith("cartethyia/")
58
- ? config.model.split("/").slice(1).join("/")
59
- : null;
60
- return {
61
- configured: !!provider,
62
- currentEndpoint: endpoint,
63
- rawApiKey: provider?.options?.apiKey ?? null,
64
- currentModels: active && models ? [active, ...models.filter((m) => m !== active)] : models,
65
- };
66
- },
67
-
68
- async apply(input, path) {
69
- const existing = (await readJsonFile(path)) as OpencodeConfig | null;
70
- const config: OpencodeConfig = (existing ?? {}) as OpencodeConfig;
71
-
72
- if (!config.provider) config.provider = {};
73
- const prior = config.provider.cartethyia;
74
- config.provider.cartethyia = {
75
- npm: "@ai-sdk/openai-compatible",
76
- options: {
77
- ...(prior?.options ?? {}),
78
- baseURL: ensureV1Suffix(input.endpoint),
79
- apiKey: input.apiKey,
80
- },
81
- models: { ...(prior?.models ?? {}), ...buildOpencodeModels(input.modelIds) },
82
- };
83
-
84
- const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
85
- config.model = activeModel === "" ? "" : `cartethyia/${activeModel}`;
86
-
87
- if (!config.agent) config.agent = {};
88
- const subagentModel = input.subagentModel ?? input.modelIds[0] ?? activeModel;
89
- config.agent.explorer = {
90
- description: "Fast explorer subagent",
91
- mode: "subagent",
92
- model: `cartethyia/${subagentModel}`,
93
- };
94
-
95
- await writeJsonFile(path, config);
96
- },
97
-
98
- async reset(path) {
99
- const config = (await readJsonFile(path)) as OpencodeConfig | null;
100
- if (!config) return false;
101
-
102
- if (config.provider) {
103
- delete config.provider.cartethyia;
104
- if (Object.keys(config.provider).length === 0) delete config.provider;
105
- }
106
-
107
- if (typeof config.model === "string" && config.model.startsWith("cartethyia/")) {
108
- delete config.model;
109
- }
110
-
111
- if (config.agent?.explorer?.model?.startsWith("cartethyia/")) {
112
- delete config.agent.explorer;
113
- if (Object.keys(config.agent).length === 0) delete config.agent;
114
- }
115
-
116
- await writeJsonFile(path, config);
117
- },
118
-
119
- download(input) {
120
- const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
121
- const subagentModel = input.subagentModel ?? input.modelIds[0] ?? activeModel;
122
- const config: OpencodeConfig = {
123
- provider: {
124
- cartethyia: {
125
- npm: "@ai-sdk/openai-compatible",
126
- options: {
127
- baseURL: ensureV1Suffix(input.endpoint),
128
- apiKey: input.apiKey,
129
- },
130
- models: buildOpencodeModels(input.modelIds),
131
- },
132
- },
133
- model: activeModel === "" ? "" : `cartethyia/${activeModel}`,
134
- agent: {
135
- explorer: {
136
- description: "Fast explorer subagent",
137
- mode: "subagent",
138
- model: `cartethyia/${subagentModel}`,
139
- },
140
- },
141
- };
142
- return {
143
- content: JSON.stringify(config, null, 2),
144
- filename: "opencode.json",
145
- mimeType: "application/json",
146
- };
147
- },
148
-
149
- messages: {
150
- applied: "OpenCode settings applied",
151
- reset: "Cartethyia settings removed from OpenCode",
152
- },
153
- };
1
+ import type {} from "../contracts";
2
+ import { ensureV1Suffix, homeDir, join, readJsonFile, writeJsonFile } from "../fs-ops";
3
+ import type { InjectorSpec } from "../contracts";
4
+
5
+
6
+ // OpenCode injector spec.
7
+ interface OpencodeModel {
8
+ name: string;
9
+ modalities: { input: string[]; output: string[] };
10
+ }
11
+
12
+ interface OpencodeProvider {
13
+ npm: string;
14
+ options: { baseURL?: string; apiKey?: string };
15
+ models: Record<string, OpencodeModel>;
16
+ }
17
+
18
+ interface OpencodeConfig {
19
+ provider?: Record<string, OpencodeProvider>;
20
+ model?: string;
21
+ agent?: {
22
+ explorer?: {
23
+ description?: string;
24
+ mode?: string;
25
+ model?: string;
26
+ };
27
+ [k: string]: unknown;
28
+ };
29
+ [k: string]: unknown;
30
+ }
31
+
32
+ function buildOpencodeModels(models: readonly string[]): Record<string, OpencodeModel> {
33
+ const map: Record<string, OpencodeModel> = {};
34
+ for (const m of models) {
35
+ if (!m) continue;
36
+ map[m] = { name: m, modalities: { input: ["text", "image"], output: ["text"] } };
37
+ }
38
+ return map;
39
+ }
40
+
41
+ export const opencodeSpec: InjectorSpec = {
42
+ toolId: "opencode",
43
+ displayName: "OpenCode",
44
+ binary: "opencode",
45
+ resolvePath: () => join(homeDir(), ".config", "opencode", "opencode.json"),
46
+ resolveDir: () => join(homeDir(), ".config", "opencode"),
47
+
48
+ async readStatus(path) {
49
+ const config = (await readJsonFile(path)) as OpencodeConfig | null;
50
+ if (!config) {
51
+ return { configured: false, currentEndpoint: null, rawApiKey: null, currentModels: null };
52
+ }
53
+ const provider = config.provider?.cartethyia;
54
+ const endpoint = provider?.options?.baseURL ?? null;
55
+ const models = provider?.models ? Object.keys(provider.models) : null;
56
+ const active =
57
+ typeof config.model === "string" && config.model.startsWith("cartethyia/")
58
+ ? config.model.split("/").slice(1).join("/")
59
+ : null;
60
+ return {
61
+ configured: !!provider,
62
+ currentEndpoint: endpoint,
63
+ rawApiKey: provider?.options?.apiKey ?? null,
64
+ currentModels: active && models ? [active, ...models.filter((m) => m !== active)] : models,
65
+ };
66
+ },
67
+
68
+ async apply(input, path) {
69
+ const existing = (await readJsonFile(path)) as OpencodeConfig | null;
70
+ const config: OpencodeConfig = (existing ?? {}) as OpencodeConfig;
71
+
72
+ if (!config.provider) config.provider = {};
73
+ const prior = config.provider.cartethyia;
74
+ config.provider.cartethyia = {
75
+ npm: "@ai-sdk/openai-compatible",
76
+ options: {
77
+ ...(prior?.options ?? {}),
78
+ baseURL: ensureV1Suffix(input.endpoint),
79
+ apiKey: input.apiKey,
80
+ },
81
+ models: { ...(prior?.models ?? {}), ...buildOpencodeModels(input.modelIds) },
82
+ };
83
+
84
+ const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
85
+ config.model = activeModel === "" ? "" : `cartethyia/${activeModel}`;
86
+
87
+ if (!config.agent) config.agent = {};
88
+ const subagentModel = input.subagentModel ?? input.modelIds[0] ?? activeModel;
89
+ config.agent.explorer = {
90
+ description: "Fast explorer subagent",
91
+ mode: "subagent",
92
+ model: `cartethyia/${subagentModel}`,
93
+ };
94
+
95
+ await writeJsonFile(path, config);
96
+ },
97
+
98
+ async reset(path) {
99
+ const config = (await readJsonFile(path)) as OpencodeConfig | null;
100
+ if (!config) return false;
101
+
102
+ if (config.provider) {
103
+ delete config.provider.cartethyia;
104
+ if (Object.keys(config.provider).length === 0) delete config.provider;
105
+ }
106
+
107
+ if (typeof config.model === "string" && config.model.startsWith("cartethyia/")) {
108
+ delete config.model;
109
+ }
110
+
111
+ if (config.agent?.explorer?.model?.startsWith("cartethyia/")) {
112
+ delete config.agent.explorer;
113
+ if (Object.keys(config.agent).length === 0) delete config.agent;
114
+ }
115
+
116
+ await writeJsonFile(path, config);
117
+ },
118
+
119
+ download(input) {
120
+ const activeModel = input.activeModel ?? input.modelIds[0] ?? "";
121
+ const subagentModel = input.subagentModel ?? input.modelIds[0] ?? activeModel;
122
+ const config: OpencodeConfig = {
123
+ provider: {
124
+ cartethyia: {
125
+ npm: "@ai-sdk/openai-compatible",
126
+ options: {
127
+ baseURL: ensureV1Suffix(input.endpoint),
128
+ apiKey: input.apiKey,
129
+ },
130
+ models: buildOpencodeModels(input.modelIds),
131
+ },
132
+ },
133
+ model: activeModel === "" ? "" : `cartethyia/${activeModel}`,
134
+ agent: {
135
+ explorer: {
136
+ description: "Fast explorer subagent",
137
+ mode: "subagent",
138
+ model: `cartethyia/${subagentModel}`,
139
+ },
140
+ },
141
+ };
142
+ return {
143
+ content: JSON.stringify(config, null, 2),
144
+ filename: "opencode.json",
145
+ mimeType: "application/json",
146
+ };
147
+ },
148
+
149
+ messages: {
150
+ applied: "OpenCode settings applied",
151
+ reset: "Cartethyia settings removed from OpenCode",
152
+ },
153
+ };
@@ -23,7 +23,7 @@ import type { ApplyInput, CliMappingInput, CliModelMapping } from "./contracts";
23
23
  * `download` and `apply` require `keyId`; the server resolves the recoverable
24
24
  * AES-256-GCM copy so the operator never pastes a raw secret.
25
25
  */
26
- export interface CliToolsRoutesConfig {
26
+ interface CliToolsRoutesConfig {
27
27
  readonly service: CliToolService;
28
28
  readonly accessResolver: ConsoleAccessResolver;
29
29
  readonly auditSink?: AuditSink;
@@ -27,7 +27,7 @@ import { ConsoleDomainError } from "../shared/errors";
27
27
  * and share one process's home directory (they are not tenant-scoped).
28
28
  */
29
29
 
30
- export function toToolRegistryEntry(def: ToolDef): ToolRegistryEntry {
30
+ function toToolRegistryEntry(def: ToolDef): ToolRegistryEntry {
31
31
  return {
32
32
  id: def.id,
33
33
  name: def.name,
@@ -14,13 +14,13 @@ import type {
14
14
  * The API-layer service owns validation against the registry; this store
15
15
  * only serializes rows in and out of Postgres.
16
16
  */
17
- export interface StoredMappingRow extends CliModelMapping {
17
+ interface StoredMappingRow extends CliModelMapping {
18
18
  readonly toolId: string;
19
19
  readonly tenantId: string;
20
20
  readonly apiKeyId: string;
21
21
  }
22
22
 
23
- export interface StoredSettings {
23
+ interface StoredSettings {
24
24
  readonly tenantId: string;
25
25
  readonly toolId: string;
26
26
  readonly apiKeyId: string;
@@ -36,6 +36,7 @@ import type { BundledProviderCatalog } from "../providers/operations/provider-ca
36
36
  import type { ValidatedNetworkBindingFactory } from "../network/pool/resolver";
37
37
  import type { TrustedProxyBoundary } from "../config/network";
38
38
  import { gzipResponse } from "./response-compression";
39
+ import { beginConsoleActivity } from "../shared/invoke-guard";
39
40
 
40
41
  export interface ConsoleApiCompositionDeps {
41
42
  readonly db: CartethyiaDatabase;
@@ -80,6 +81,15 @@ export interface ConsoleApiCompositionDeps {
80
81
  | undefined;
81
82
  readonly resolvePeerAddress?: (request: Request) => string | null;
82
83
  readonly trustedProxyBoundary?: TrustedProxyBoundary;
84
+ /**
85
+ * The process shutdown coordinator, narrowed to the surface the update apply
86
+ * route needs. Declared structural (not the class) so the console composition
87
+ * root does not import the boot layer; `ShutdownCoordinator` satisfies it.
88
+ */
89
+ readonly shutdownCoordinator?: {
90
+ readonly begin: (reason: "update") => Promise<void>;
91
+ readonly totalShutdownBudgetMs: () => number;
92
+ };
83
93
  }
84
94
  /**
85
95
  * Extracts a bearer API key from a console request, or `undefined`.
@@ -109,6 +119,12 @@ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): AnyElysia
109
119
  * process (tests, or a second app instance) never share decisions.
110
120
  */
111
121
  const sessionAccessCache = new WeakMap<Request, AccessDecision | null>();
122
+ /**
123
+ * G-03 InvokeGuard: the console control plane's foreground-activity count.
124
+ * `beforeHandle` bumps it for the request; `afterResponse` releases it. The
125
+ * end callback is keyed by request so parallel requests pair correctly.
126
+ */
127
+ const consoleActivityEnds = new WeakMap<Request, () => void>();
112
128
  const cookiePolicy = defaultSessionCookiePolicy;
113
129
  const credentialService = new ConsoleCredentialService();
114
130
  const sessionService = new ConsoleSessionService(db, cookiePolicy);
@@ -137,6 +153,12 @@ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): AnyElysia
137
153
  .use(createConsoleCsrfMiddleware())
138
154
  .use(createConsoleMutationLimiterMiddleware())
139
155
  .beforeHandle(async ({ request }: { request: Request }) => {
156
+ // G-03: count this console request as foreground activity for the
157
+ // duration of its handling. Released in `afterResponse` below (or by
158
+ // the catch-all in the error path, which also runs before the response
159
+ // leaves). The scheduled worker registry uses this to defer sweeps
160
+ // while the operator is actively using the console.
161
+ consoleActivityEnds.set(request, beginConsoleActivity());
140
162
  // The auth routes (`/console/api/auth/*`) resolve the session themselves
141
163
  // and never read `accessResolver`, so resolving here too would repeat the
142
164
  // session lookup plus its user query on every login/session/logout call
@@ -167,6 +189,15 @@ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): AnyElysia
167
189
  }),
168
190
  );
169
191
  })
192
+ .afterResponse(({ request }: { request: Request }) => {
193
+ // G-03: release the foreground-activity count for this request.
194
+ // Elysia runs `afterResponse` for every completed request, errored ones
195
+ // included (the error is converted to a response first), so this is the
196
+ // single reliable release point — a failing route can never leak an
197
+ // elevated foreground count (which would defer sweeps forever).
198
+ consoleActivityEnds.get(request)?.();
199
+ consoleActivityEnds.delete(request);
200
+ })
170
201
  .use(
171
202
  createConsoleAuthRoutes(
172
203
  db,
@@ -197,6 +228,7 @@ export function createConsoleRouter(deps: ConsoleApiCompositionDeps): AnyElysia
197
228
  admissionService: deps.admissionService,
198
229
  readRoutingAccountInflight: deps.readRoutingAccountInflight,
199
230
  ...(deps.flushBuffers ? { flushBuffers: deps.flushBuffers } : {}),
231
+ ...(deps.shutdownCoordinator ? { shutdownCoordinator: deps.shutdownCoordinator } : {}),
200
232
  credentialService,
201
233
  // The backup surface re-authenticates the operator, so it needs the current
202
234
  // user's hash. Read from the session on the request that asks for it, never
@@ -9,7 +9,7 @@ import { acceptsGzip } from "./response-compression";
9
9
  /**
10
10
  * Represents the result of serving a static file.
11
11
  */
12
- export interface StaticServeResult {
12
+ interface StaticServeResult {
13
13
  status: number;
14
14
  body: Uint8Array | undefined;
15
15
  headers: Record<string, string>;
@@ -18,7 +18,7 @@ export interface StaticServeResult {
18
18
  /**
19
19
  * Configuration for the static file handler.
20
20
  */
21
- export interface StaticHandlerConfig {
21
+ interface StaticHandlerConfig {
22
22
  /** Absolute path to the dashboard build directory */
23
23
  buildDir: string;
24
24
  /**
@@ -30,7 +30,7 @@ export interface StaticHandlerConfig {
30
30
  }
31
31
 
32
32
  /** Shared landing, console, and public share entry document produced by Vite. */
33
- export const DEFAULT_ENTRY_DOCUMENTS: Readonly<Record<string, string>> = {
33
+ const DEFAULT_ENTRY_DOCUMENTS: Readonly<Record<string, string>> = {
34
34
  "/": "index.html",
35
35
  "/share": "index.html",
36
36
  "/console": "index.html",
@@ -47,7 +47,7 @@ function dashboardBuildHeader(html: string): Record<string, string> {
47
47
  * their own card here — crawlers do not run the client bundle, so a
48
48
  * `document.title` set at runtime cannot reach them.
49
49
  */
50
- export interface SocialMeta {
50
+ interface SocialMeta {
51
51
  title: string;
52
52
  description: string;
53
53
  image: string;
@@ -62,11 +62,11 @@ export const SHARE_SOCIAL_META: SocialMeta = {
62
62
  title: "Cartethyia — Bansos Token",
63
63
  description:
64
64
  "Come and save your tokens 💖 Shared Cartethyia API key — Bansos Token with live quota, usage and model allowlist.",
65
- image: "/assets/brand/og_bansos.webp",
66
- imageType: "image/webp",
67
- // Read from the file's own VP8 header, not carried over from the JPEG this
68
- // replaced: og:image:width/height are what a crawler uses to allocate the
69
- // card before the bytes arrive, so a copied size makes every preview crop.
65
+ image: "/assets/brand/og_bansos.jpg",
66
+ imageType: "image/jpeg",
67
+ // Read from the file's own header, not carried over from a previous image:
68
+ // og:image:width/height are what a crawler uses to allocate the card before
69
+ // the bytes arrive, so a copied size makes every preview crop.
70
70
  imageWidth: 1760,
71
71
  imageHeight: 576,
72
72
  imageAlt: "Cartethyia Bansos Token — Come and save your tokens",
@@ -124,6 +124,16 @@ export interface ConsoleDomainContext {
124
124
  readonly loadConsoleUser: (request: Request) => Promise<{ readonly passwordHash: string } | null>;
125
125
  /** Password verification against the console user's stored hash. */
126
126
  readonly credentialService: Pick<ConsoleCredentialService, "verifyPassword">;
127
+ /**
128
+ * The process shutdown coordinator, narrowed to the update apply route's
129
+ * drain surface. Optional because reduced compositions (tests) legitimately
130
+ * build a console that cannot apply updates; the apply route answers 503
131
+ * rather than exiting undrained when it is absent.
132
+ */
133
+ readonly shutdownCoordinator?: {
134
+ readonly begin: (reason: "update") => Promise<void>;
135
+ readonly totalShutdownBudgetMs: () => number;
136
+ };
127
137
  }
128
138
  import { and, eq, isNull, or } from "drizzle-orm";
129
139
  import { networkPools, providerRoutingSettings } from "../persistence/schema";
@@ -252,6 +262,9 @@ export function registerConsoleDomains(
252
262
  console.use(createUpdateRoutes({
253
263
  accessResolver: ctx.accessResolver,
254
264
  observabilityStore,
265
+ ...(ctx.shutdownCoordinator === undefined
266
+ ? {}
267
+ : { shutdownCoordinator: ctx.shutdownCoordinator }),
255
268
  }));
256
269
  console.use(createRemoteSupportRoutes({
257
270
  accessResolver: ctx.accessResolver,
@@ -271,6 +284,7 @@ export function registerConsoleDomains(
271
284
  accessResolver: ctx.accessResolver,
272
285
  auditSink: ctx.auditRecorder,
273
286
  providerRegistry: ctx.providerRegistry,
287
+ redis: ctx.redis,
274
288
  snapshotInvalidator: ctx.routeSnapshotService,
275
289
  resolveExportCredentials,
276
290
  // Without this, a custom provider only becomes dispatchable after a
@@ -384,8 +398,8 @@ export function registerConsoleDomains(
384
398
  // it is released when the last of those flows settles.
385
399
  const oauthCallbackListener = new OAuthCallbackListener({
386
400
  completer: {
387
- complete: (providerId, code, state) =>
388
- completeLogin(oauthConfig, providerId, code, state),
401
+ complete: (providerId, code, state, callbackParams) =>
402
+ completeLogin(oauthConfig, providerId, code, state, callbackParams),
389
403
  },
390
404
  });
391
405
  const oauthConfig: OAuthLoginConfig = {
@@ -54,13 +54,6 @@ export interface InferhubClientOptions {
54
54
  readonly now?: () => number;
55
55
  }
56
56
 
57
- export class InferhubRateLimited extends Error {
58
- constructor() {
59
- super("inferhub management rate limit reached");
60
- this.name = "InferhubRateLimited";
61
- }
62
- }
63
-
64
57
  /**
65
58
  * One management GET.
66
59
  *
@@ -20,7 +20,7 @@ import { decryptCredentialToString, encryptCredential, hashSecret } from "../../
20
20
  import type { CartethyiaDatabase } from "../../persistence/db-handle";
21
21
 
22
22
  /** Shape returned to the console: whether a key is set, and never the key. */
23
- export interface InferhubKeyStatus {
23
+ interface InferhubKeyStatus {
24
24
  readonly configured: boolean;
25
25
  /** Last four characters, so an operator can tell two keys apart. */
26
26
  readonly last4: string | null;
@@ -26,7 +26,7 @@ import type {
26
26
  /** Ask buckets are keyed to this many decimals so float noise cannot split one price into two tiers. */
27
27
  const PRICE_PRECISION = 6;
28
28
  /** Default number of live providers a capacity-weighted price must have behind it. */
29
- export const DEFAULT_MIN_CAPACITY = 2;
29
+ const DEFAULT_MIN_CAPACITY = 2;
30
30
 
31
31
  const FAMILY_STATES: readonly FamilyState[] = [
32
32
  "operational",
@@ -114,7 +114,7 @@ export function groupTiers(
114
114
  * provider count would make `providersLive` wrong, and a wrong availability
115
115
  * number is worse than an absent one.
116
116
  */
117
- export function pricePointsToTiers(
117
+ function pricePointsToTiers(
118
118
  points: unknown,
119
119
  official: number | null,
120
120
  ): readonly Tier[] {
@@ -57,7 +57,7 @@ import type {
57
57
  /** Success rate below which a model is not routed to, when one is reported. */
58
58
  const MIN_SUCCESS_RATE_PCT = 80;
59
59
 
60
- export interface InferhubRoutesConfig {
60
+ interface InferhubRoutesConfig {
61
61
  readonly accessResolver: (request: Request) => AccessDecision | undefined;
62
62
  /** Resolves the `config_read` key. Absent means the catalog cannot be read. */
63
63
  readonly resolveConfigKey?: () => Promise<string | undefined> | string | undefined;
@@ -34,7 +34,7 @@ export interface ModelHealth {
34
34
  readonly familyState: FamilyState | null;
35
35
  }
36
36
 
37
- export interface ModelCapabilities {
37
+ interface ModelCapabilities {
38
38
  readonly contextWindow: number | null;
39
39
  readonly maxOutputTokens: number | null;
40
40
  readonly modalities: readonly string[];
@@ -173,7 +173,7 @@ export interface UsageCacheResponse {
173
173
  cacheWriteTokens: number;
174
174
  hitRate: number;
175
175
  }
176
- export type UsageRequestMode = "stream" | "non_stream";
176
+ type UsageRequestMode = "stream" | "non_stream";
177
177
  export interface UsageRequestItem {
178
178
  requestId: string;
179
179
  surface?: string;
@@ -34,7 +34,7 @@ import { poolByteSnapshot } from "../../network/pool/byte-accounting";
34
34
  import { consoleSseResponse, createConsoleSseStream } from "./sse";
35
35
  import { subscribeRequestCompleted } from "../../observability/request-notify";
36
36
 
37
- export interface LiveConfig {
37
+ interface LiveConfig {
38
38
  readonly accessResolver: ConsoleAccessResolver;
39
39
  readonly poolSelector?: NetworkPoolSelector;
40
40
  readonly db?: CartethyiaDatabase;
@@ -94,10 +94,9 @@ export function createLiveRoutes(config: LiveConfig): AnyElysia {
94
94
  requireScope(access, "dashboard:read");
95
95
  const tenantId = access?.tenantId;
96
96
  if (!tenantId) return errorResponse(new Error("Tenant required"), set, "Live operation failed");
97
- set.headers["content-type"] = "text/event-stream";
98
- set.headers["cache-control"] = "no-cache, no-transform";
99
- set.headers["connection"] = "keep-alive";
100
- set.headers["x-accel-buffering"] = "no";
97
+ // No `set.headers` writes here: this handler returns a `Response`, so
98
+ // Elysia discards `set` and `consoleSseResponse` below owns the SSE
99
+ // headers (content-type, cache-control, connection, buffering).
101
100
  return consoleSseResponse(
102
101
  createConsoleSseStream(request.signal, ({ send }) => {
103
102
  return subscribeRequestCompleted((notice) => {
@@ -119,22 +118,36 @@ export function createLiveRoutes(config: LiveConfig): AnyElysia {
119
118
  })
120
119
  .get("/live/in-flight/stream", ({ request, set }) => {
121
120
  try {
122
- requireScope(config.accessResolver(request), "dashboard:read");
121
+ const access = requireScope(config.accessResolver(request), "dashboard:read");
122
+ const tenantId = access?.tenantId;
123
+ return consoleSseResponse(
124
+ createConsoleSseStream(request.signal, ({ send }) => {
125
+ const store = config.stateStore;
126
+ if (!store) {
127
+ send("count", EMPTY_IN_FLIGHT);
128
+ return () => {};
129
+ }
130
+ // The Usage page keeps one stream open for both the in-flight gauge
131
+ // and request-table invalidation, so this route also fans out
132
+ // `request_completed` events (tagged by kind) for the tenant,
133
+ // mirroring `/live/requests/stream`.
134
+ const unsubscribe = store.subscribeInFlight((snapshot) => send("count", snapshot));
135
+ let unsubscribeCompleted: (() => void) | undefined;
136
+ if (tenantId) {
137
+ unsubscribeCompleted = subscribeRequestCompleted((notice) => {
138
+ if (notice.tenantId === tenantId) send("request_completed", notice);
139
+ });
140
+ }
141
+ send("count", store.inFlightSnapshot());
142
+ return () => {
143
+ unsubscribe();
144
+ unsubscribeCompleted?.();
145
+ };
146
+ }),
147
+ );
123
148
  } catch (e) {
124
149
  return errorResponse(e, set, "Live operation failed");
125
150
  }
126
- return consoleSseResponse(
127
- createConsoleSseStream(request.signal, ({ send }) => {
128
- const store = config.stateStore;
129
- if (!store) {
130
- send("count", EMPTY_IN_FLIGHT);
131
- return () => {};
132
- }
133
- const unsubscribe = store.subscribeInFlight((snapshot) => send("count", snapshot));
134
- send("count", store.inFlightSnapshot());
135
- return unsubscribe;
136
- }),
137
- );
138
151
  })
139
152
  .get("/live/pools", async ({ request, set }) => {
140
153
  try {