cartethyia 2.7.8 → 2.7.9

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 (371) hide show
  1. package/.env.example +0 -1
  2. package/README.md +29 -59
  3. package/dist/dashboard/assets/BannedPage-BxoG1MrL.js +1 -0
  4. package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-ixwgKk53.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-BmttNV3U.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-BE3qwwfC.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
  11. package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js +1 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
  13. package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js +1 -0
  14. package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
  17. package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BOoO8rpz.js} +2 -2
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-ChJuNNVN.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-BZAJtPg1.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-BE40s3u5.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +8 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BJ87Pp0U.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
  33. package/dist/dashboard/assets/{QuotaPage-CMJKNYWb.js → QuotaPage-gkSyRAKa.js} +1 -1
  34. package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-CFNcATJJ.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-YoD4tY5l.js} +1 -1
  40. package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-DxjaAhb_.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-BTlkq_Uk.js +1 -0
  44. package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
  45. package/dist/dashboard/assets/app-BX2nnKqs.css +2 -0
  46. package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
  47. package/dist/dashboard/assets/assert-CndthXFQ.js +1 -0
  48. package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-DdbT_7Am.js} +1 -1
  50. package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
  51. package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
  52. package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
  53. package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-CsGN-nbm.js} +1 -1
  54. package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
  55. package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
  56. package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
  57. package/dist/dashboard/assets/brand/favicon.webp +0 -0
  58. package/dist/dashboard/assets/brand/login_register.webp +0 -0
  59. package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
  60. package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
  61. package/dist/dashboard/assets/brand/og_image.webp +0 -0
  62. package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
  63. package/dist/dashboard/assets/{card-_HwAEqFF.js → card-mgZ_TLLZ.js} +1 -1
  64. package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
  65. package/dist/dashboard/assets/cli-tools-A1-v8-03.js +1 -0
  66. package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
  67. package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CJ4Zty89.js} +1 -1
  68. package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
  69. package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-B5L2jPQ_.js} +1 -1
  70. package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
  71. package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-DkjUouAj.js} +1 -1
  72. package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
  73. package/dist/dashboard/assets/{entry-COaC-irN.js → entry-B-LVLV6o.js} +1 -1
  74. package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
  75. package/dist/dashboard/assets/entry-CAhdYl3B.js +1 -0
  76. package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
  77. package/dist/dashboard/assets/entry-D2xD0Tmd.js +4 -0
  78. package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
  79. package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-CrsdLVsn.js} +1 -1
  80. package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
  81. package/dist/dashboard/assets/{index-CgKmFngv.js → index-BU64Lqvp.js} +2 -2
  82. package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
  83. package/dist/dashboard/assets/{inline-B2BirKry.js → inline-B2aDLyyg.js} +1 -1
  84. package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
  85. package/dist/dashboard/assets/{input-D-qV9dKY.js → input-BCVkdR9d.js} +1 -1
  86. package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
  87. package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-DNcAdMK-.js} +1 -1
  88. package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
  89. package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-DgrIH0hw.js} +1 -1
  90. package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
  91. package/dist/dashboard/assets/{live-DGizF06-.js → live-Cae01iu8.js} +1 -1
  92. package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
  93. package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
  94. package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
  95. package/dist/dashboard/assets/{network-C9UE-bOr.js → network-CRib7H_2.js} +1 -1
  96. package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
  97. package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-BKQE8Xpz.js} +1 -1
  98. package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
  99. package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-ecPvG_8g.js} +1 -1
  100. package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
  101. package/dist/dashboard/assets/providers/devin.svg +9 -0
  102. package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
  103. package/dist/dashboard/assets/providers/windsurf.svg +10 -0
  104. package/dist/dashboard/assets/providers/windsurf.svg.gz +0 -0
  105. package/dist/dashboard/assets/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
  106. package/dist/dashboard/assets/query-keys-IKLh0YFd.js.gz +0 -0
  107. package/dist/dashboard/assets/routing-Ckm1UXuC.js +1 -0
  108. package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
  109. package/dist/dashboard/assets/{select-BCOcv8WK.js → select-ChoFWyKz.js} +1 -1
  110. package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
  111. package/dist/dashboard/assets/settings-CKjFPlKW.js +1 -0
  112. package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
  113. package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DWCwU3fh.js} +1 -1
  114. package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
  115. package/dist/dashboard/assets/{state-DXbGTx7N.js → state-Cg3VL5J_.js} +1 -1
  116. package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
  117. package/dist/dashboard/assets/story/25817331.webp +0 -0
  118. package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
  119. package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
  120. package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
  121. package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
  122. package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
  123. package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
  124. package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
  125. package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-Db70BMix.js} +1 -1
  126. package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
  127. package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BqdE0LuM.js} +1 -1
  128. package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
  129. package/dist/dashboard/console-backgrounds.webp +0 -0
  130. package/dist/dashboard/console-backgrounds_initial.webp +0 -0
  131. package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
  132. package/dist/dashboard/index.html +3 -3
  133. package/dist/dashboard/index.html.gz +0 -0
  134. package/dist/dashboard/precompressed-assets.json +57 -55
  135. package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
  136. package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
  137. package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
  138. package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
  139. package/package.json +1 -1
  140. package/src/boot/dependencies.ts +11 -3
  141. package/src/config/cooldowns.ts +1 -1
  142. package/src/config/spec.ts +0 -6
  143. package/src/console/api-keys/routes.ts +11 -4
  144. package/src/console/console-router.ts +7 -0
  145. package/src/console/dashboard-assets.ts +5 -5
  146. package/src/console/domain-registration.ts +27 -0
  147. package/src/console/ip-bans/routes.ts +99 -0
  148. package/src/console/providers/catalog/catalog-projections.ts +5 -2
  149. package/src/console/providers/catalog/contracts.ts +123 -0
  150. package/src/console/providers/catalog/model-operations.ts +122 -10
  151. package/src/console/providers/catalog/provider-operations.ts +116 -8
  152. package/src/console/providers/catalog/public-model-store.ts +0 -0
  153. package/src/console/providers/catalog/routes.ts +64 -4
  154. package/src/console/providers/catalog/store-helpers.ts +30 -1
  155. package/src/console/providers/catalog/store.ts +243 -3
  156. package/src/console/quota/account-quota-global.ts +89 -1
  157. package/src/console/quota/native-identity.ts +2 -0
  158. package/src/console/settings/contracts.ts +18 -0
  159. package/src/console/settings/store.ts +32 -0
  160. package/src/console/system-prompt/contracts.ts +0 -1
  161. package/src/main.ts +1 -0
  162. package/src/observability/event-query.ts +18 -4
  163. package/src/persistence/dialect.ts +12 -0
  164. package/src/persistence/schema.ts +20 -2
  165. package/src/protocol/dsml.ts +1 -1
  166. package/src/protocol/gateway-error.ts +1 -0
  167. package/src/protocol/reasoning.ts +1 -1
  168. package/src/protocol/request/chat.ts +4 -4
  169. package/src/protocol/request/messages.ts +1 -1
  170. package/src/protocol/response/gemini.ts +6 -1
  171. package/src/protocol/sse-decoder.ts +25 -8
  172. package/src/protocol/stream-error-frames.ts +13 -3
  173. package/src/protocol/translation/quirks.ts +1 -1
  174. package/src/protocol/translation/tool-repair.ts +2 -2
  175. package/src/protocol/upstream/send-claude-messages.ts +15 -4
  176. package/src/protocol/upstream-parsing.ts +1 -1
  177. package/src/providers/adapters/compatible-adapter.ts +7 -5
  178. package/src/providers/authentication/oauth-refresh-service.ts +149 -36
  179. package/src/providers/default-registry.ts +68 -3
  180. package/src/providers/discovery/discovery-types.ts +12 -0
  181. package/src/providers/discovery/probe-phases.ts +61 -30
  182. package/src/providers/discovery/probing-service.ts +279 -164
  183. package/src/providers/integrations/antigravity/antigravity-protocol.ts +117 -2
  184. package/src/providers/integrations/antigravity/antigravity.ts +13 -2
  185. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
  186. package/src/providers/integrations/buddy/buddy-chat-shared.ts +18 -18
  187. package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
  188. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
  189. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
  190. package/src/providers/integrations/buddy/buddy-identity.ts +70 -0
  191. package/src/providers/integrations/buddy/buddy-media.ts +4 -5
  192. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
  193. package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
  194. package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
  195. package/src/providers/integrations/buddy/capabilities.ts +4 -41
  196. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
  197. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +20 -1
  198. package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -2
  199. package/src/providers/integrations/buddy/codebuddy/shared.ts +6 -10
  200. package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
  201. package/src/providers/integrations/cursor/cursor-exec.ts +738 -0
  202. package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
  203. package/src/providers/integrations/cursor/cursor-request.ts +9 -8
  204. package/src/providers/integrations/cursor/cursor-shared.ts +19 -1
  205. package/src/providers/integrations/cursor/cursor.ts +50 -30
  206. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +26 -100
  207. package/src/providers/integrations/devin/devin-auth.ts +353 -0
  208. package/src/providers/integrations/devin/devin-catalog.ts +207 -0
  209. package/src/providers/integrations/devin/devin-http.ts +91 -0
  210. package/src/providers/integrations/devin/devin-quota.ts +214 -0
  211. package/src/providers/integrations/devin/devin-shared.ts +111 -0
  212. package/src/providers/integrations/devin/devin.ts +539 -0
  213. package/src/providers/integrations/devin/protocol/devin-proto.ts +584 -0
  214. package/src/providers/integrations/devin/protocol/framing.ts +124 -0
  215. package/src/providers/integrations/factory/factory.ts +2 -2
  216. package/src/providers/integrations/freepi/freepi-catalog.ts +60 -0
  217. package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
  218. package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
  219. package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
  220. package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
  221. package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
  222. package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
  223. package/src/providers/integrations/freepi/freepi.ts +292 -0
  224. package/src/providers/integrations/gemini.ts +2 -2
  225. package/src/providers/integrations/hermes/hermes-oauth.ts +94 -0
  226. package/src/providers/integrations/hermes.ts +4 -12
  227. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  228. package/src/providers/integrations/perch/perch-catalog.ts +105 -0
  229. package/src/providers/integrations/perch/perch-oauth.ts +170 -0
  230. package/src/providers/integrations/perch/perch-protocol.ts +211 -0
  231. package/src/providers/integrations/perch/perch-quota.ts +137 -0
  232. package/src/providers/integrations/perch/perch-realm.ts +82 -0
  233. package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
  234. package/src/providers/integrations/perch/perch.ts +315 -0
  235. package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
  236. package/src/providers/integrations/qoder/chat-proto.ts +328 -328
  237. package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
  238. package/src/providers/integrations/qoder/qoder-adapter.ts +89 -28
  239. package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
  240. package/src/providers/integrations/qoder/qoder-catalog.ts +6 -1
  241. package/src/providers/integrations/qoder/qoder-checkin.ts +2 -2
  242. package/src/providers/integrations/qoder/qoder-grpc.ts +210 -6
  243. package/src/providers/integrations/qoder/qoder-ide.ts +5 -1
  244. package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
  245. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
  246. package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
  247. package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
  248. package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
  249. package/src/providers/integrations/qoder/qoder.ts +3 -6
  250. package/src/providers/integrations/trae/trae-catalog.ts +9 -14
  251. package/src/providers/integrations/trae/trae-headers.ts +36 -11
  252. package/src/providers/integrations/trae/trae-oauth.ts +14 -17
  253. package/src/providers/integrations/trae/trae-protocol.ts +3 -6
  254. package/src/providers/integrations/trae/trae-quota.ts +103 -21
  255. package/src/providers/integrations/trae/trae-realm.ts +36 -15
  256. package/src/providers/integrations/trae/trae.ts +97 -7
  257. package/src/providers/operations/account-error-classification.ts +66 -1
  258. package/src/providers/operations/account-health-service.ts +192 -26
  259. package/src/providers/operations/account-refresh-status.ts +284 -0
  260. package/src/providers/operations/account-tier.ts +67 -0
  261. package/src/providers/operations/client-versions.ts +37 -99
  262. package/src/providers/operations/cooldown-rules.ts +61 -0
  263. package/src/providers/operations/provider-catalog-seeder.ts +4 -0
  264. package/src/providers/provider-contracts.ts +29 -0
  265. package/src/providers/provider-metadata.ts +59 -4
  266. package/src/providers/provider-model-definition.ts +36 -0
  267. package/src/providers/quota/refresh.ts +21 -0
  268. package/src/security/abuse.ts +71 -0
  269. package/src/transport/dispatch/proxy-request.ts +1 -0
  270. package/src/transport/dispatch/streaming/stream.ts +1 -0
  271. package/src/transport/dispatch/upstream.ts +4 -1
  272. package/src/transport/failure-policy.ts +113 -7
  273. package/src/transport/routing/router.ts +25 -1
  274. package/src/transport/surface/messages/adapter.ts +2 -1
  275. package/src/transport/surface/responses/encode.ts +12 -1
  276. package/src/workers/daily-checkin.ts +1 -1
  277. package/src/workers/quota-refresh-sweep.ts +1 -1
  278. package/src/workers/scheduler.ts +22 -4
  279. package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
  280. package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
  281. package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
  282. package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
  283. package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
  284. package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
  285. package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
  286. package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
  287. package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
  288. package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
  289. package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
  290. package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
  291. package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
  292. package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
  293. package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
  294. package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
  295. package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
  296. package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
  297. package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
  298. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
  299. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
  300. package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
  301. package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
  302. package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
  303. package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
  304. package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
  305. package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
  306. package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
  307. package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
  308. package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
  309. package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
  310. package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
  311. package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
  312. package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
  313. package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
  314. package/dist/dashboard/assets/assert-CidQVoNo.js +0 -1
  315. package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
  316. package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
  317. package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
  318. package/dist/dashboard/assets/brand/bansos_page.png +0 -0
  319. package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
  320. package/dist/dashboard/assets/brand/favicon.jpg +0 -0
  321. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  322. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  323. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  324. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  325. package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
  326. package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
  327. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
  328. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
  329. package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
  330. package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
  331. package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
  332. package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
  333. package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
  334. package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
  335. package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
  336. package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
  337. package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
  338. package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
  339. package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
  340. package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
  341. package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
  342. package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
  343. package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
  344. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
  345. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  346. package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
  347. package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
  348. package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
  349. package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
  350. package/dist/dashboard/assets/query-keys-YSoQOUh6.js.gz +0 -0
  351. package/dist/dashboard/assets/routing-fnCsxgNO.js +0 -1
  352. package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
  353. package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
  354. package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
  355. package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
  356. package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
  357. package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
  358. package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
  359. package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
  360. package/dist/dashboard/console-backgrounds.jpg +0 -0
  361. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  362. package/dist/dashboard/donation/qris-risun-marke.png +0 -0
  363. package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
  364. package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
  365. package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
  366. package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
  367. package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
  368. package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
  369. package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
  370. /package/dist/dashboard/assets/{app-CTxoqyYB.js → app-B7kIWFm5.js} +0 -0
  371. /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-B7kIWFm5.js.gz} +0 -0
@@ -1,398 +1,165 @@
1
1
  /**
2
- * Qoder native machine identity (UMID) — the genuine SG bridge via umidpack.
2
+ * Qoder OS-derived machine identity — donor-style deterministic derivation.
3
3
  *
4
- * Research record (2026-10-30): same-account controls found that the daily
5
- * CREDITS campaign does not gate grants on machine identity. This module
6
- * prefers the vendor bridge for stable native identity and seed replay, with
7
- * a deterministic generated fallback when no bridge is available.
4
+ * The vendor bridge (runtime-info / umidpack) is no longer vendored or
5
+ * executed. This module derives the machine identity with the same *shape*
6
+ * and *derivation pattern* as the donor hub's fingerprint module:
8
7
  *
9
- * Seed semantics (verified live): the Linux ELF resolves the user home via
10
- * the passwd entry — it ignores `$HOME`/`XDG_CONFIG_HOME`, so the seed file
11
- * is always `/home/<user>/.config/.locale_cfg`, one global file per Linux
12
- * user. Per-account isolation therefore lives in the DATABASE (each account
13
- * stores its own 350-byte seed) plus a flock-serialized bridge section:
14
- * mint = wipe → run → capture seed+token; replay = write stored seed → run.
15
- * Verified cycle (umidpack ELF under WSL): mint A, mint B (distinct),
16
- * replay A ✓, replay B ✓, replay A again ✓.
8
+ * - `derive_id(uid, salt)` → a UUIDv4-shaped id (version nibble `4`,
9
+ * variant nibble `a`), stable per (uid, salt).
10
+ * - `derive_machine_token(uid)` → a base64url-looking 43-char token
11
+ * (sha512-derived).
12
+ * - `derive_machine_type(uid)` → 18 hex chars.
17
13
  *
18
- * Platform behavior:
19
- * win32 — the exe is hardware-bound: one identity per machine, no seed.
20
- * linux — direct spawn of the umidpack ELF, serialized seed file.
21
- * darwin — the Mach-O runs directly; seed path is the macOS user home.
22
- * win32 + WSL (this repo's primary deployment) — the ELF runs via WSL with
23
- * flock serialization; the bridge binary is staged into /tmp once.
14
+ * The donor salted with the account uid alone. We salt with the **OS
15
+ * fingerprint + account uid** instead: the fingerprint keeps the identity
16
+ * host-stable (one machine = one base), and the uid keeps accounts
17
+ * isolated on the same host — the same collision-avoidance property the
18
+ * native bridge had (per-machine hardware identity, but per-account seeds).
24
19
  *
25
- * The generated path remains a fallback for hosts with no usable bridge. It
26
- * produces deterministic, well-shaped tokens but is not an SG identity. Live
27
- * controls showed that machine identity does not gate daily CREDITS grants.
28
- *
29
- * Bridge CLI (donor-verified):
30
- * linux : runtime-info <env>
31
- * darwin: printf '{"account":"<uid>"}\n' | runtime-info <env> --account-stdin
32
- * win32 : runtime-info.exe <env> [--account-stdin]
20
+ * The result is deterministic, offline, and never touches the network. It is
21
+ * not an Alibaba SG-signed token — it is a spoofed native-shaped identity.
33
22
  */
34
- import { spawnSync } from "node:child_process";
35
23
  import { createHash } from "node:crypto";
36
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
37
- import { tmpdir } from "node:os";
38
- import { join } from "node:path";
39
- import { log } from "../../../observability/logger";
24
+ import { readFileSync } from "node:fs";
25
+ import {
26
+ arch as osArch,
27
+ cpus,
28
+ hostname,
29
+ platform as osPlatform,
30
+ release as osRelease,
31
+ totalmem,
32
+ userInfo,
33
+ } from "node:os";
40
34
  import { qoderMachineHostname, qoderMachineOs } from "../../operations/cli-platform";
41
35
 
42
- /** Environment code: an upstream "region/flavor", not a device identity. */
43
- const ENV_CODE = "3";
44
-
45
- /** One native identity sample (same shape the bridge prints). */
36
+ /** One machine identity sample (same shape the bridge printed). */
46
37
  export interface QoderNativeIdentity {
47
38
  readonly machineToken: string;
48
39
  readonly machineType: string;
49
40
  readonly machineCode: string;
50
41
  readonly isVm: boolean;
51
- readonly source: "runtime-info" | "generated";
42
+ readonly source: "runtime-info" | "generated" | "os";
52
43
  }
53
44
 
54
- /** Length of the base64url payload after the `P1gA` prefix (token total 88). */
55
- const TOKEN_PAYLOAD_LENGTH = 84;
56
- /** Hex length of machineType / machineCode in the bridge's output. */
45
+ /** Hex length of machineType / machineCode (donor `derive_id` output, dashes stripped). */
57
46
  const MACHINE_TYPE_LENGTH = 18;
58
47
  const MACHINE_CODE_LENGTH = 18;
48
+ /** base64url token length after the sha512 digest (donor `derive_machine_token`). */
49
+ const MACHINE_TOKEN_LENGTH = 43;
59
50
 
60
- /** Where the umidpack binaries live, relative to the repo root. */
61
- export function umidpackDir(): string {
62
- return join(process.cwd(), "vendor", "qoder-umid", "umidpack");
63
- }
64
-
65
- /** The vendored mini-ELF tarball (static glibc bundle for containers). */
66
- export function umidMiniTarball(): string {
67
- return join(process.cwd(), "vendor", "qoder-umid", "qoder-umid-mini.tar.gz");
68
- }
69
-
70
- /**
71
- * Staging directory for the extracted mini-ELF bundle. Uses a per-user cache
72
- * dir (respecting `XDG_CACHE_HOME` on Linux) so a container does not need to
73
- * carry the extracted tree, and the repo stays clean.
74
- */
75
- export function umidMiniDir(): string {
76
- const base = process.env.XDG_CACHE_HOME?.trim() || join(process.env.HOME ?? tmpdir(), ".cache");
77
- return join(base, "cartethyia", "umid-mini");
78
- }
79
-
80
- let miniExtracted = false;
81
-
82
- /** Extracts `qoder-umid-mini.tar.gz` once into {@link umidMiniDir}. */
83
- export function ensureUmidMiniExtracted(): boolean {
84
- const tar = umidMiniTarball();
85
- const out = umidMiniDir();
86
- if (!existsSync(tar)) return false;
87
- if (existsSync(join(out, "opt", "umid", "runtime-info")) && miniExtracted) return true;
51
+ /** Reads a file if it exists, trimming whitespace; empty string otherwise. */
52
+ function readTrimmed(path: string): string {
88
53
  try {
89
- mkdirSync(out, { recursive: true });
90
- // Re-extract on empty/missing target only; leave existing tree in place.
91
- if (!existsSync(join(out, "opt", "umid", "runtime-info"))) {
92
- const r = spawnSync("tar", ["-xzf", tar, "-C", out], { encoding: "utf8", timeout: 30_000 });
93
- if (r.status !== 0) {
94
- log.warn(`[qoder] umid mini extract failed: ${String(r.stderr ?? "").slice(0, 300)}`);
95
- return false;
96
- }
97
- }
98
- const bin = join(out, "opt", "umid", "runtime-info");
99
- if (existsSync(bin)) chmodSync(bin, 0o755);
100
- miniExtracted = true;
101
- return true;
102
- } catch (error) {
103
- log.warn("[qoder] umid mini extract error", error as Error);
104
- return false;
105
- }
106
- }
107
-
108
- /** WSL-side staging/seed paths for the Linux bridge on a Windows host. */
109
- const WSL_BIN = "/tmp/umidpack/runtime-info";
110
- const WSL_SEED = "/home/risun/.config/.locale_cfg";
111
- const WSL_LOCK = "/tmp/umidpack/bridge.lock";
112
-
113
- type Bridge = { kind: "elf" | "macho" | "pe" | "wsl-elf" | "mini-elf" };
114
-
115
- /** True when this process runs inside a container (Docker/Podman). */
116
- function isContainerized(): boolean {
117
- if (existsSync(join("/", ".dockerenv")) || existsSync(join("/", ".containerenv"))) return true;
118
- try {
119
- const cgroup = readFileSync("/proc/1/cgroup", "utf8");
120
- return /(?:docker|containerd|podman|kubepods)/i.test(cgroup);
54
+ return readFileSync(path, "utf8").trim();
121
55
  } catch {
122
- return false;
56
+ return "";
123
57
  }
124
58
  }
125
59
 
126
- /** Picks the bridge for this host; `null` when nothing genuine can run. */
127
- function pickBridge(): Bridge | null {
128
- if (process.platform === "win32") {
129
- // Prefer the WSL ELF (seed-capable → per-account identities); fall back
130
- // to the Windows exe pair (hardware-bound, one identity per machine).
131
- const elf = join(umidpackDir(), "elf-x86_64", "runtime-info");
132
- if (existsSync(elf)) return { kind: "wsl-elf" };
133
- const exe = join(umidpackDir(), "runtime-info.exe");
134
- const dll = join(umidpackDir(), "sgsdk.dll");
135
- if (existsSync(exe) && existsSync(dll)) return { kind: "pe" };
136
- // Windows has no native mini-ELF runner; WSL may still be present.
137
- return ensureUmidMiniExtracted() ? { kind: "wsl-elf" } : null;
138
- }
139
- if (process.platform === "darwin") {
140
- const arch = process.arch === "arm64" ? "macho-arm64" : "macho-x86_64";
141
- // Prefer the re-signed adhoc `.clean` binary (DYLD-spoofable); the stock
142
- // vendored binary is Hardened Runtime and ignores DYLD_INSERT_LIBRARIES.
143
- const clean = join(umidpackDir(), arch, "runtime-info.clean");
144
- if (existsSync(clean)) return { kind: "macho" };
145
- return existsSync(join(umidpackDir(), arch, "runtime-info")) ? { kind: "macho" } : null;
146
- }
147
- // Linux. Containers (Docker/K8s/Podman) prefer the mini-ELF bundle: it ships
148
- // a static glibc tree and mints tokens with `isVm:false`, so a containerized
149
- // deployment is not flagged as a VM. Set CARTETHYIA_QODER_UMID_MINI=1 to
150
- // force it on any Linux host, or =0 to disable container detection.
151
- const miniForced = process.env.CARTETHYIA_QODER_UMID_MINI;
152
- const wantMini =
153
- miniForced === "1" || (miniForced !== "0" && isContainerized());
154
- if (wantMini && process.arch === "x64" && ensureUmidMiniExtracted()) {
155
- return { kind: "mini-elf" };
60
+ /** Best-effort machine id per platform (empty when unavailable without a spawn). */
61
+ function machineId(): string {
62
+ if (process.platform === "linux") {
63
+ return (
64
+ readTrimmed("/etc/machine-id") ||
65
+ readTrimmed("/var/lib/dbus/machine-id") ||
66
+ readTrimmed("/sys/class/dmi/id/product_uuid")
67
+ );
156
68
  }
157
- const arch = process.arch === "arm64" ? "elf-aarch64" : "elf-x86_64";
158
- if (existsSync(join(umidpackDir(), arch, "runtime-info"))) return { kind: "elf" };
159
- if (existsSync(join(umidpackDir(), "elf-x86_64", "runtime-info"))) return { kind: "elf" };
160
- // Linux without a native vendored ELF (e.g. a slim container with no mini):
161
- // fall back to the mini-ELF bundle when it extracts.
162
- if (ensureUmidMiniExtracted() && process.arch === "x64") return { kind: "mini-elf" };
163
- return null;
69
+ return "";
164
70
  }
165
71
 
166
- /** Generated (software) identity — deterministic per account id, NOT SG-signed. */
167
- export function mintQoderGeneratedIdentity(accountId: string): QoderNativeIdentity {
168
- const first = createHash("sha256").update(accountId).digest("base64url");
169
- const second = createHash("sha256").update(`${accountId}:${first}`).digest("base64url");
170
- const token = `P1gA${`${first}${second}`.slice(0, TOKEN_PAYLOAD_LENGTH)}`;
171
- return {
172
- machineToken: token,
173
- machineType: createHash("sha256").update(`${accountId}:type`).digest("hex").slice(0, MACHINE_TYPE_LENGTH),
174
- machineCode: createHash("sha256").update(`${accountId}:code`).digest("hex").slice(0, MACHINE_CODE_LENGTH),
175
- isVm: false,
176
- source: "generated",
177
- };
72
+ /** Collects a stable, host-unique fingerprint string (the salt base). */
73
+ export function collectOsFingerprint(): string {
74
+ const parts: string[] = [
75
+ hostname(),
76
+ osPlatform(),
77
+ osArch(),
78
+ osRelease(),
79
+ String(cpus().length),
80
+ String(Math.floor(totalmem() / (1024 * 1024))),
81
+ qoderMachineOs(),
82
+ qoderMachineHostname(),
83
+ ];
84
+ const mid = machineId();
85
+ if (mid) parts.push(mid);
86
+ const user = userInfo().username;
87
+ if (user) parts.push(user);
88
+ return parts.join("\n");
178
89
  }
179
90
 
180
- /** Parse one bridge JSON line into an identity; null on any mismatch. */
181
- function parseBridgeLine(stdout: string): QoderNativeIdentity | null {
182
- const line = stdout.split(/\r?\n/).find((l) => l.startsWith("{"));
183
- if (!line) return null;
184
- try {
185
- const rec = JSON.parse(line) as Record<string, unknown>;
186
- const machineToken = String(rec.machineToken ?? "").trim();
187
- const machineType = String(rec.machineType ?? "").trim();
188
- const machineCode = String(rec.machineCode ?? "").trim();
189
- if (!machineToken || !machineType || !machineCode) return null;
190
- const vmInfo = rec.vmInfo;
191
- const isVm = typeof vmInfo === "object" && vmInfo !== null && (vmInfo as Record<string, unknown>).isVm === true;
192
- return { machineToken, machineType, machineCode, isVm, source: "runtime-info" };
193
- } catch {
194
- return null;
195
- }
91
+ /** Donor `derive_id`: md5(salt:uid) → UUIDv4-shaped id (version 4, variant a). */
92
+ function deriveId(uid: string, salt: string): string {
93
+ const seed = `${salt}:${uid || "anonymous"}`;
94
+ let h = createHash("md5").update(seed).digest("hex");
95
+ // Force the UUIDv4 version (13th nibble) and variant (17th nibble).
96
+ h = h.slice(0, 12) + "4" + h.slice(13, 16) + "a" + h.slice(17);
97
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
196
98
  }
197
99
 
198
- /** Stage the ELF into the WSL filesystem once (idempotent, fast after first). */
199
- function ensureWslStaged(): void {
200
- const src = join(umidpackDir(), "elf-x86_64", "runtime-info").replace(/\\/g, "/");
201
- const drive = /^([A-Za-z]):/.exec(src);
202
- const wslSrc = drive ? `/mnt/${drive[1]!.toLowerCase()}${src.slice(2)}` : src;
203
- wsl(
204
- `mkdir -p /tmp/umidpack && cp "${wslSrc}" ${WSL_BIN} && chmod +x ${WSL_BIN} && ` +
205
- `mkdir -p $(dirname ${WSL_SEED})`,
206
- );
100
+ /** Donor `derive_machine_token`: sha512 → base64url, 43 chars. */
101
+ function deriveMachineToken(uid: string, salt: string): string {
102
+ const raw = createHash("sha512").update(`machinetoken:${salt}:${uid}`).digest();
103
+ return raw.toString("base64url").slice(0, MACHINE_TOKEN_LENGTH);
207
104
  }
208
105
 
209
- function wsl(script: string, timeout = 120_000): string {
210
- const r = spawnSync("wsl", ["-e", "bash", "-lc", script], { encoding: "utf8", timeout, windowsHide: true });
211
- return String(r.stdout ?? "");
106
+ /** Donor `derive_machine_type`: derive_id without dashes, 18 chars. */
107
+ function deriveMachineType(uid: string, salt: string): string {
108
+ return deriveId(uid, `machinetype:${salt}`).replaceAll("-", "").slice(0, MACHINE_TYPE_LENGTH);
212
109
  }
213
110
 
214
111
  /**
215
- * Best-effort make a POSIX bridge binary executable before spawning it. The
216
- * umidpack binaries are committed without the exec bit (git mode 100644) and
217
- * nothing else in the delivery path sets it — a Docker image or a fresh clone
218
- * on Linux/macOS would otherwise fail to spawn them (EACCES -> "[qoder] elf
219
- * mint failed"). Idempotent; if it cannot set the bit, `spawnSync` reports
220
- * the real failure as before.
112
+ * Derives a machine identity for one account from the host OS fingerprint +
113
+ * account uid. Deterministic: same host + same account → same identity.
221
114
  */
222
- export function ensurePosixExecutable(file: string): void {
223
- try {
224
- chmodSync(file, 0o755);
225
- } catch {
226
- /* spawn will report the actual error */
227
- }
115
+ export function mintQoderOsIdentity(accountId: string): QoderNativeIdentity {
116
+ const salt = collectOsFingerprint();
117
+ const uid = accountId || "anonymous";
118
+ return {
119
+ machineToken: deriveMachineToken(uid, salt),
120
+ machineType: deriveMachineType(uid, salt),
121
+ machineCode: deriveId(uid, `machinecode:${salt}`).replaceAll("-", "").slice(0, MACHINE_CODE_LENGTH),
122
+ isVm: false,
123
+ source: "os",
124
+ };
228
125
  }
229
126
 
230
- /** Run the bridge inside WSL under flock; returns the identity or null. */
231
-
232
- function seedPath(): string {
233
- if (process.platform === "win32") return WSL_SEED;
234
- const home = process.env.HOME ?? "";
235
- return join(home, ".config", ".locale_cfg");
127
+ /** Legacy alias retained for callers that still import the generated mint. */
128
+ export function mintQoderGeneratedIdentity(accountId: string): QoderNativeIdentity {
129
+ return mintQoderOsIdentity(accountId);
236
130
  }
237
131
 
238
- /**
239
- * Mints a fresh native identity: wipe the seed (under the lock), run the
240
- * bridge, capture the identity AND the seed it wrote. The seed is required
241
- * for later replay of this same native identity. Returns `null` when the
242
- * bridge fails; falls back to the generated identity only when no bridge
243
- * exists.
244
- */
245
- export function mintQoderNativeIdentity(accountId: string): { identity: QoderNativeIdentity; seed: string } | null {
246
- const bridge = pickBridge();
247
- if (!bridge) {
248
- log.warn("[qoder] no native bridge for this host — using generated identity fallback");
249
- return { identity: mintQoderGeneratedIdentity(accountId), seed: "" };
250
- }
251
-
252
- if (bridge.kind === "wsl-elf") {
253
- ensureWslStaged();
254
- const out = wsl(
255
- `exec 9>${WSL_LOCK}; flock 9; rm -f ${WSL_SEED}; ${WSL_BIN} ${ENV_CODE}`,
256
- );
257
- const identity = parseBridgeLine(out);
258
- if (!identity) { log.warn("[qoder] wsl mint failed"); return null; }
259
- const seed = wsl(`cat ${WSL_SEED}`);
260
- return { identity, seed };
261
- }
262
-
263
- if (bridge.kind === "elf") {
264
- const exe = join(umidpackDir(), process.arch === "arm64" ? "elf-aarch64" : "elf-x86_64", "runtime-info");
265
- ensurePosixExecutable(exe);
266
- const seed = seedPath();
267
- const dir = seed.slice(0, seed.lastIndexOf("/"));
268
- mkdirSync(dir, { recursive: true });
269
- try { spawnSync("rm", ["-f", seed]); } catch { /* ignore */ }
270
- const r = spawnSync(exe, [ENV_CODE], { encoding: "utf8", timeout: 25_000 });
271
- const identity = parseBridgeLine(String(r.stdout ?? ""));
272
- if (!identity) { log.warn("[qoder] elf mint failed"); return null; }
273
- return { identity, seed: existsSync(seed) ? readFileSync(seed, "utf8") : "" };
274
- }
275
-
276
- if (bridge.kind === "macho") {
277
- const arch = process.arch === "arm64" ? "macho-arm64" : "macho-x86_64";
278
- const exe = join(umidpackDir(), arch, "runtime-info");
279
- ensurePosixExecutable(exe);
280
- const seed = seedPath();
281
- const dir = seed.slice(0, seed.lastIndexOf("/"));
282
- mkdirSync(dir, { recursive: true });
283
- try { spawnSync("rm", ["-f", seed]); } catch { /* ignore */ }
284
- const r = spawnSync(exe, [ENV_CODE, "--account-stdin"], {
285
- input: `${JSON.stringify({ account: accountId })}\n`,
286
- encoding: "utf8",
287
- timeout: 25_000,
288
- });
289
- const identity = parseBridgeLine(String(r.stdout ?? ""));
290
- if (!identity) { log.warn("[qoder] macho mint failed"); return null; }
291
- return { identity, seed: existsSync(seed) ? readFileSync(seed, "utf8") : "" };
292
- }
293
-
294
- if (bridge.kind === "mini-elf") {
295
- const exe = join(umidMiniDir(), "opt", "umid", "runtime-info");
296
- ensurePosixExecutable(exe);
297
- const seed = seedPath();
298
- const dir = seed.slice(0, seed.lastIndexOf("/"));
299
- mkdirSync(dir, { recursive: true });
300
- try { spawnSync("rm", ["-f", seed]); } catch { /* ignore */ }
301
- const r = spawnSync(exe, [ENV_CODE], {
302
- encoding: "utf8",
303
- timeout: 25_000,
304
- env: { ...process.env, LD_LIBRARY_PATH: join(umidMiniDir(), "lib", "x86_64-linux-gnu") },
305
- });
306
- const identity = parseBridgeLine(String(r.stdout ?? ""));
307
- if (!identity) { log.warn("[qoder] mini-elf mint failed"); return null; }
308
- return { identity, seed: existsSync(seed) ? readFileSync(seed, "utf8") : "" };
309
- }
310
-
311
- // pe — hardware-bound; no seed concept on Windows.
312
- const exe = join(umidpackDir(), "runtime-info.exe");
313
- const r = spawnSync(exe, [ENV_CODE], { encoding: "utf8", timeout: 30_000, windowsHide: true, cwd: umidpackDir() });
314
- const identity = parseBridgeLine(String(r.stdout ?? ""));
315
- if (!identity) { log.warn("[qoder] pe mint failed"); return null; }
316
- return { identity, seed: "" };
132
+ /** No bridge exists anymore; the OS mint is the only path. */
133
+ export function mintQoderNativeIdentity(accountId = ""): QoderNativeIdentity {
134
+ return mintQoderOsIdentity(accountId);
317
135
  }
318
136
 
319
- /**
320
- * Replays an identity from a stored seed: materialize the seed at the bridge's
321
- * fixed path (under the lock) and re-run — the caller verifies the token
322
- * matches the stored record. Returns `null` when no seed is available, the
323
- * host cannot replay (Windows exe), or the bridge failed.
324
- */
325
- export function replayQoderNativeIdentity(seed: string, accountId: string): QoderNativeIdentity | null {
326
- if (!seed) return null;
327
- const bridge = pickBridge();
328
- if (!bridge) return null;
329
-
330
- if (bridge.kind === "wsl-elf") {
331
- ensureWslStaged();
332
- const quoted = seed.replace(/'/g, `'\\''`);
333
- const out = wsl(
334
- `exec 9>${WSL_LOCK}; flock 9; printf '%s' '${quoted}' > ${WSL_SEED}; ${WSL_BIN} ${ENV_CODE}`,
335
- );
336
- return parseBridgeLine(out);
337
- }
338
-
339
- if (bridge.kind === "elf") {
340
- const exe = join(umidpackDir(), process.arch === "arm64" ? "elf-aarch64" : "elf-x86_64", "runtime-info");
341
- ensurePosixExecutable(exe);
342
- const seed = seedPath();
343
- writeFileSync(seed, seed, "utf8");
344
- const r = spawnSync(exe, [ENV_CODE], { encoding: "utf8", timeout: 25_000 });
345
- return parseBridgeLine(String(r.stdout ?? ""));
346
- }
347
-
348
- if (bridge.kind === "macho") {
349
- const arch = process.arch === "arm64" ? "macho-arm64" : "macho-x86_64";
350
- const exe = join(umidpackDir(), arch, "runtime-info");
351
- ensurePosixExecutable(exe);
352
- const seedPathStr = seedPath();
353
- writeFileSync(seedPathStr, seed, "utf8");
354
- const r = spawnSync(exe, [ENV_CODE, "--account-stdin"], {
355
- input: `${JSON.stringify({ account: accountId })}\n`,
356
- encoding: "utf8",
357
- timeout: 25_000,
358
- });
359
- return parseBridgeLine(String(r.stdout ?? ""));
360
- }
361
-
362
- if (bridge.kind === "mini-elf") {
363
- const exe = join(umidMiniDir(), "opt", "umid", "runtime-info");
364
- ensurePosixExecutable(exe);
365
- const seedPathStr = seedPath();
366
- writeFileSync(seedPathStr, seed, "utf8");
367
- const r = spawnSync(exe, [ENV_CODE], {
368
- encoding: "utf8",
369
- timeout: 25_000,
370
- env: { ...process.env, LD_LIBRARY_PATH: join(umidMiniDir(), "lib", "x86_64-linux-gnu") },
371
- });
372
- return parseBridgeLine(String(r.stdout ?? ""));
373
- }
374
-
375
- return null; // pe: cannot replay a seed on a hardware-bound identity
137
+ /** Replay is a no-op: the OS identity is deterministic and host-bound. */
138
+ export function replayQoderNativeIdentity(_seed: string, accountId = ""): QoderNativeIdentity | null {
139
+ return mintQoderOsIdentity(accountId);
376
140
  }
377
141
 
378
142
  /**
379
143
  * The six native machine headers for one identity.
380
144
  *
381
- * The upstream treats `cosy-machineid` as a stable UUID-shaped machine id
382
- * (the desktop client caches it; the donor hub derives a UUIDv4 from the
383
- * account uid). The native machineToken/Type/Code come from the UMID bridge.
384
- * The OS and hostname are derived from the real runtime (`qoderMachineOs` /
385
- * `qoderMachineHostname`), not hardcoded — the campaign surface fingerprint
386
- * must match the actual client (verified live 2026-11-04).
145
+ * The upstream treats `cosy-machineid` as a stable UUID-shaped machine id.
146
+ * OS-derived identities (source "os") keep the full header set — they are
147
+ * host-stable, per-account isolated, and shaped like the bridge output.
148
+ * Generated identities (source "generated") do NOT send the full set: the
149
+ * upstream filters the daily CREDITS campaign when a full set of derived
150
+ * headers appears (donor issue #10).
387
151
  */
388
152
  export function qoderMachineHeaders(identity: QoderNativeIdentity, machineId?: string): Record<string, string> {
389
153
  const mid = machineId && machineId.length > 0 ? machineId : identity.machineToken;
390
- return {
154
+ const headers: Record<string, string> = {
391
155
  "cosy-machineid": mid,
392
- "cosy-machinetoken": identity.machineToken,
393
- "cosy-machinetype": identity.machineType,
394
- "cosy-machinecode": identity.machineCode,
395
156
  "cosy-machineos": qoderMachineOs(),
396
157
  "cosy-machinehostname": qoderMachineHostname(),
397
158
  };
159
+ if (identity.source !== "generated") {
160
+ headers["cosy-machinetoken"] = identity.machineToken;
161
+ headers["cosy-machinetype"] = identity.machineType;
162
+ headers["cosy-machinecode"] = identity.machineCode;
163
+ }
164
+ return headers;
398
165
  }
@@ -10,6 +10,34 @@
10
10
  // is deliberately static — Qoder publishes no endpoint that resolves a name to
11
11
  // a slot the way Copilot's `/auto` does, so there is nothing to ask at runtime.
12
12
 
13
+ import type { ModelWarning } from "../../provider-model-definition";
14
+
15
+ /**
16
+ * Three provider-level caveats (D37), attached to every `qoder`/`qodercn` row —
17
+ * static, virtual, and discovered alike. These are deliberately statements of
18
+ * possibility, not per-model claims: the provider may route a slot to a
19
+ * different model, its cache may be unreliable, and a plan/transport decision
20
+ * may refuse a request. No roster row is asserted to have any of these
21
+ * behaviours individually.
22
+ */
23
+ export const QODER_PROVIDER_WARNINGS: readonly ModelWarning[] = [
24
+ {
25
+ kind: "fallback_model",
26
+ message: "Provider may fall back to another model for this slot.",
27
+ severity: "warn",
28
+ },
29
+ {
30
+ kind: "cache_reliability",
31
+ message: "Cache reliability may be degraded for this provider.",
32
+ severity: "warn",
33
+ },
34
+ {
35
+ kind: "model_refusal",
36
+ message: "This provider may refuse certain model requests (plan/transport).",
37
+ severity: "warn",
38
+ },
39
+ ];
40
+
13
41
  /** A virtual id and the roster key it stands for. */
14
42
  export interface QoderVirtualModel {
15
43
  /** The id a caller sends and the catalog publishes. */
@@ -43,7 +71,11 @@ export const QODER_VIRTUAL_MODELS: readonly QoderVirtualModel[] = [
43
71
  { id: "cantus", target: "cmodel", displayName: "Cantus" },
44
72
  { id: "sonus", target: "smodel", displayName: "Sonus" },
45
73
  { id: "qwen3.8-max", target: "qmodel_38max", displayName: "Qwen3.8-Max" },
46
- { id: "qwen3.8-flash", target: "qfmodel", displayName: "Qwen3.8-Flash" },
74
+ // `qwen3.8-flash` is the free-tier entry point over the `qfmodel` slot.
75
+ // Upstream's live `is_free` on this slot is a plan-tier flag rather than a
76
+ // zero-cost tier, so the static roster deliberately does not state it; the
77
+ // free badge is applied here, the same way `lite` overrides `qmodel`.
78
+ { id: "qwen3.8-flash", target: "qfmodel", displayName: "Qwen3.8-Flash", free: true },
47
79
  { id: "qwen3.7-max", target: "qmodel_latest", displayName: "Qwen3.7-Max" },
48
80
  { id: "qwen3.7-plus", target: "qmodel", displayName: "Qwen3.7-Plus" },
49
81
  { id: "kimi-k3", target: "kmodel_latest", displayName: "Kimi-K3.1-Pro" },
@@ -115,17 +115,14 @@ export type { QoderUserInfo, QoderOAuthState } from "./qoder-oauth";
115
115
  // Quota
116
116
  export { fetchQoderQuota, fetchQoderCnQuota } from "./qoder-quota";
117
117
 
118
- // UMID / native identity
118
+ // UMID / OS-derived machine identity
119
119
  export {
120
+ mintQoderOsIdentity,
121
+ collectOsFingerprint,
120
122
  mintQoderNativeIdentity,
121
123
  replayQoderNativeIdentity,
122
124
  mintQoderGeneratedIdentity,
123
125
  qoderMachineHeaders,
124
- ensurePosixExecutable,
125
- umidpackDir,
126
- umidMiniTarball,
127
- umidMiniDir,
128
- ensureUmidMiniExtracted,
129
126
  } from "./qoder-umid";
130
127
  export type { QoderNativeIdentity } from "./qoder-umid";
131
128
  export {
@@ -37,7 +37,7 @@ export interface TraeModelRow {
37
37
  /** Which upstream endpoint serves a row. */
38
38
  export type TraeSurface = "chat" | "agent";
39
39
 
40
- /** CN roster: 20 chat-face models from the donor's client-state snapshot. */
40
+ /** CN roster: 20 chat-face models from the client-state snapshot. */
41
41
  const TRAE_CN_ROWS: readonly TraeModelRow[] = [
42
42
  { id: "Doubao-Seed-Code", displayName: "Seed-Code", ctx: 256000, out: 224000, vision: true, reasoning: true },
43
43
  { id: "DeepSeek-V4-Flash-Official", displayName: "DeepSeek-V4-Flash", ctx: 1000000, out: 936000, vision: false, reasoning: true },
@@ -100,21 +100,16 @@ const TRAE_CN_ROWS: readonly TraeModelRow[] = [
100
100
  */
101
101
  const TRAE_INTL_ROWS: readonly TraeModelRow[] = [
102
102
  { id: "gpt-5.4", displayName: "GPT-5.4", ctx: 1_000_000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
103
- { id: "gpt-5.2", displayName: "GPT-5.2", ctx: 272000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
104
103
  { id: "gpt-5.2-codex-paygo", displayName: "GPT-5.2-Codex", ctx: 272000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
105
- { id: "gpt-5.1-paygo", displayName: "GPT-5.1", ctx: 272000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
106
- { id: "gpt-5-paygo", displayName: "GPT-5", ctx: 272000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
107
104
  { id: "Dola-Seed-2.0-Code", displayName: "Seed-2.1-Turbo", ctx: 1000000, out: 131_072, vision: true, reasoning: true, surface: "agent" },
108
- { id: "deepseek-v4.1-flash", displayName: "DeepSeek-V4.1-Flash", ctx: 1000000, out: 384_000, vision: true, reasoning: true, surface: "agent" },
109
- { id: "deepseek-v4-flash-0731", displayName: "DeepSeek-V4-Flash", ctx: 1000000, out: 384_000, vision: false, reasoning: true, surface: "agent" },
110
- { id: "deepseek-v4-pro-0813", displayName: "DeepSeek-V4-Pro", ctx: 1000000, out: 384_000, vision: false, reasoning: true, surface: "agent" },
111
- { id: "kimi-k3", displayName: "Kimi-K3", ctx: 1000000, out: 131_072, vision: true, reasoning: true, surface: "agent" },
112
- { id: "kimi-k2.7-code", displayName: "Kimi-K2.7-Code", ctx: 1000000, out: 65_536, vision: true, reasoning: true, surface: "agent" },
113
- { id: "kimi-k2.5", displayName: "Kimi-K2.5", ctx: 200000, out: 262_144, vision: false, reasoning: true, surface: "agent" },
114
- { id: "gemini-3.1-pro", displayName: "Gemini-3.1-Pro-Preview", ctx: 1000000, out: 65_536, vision: true, reasoning: true, surface: "agent" },
115
- { id: "gemini-3-flash-solo", displayName: "Gemini-3-Flash-Preview", ctx: 1000000, out: 65_536, vision: true, reasoning: true, surface: "agent" },
116
- { id: "minimax-m3", displayName: "MiniMax-M3", ctx: 1000000, out: 512_000, vision: true, reasoning: true, surface: "agent" },
117
- { id: "minimax-m2.7", displayName: "MiniMax-M2.7", ctx: 200000, out: 131_072, vision: false, reasoning: true, surface: "agent" },
105
+ { id: "gemini-3.1-pro-paygo", displayName: "Gemini-3.1-Pro-PayGo", ctx: 1000000, out: 65_536, vision: true, reasoning: true, surface: "agent" },
106
+ // Search-agent configs from the live picker (batch_get_detail_param). They
107
+ // resolve to real chat models — gpt-5.4 / gpt-5.3-codex / gemini-3-flash —
108
+ // and accept the same tool-calling wire as any agent row, so their specs
109
+ // mirror the model they resolve to (verified live 2026-11-06).
110
+ { id: "search_agent_gpt-5.4", displayName: "Search Agent (GPT-5.4)", ctx: 1_000_000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
111
+ { id: "search_agent_gpt-5.3-codex", displayName: "Search Agent (GPT-5.3-Codex)", ctx: 272000, out: 128_000, vision: true, reasoning: true, surface: "agent" },
112
+ { id: "search_agent_gemini_3_pro_with_g3f", displayName: "Search Agent (Gemini-3-Flash)", ctx: 1000000, out: 65_536, vision: true, reasoning: true, surface: "agent" },
118
113
  ];
119
114
 
120
115
  function traeModels(rows: readonly TraeModelRow[], providerId: string): readonly ModelDefinition[] {