cartethyia 2.5.9 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/.env.example +15 -42
  2. package/README.md +11 -10
  3. package/dist/dashboard/assets/{BannedPage-Brvuj_Eb.js → BannedPage-l6XMnfr9.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-l6XMnfr9.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage-CqfXtI3y.js → CliToolDetailPage-DwOzAW45.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-DwOzAW45.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-GQeS91bg.js → CliToolsPage-BT3Up3QA.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-BT3Up3QA.js.gz +0 -0
  9. package/dist/dashboard/assets/{CombosPage-BDRsTXBB.js → CombosPage-6kYIUpzR.js} +1 -1
  10. package/dist/dashboard/assets/CombosPage-6kYIUpzR.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-zP8AFHX0.js → ConsoleLogPage-zRnj1mlR.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-zRnj1mlR.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-BmfrNZ14.js → CustomizationPage-C7m-H1Rz.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-C7m-H1Rz.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-DoreIgm8.js → LoginPage-CbphLvjg.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-CbphLvjg.js.gz +0 -0
  19. package/dist/dashboard/assets/{ModelPicker-C7pDb41R.js → ModelPicker-DVny4S5_.js} +1 -1
  20. package/dist/dashboard/assets/ModelPicker-DVny4S5_.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-BnoPgA7w.js → ProvidersPage-Dfb2896L.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-Dfb2896L.js.gz +0 -0
  27. package/dist/dashboard/assets/{ProxyPage-Bq_TGgdb.js → ProxyPage-BaCIdAUt.js} +1 -1
  28. package/dist/dashboard/assets/ProxyPage-BaCIdAUt.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-Day3mCOn.js → SetupPage-D4g6vOGc.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-D4g6vOGc.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-DQxllnB5.js → SortableList-C93i14BD.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-C93i14BD.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-uMExoWu1.js → StudioPage-SgQpymjm.js} +1 -1
  38. package/dist/dashboard/assets/{StudioPage-uMExoWu1.js.gz → StudioPage-SgQpymjm.js.gz} +0 -0
  39. package/dist/dashboard/assets/{UsagePage-DXa1oR-4.js → UsagePage-BFME-eba.js} +2 -2
  40. package/dist/dashboard/assets/UsagePage-BFME-eba.js.gz +0 -0
  41. package/dist/dashboard/assets/{api-keys-DQYLQxpW.js → api-keys-C23S9sgp.js} +1 -1
  42. package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
  43. package/dist/dashboard/assets/{app-BIt446yE.js → app-2KhtHCv9.js} +1 -1
  44. package/dist/dashboard/assets/{app-BIt446yE.js.gz → app-2KhtHCv9.js.gz} +0 -0
  45. package/dist/dashboard/assets/app-CEeaMHOy.css +2 -0
  46. package/dist/dashboard/assets/app-CEeaMHOy.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-C9FD_JwJ.js → assert-DU6qrMA_.js} +1 -1
  48. package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-CR72dasT.js → badge-CKsF123d.js} +1 -1
  50. package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-CI9_eSfO.js → banner-8j7uChA9.js} +1 -1
  52. package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
  53. package/dist/dashboard/assets/{card-DS7CQEsO.js → card-CdsSlWA3.js} +1 -1
  54. package/dist/dashboard/assets/card-CdsSlWA3.js.gz +0 -0
  55. package/dist/dashboard/assets/{cli-tools-CNqzrfdb.js → cli-tools-BaFUuFFF.js} +1 -1
  56. package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
  57. package/dist/dashboard/assets/{clipboard-button-611pSsaX.js → clipboard-button-uL5aYLfW.js} +1 -1
  58. package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
  59. package/dist/dashboard/assets/{dialog-k37exjNt.js → dialog-C07hr5_G.js} +1 -1
  60. package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
  61. package/dist/dashboard/assets/{drawer-CX7N8ucR.js → drawer-BPO1TcKH.js} +1 -1
  62. package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-CTP8AyiS.js → entry-Bz_CtDfC.js} +1 -1
  64. package/dist/dashboard/assets/entry-Bz_CtDfC.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-CwPRKk0d.js +4 -0
  66. package/dist/dashboard/assets/entry-CwPRKk0d.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-GJRbmrpA.js +1 -0
  68. package/dist/dashboard/assets/entry-GJRbmrpA.js.gz +0 -0
  69. package/dist/dashboard/assets/{github-badge-sltk1qUi.js → github-badge-DmQreSDd.js} +1 -1
  70. package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
  71. package/dist/dashboard/assets/{index-z3zDOSMM.js → index-Bblu6erR.js} +2 -2
  72. package/dist/dashboard/assets/index-Bblu6erR.js.gz +0 -0
  73. package/dist/dashboard/assets/{inline-BhY2sSnO.js → inline-C9dCYaBZ.js} +1 -1
  74. package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
  75. package/dist/dashboard/assets/{input-V1umFiBk.js → input-CjCnXweJ.js} +1 -1
  76. package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
  77. package/dist/dashboard/assets/{layout-BBOYycyS.js → layout-V6y8DAkl.js} +1 -1
  78. package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
  79. package/dist/dashboard/assets/{list-row-1zzZYM0B.js → list-row-CM1AaG_y.js} +1 -1
  80. package/dist/dashboard/assets/list-row-CM1AaG_y.js.gz +0 -0
  81. package/dist/dashboard/assets/{live-BivGfuUs.js → live-ta6GMb-8.js} +1 -1
  82. package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
  83. package/dist/dashboard/assets/{model-bans-CmffjLuG.js → model-bans-BmYTmbAk.js} +1 -1
  84. package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
  85. package/dist/dashboard/assets/{mutation-46P0oWMe.js → mutation-g_fduiNw.js} +1 -1
  86. package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
  87. package/dist/dashboard/assets/{numbers-DkfMR5Qs.js → numbers-BOevJzdz.js} +1 -1
  88. package/dist/dashboard/assets/numbers-BOevJzdz.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-BFhGpwR1.js → query-keys-UETqfytp.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
  91. package/dist/dashboard/assets/{routing-CAb4F37R.js → routing-BPUo-W8d.js} +1 -1
  92. package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
  93. package/dist/dashboard/assets/{select-C6MMiaio.js → select-C980c4cz.js} +1 -1
  94. package/dist/dashboard/assets/select-C980c4cz.js.gz +0 -0
  95. package/dist/dashboard/assets/{settings-DNX9sydi.js → settings--3hxSyry.js} +1 -1
  96. package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
  97. package/dist/dashboard/assets/{stack-BHTfXdz_.js → stack-_gfTdLVB.js} +1 -1
  98. package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
  99. package/dist/dashboard/assets/{state-mPDRlQkl.js → state-2c5V4zo7.js} +1 -1
  100. package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
  101. package/dist/dashboard/assets/{switch-DOmJxg7H.js → switch-Dkke7Naf.js} +1 -1
  102. package/dist/dashboard/assets/switch-Dkke7Naf.js.gz +0 -0
  103. package/dist/dashboard/assets/{useMutation-Dem0lXQj.js → useMutation-EDFRkn1i.js} +1 -1
  104. package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
  105. package/dist/dashboard/index.html +1 -1
  106. package/dist/dashboard/index.html.gz +0 -0
  107. package/dist/dashboard/precompressed-assets.json +51 -51
  108. package/migrations/README.md +52 -52
  109. package/migrations/full-postgres/0020_add_telemetry_event_analytics.sql +77 -0
  110. package/migrations/full-postgres/0021_add_api_key_concurrency_tolerance.sql +13 -0
  111. package/migrations/full-postgres/0022_add_inferhub_config_key.sql +17 -0
  112. package/migrations/full-postgres/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  113. package/migrations/lite-sqlite3/0020_add_telemetry_event_analytics.sql +69 -0
  114. package/migrations/lite-sqlite3/0021_add_api_key_concurrency_tolerance.sql +13 -0
  115. package/migrations/lite-sqlite3/0022_add_inferhub_config_key.sql +17 -0
  116. package/migrations/lite-sqlite3/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  117. package/package.json +96 -97
  118. package/scripts/cli/admin.ts +126 -125
  119. package/scripts/cli/autostart.ts +237 -237
  120. package/scripts/cli/background.ts +120 -110
  121. package/scripts/cli/bin/carte.cjs +8 -8
  122. package/scripts/cli/bin/cartethyia.cjs +167 -167
  123. package/scripts/cli/console-menu.ts +308 -275
  124. package/scripts/cli/controller.ts +145 -0
  125. package/scripts/cli/doctor.ts +1 -1
  126. package/scripts/cli/env.ts +99 -99
  127. package/scripts/cli/gateway.ts +264 -261
  128. package/scripts/{health.ts → cli/health.ts} +4 -4
  129. package/scripts/cli/instance.ts +234 -224
  130. package/scripts/cli/main.ts +188 -164
  131. package/scripts/cli/platform.ts +64 -64
  132. package/scripts/cli/prompt.ts +275 -107
  133. package/scripts/cli/services.ts +88 -88
  134. package/scripts/cli/setup.ts +445 -445
  135. package/scripts/cli/start.ts +85 -82
  136. package/scripts/cli/startup-signal.ts +23 -23
  137. package/scripts/cli/telemetry.ts +70 -0
  138. package/scripts/cli/tray/index.ts +263 -263
  139. package/scripts/cli/tray/windows.ps1 +107 -107
  140. package/scripts/cli/tray.ts +192 -208
  141. package/scripts/cli/update.ts +39 -39
  142. package/scripts/cli/version.ts +67 -67
  143. package/scripts/cli/wordmark.ts +58 -58
  144. package/src/boot/app.ts +16 -1
  145. package/src/boot/dependencies.ts +128 -25
  146. package/src/config/package-paths.ts +24 -0
  147. package/src/config/resources.ts +137 -0
  148. package/src/config/runtime.ts +133 -76
  149. package/src/config/spec.ts +30 -29
  150. package/src/config/telemetry.ts +0 -25
  151. package/src/console/api-keys/bucket-spend.ts +14 -17
  152. package/src/console/api-keys/contracts.ts +410 -410
  153. package/src/console/api-keys/routes.ts +12 -0
  154. package/src/console/audit/store.ts +2 -3
  155. package/src/console/auth/setup-service.ts +8 -1
  156. package/src/console/backup/routes.ts +7 -0
  157. package/src/console/backup/service.ts +463 -463
  158. package/src/console/backup/store.ts +16 -11
  159. package/src/console/backup/validate.ts +1 -4
  160. package/src/console/cli-tools/fs-ops.ts +18 -2
  161. package/src/console/data-management/contracts.ts +1 -8
  162. package/src/console/data-management/operations.ts +61 -48
  163. package/src/console/data-management/routes.ts +4 -2
  164. package/src/console/domain-registration.ts +25 -3
  165. package/src/console/inferhub/client.ts +139 -0
  166. package/src/console/inferhub/key-store.ts +129 -0
  167. package/src/console/inferhub/normalize.ts +347 -0
  168. package/src/console/inferhub/routes.ts +411 -0
  169. package/src/console/inferhub/store.ts +109 -0
  170. package/src/console/inferhub/types.ts +183 -0
  171. package/src/console/observability/contracts.ts +2 -41
  172. package/src/console/observability/store.ts +176 -371
  173. package/src/console/providers/catalog/public-model-store.ts +0 -0
  174. package/src/console/providers/catalog/store.ts +23 -36
  175. package/src/console/quota/account-quota-shared.ts +52 -52
  176. package/src/console/quota/account-quota-tenant.ts +16 -24
  177. package/src/console/quota/refresh.ts +441 -441
  178. package/src/console/remote-support/service.ts +270 -114
  179. package/src/console/routing/pools/import-parse.ts +206 -206
  180. package/src/console/routing/pools/operations.ts +543 -543
  181. package/src/console/routing/pools/probe-verdict.ts +132 -132
  182. package/src/console/routing/pools/routes.ts +181 -181
  183. package/src/console/routing/pools/store.ts +1 -1
  184. package/src/console/settings/contracts.ts +42 -40
  185. package/src/console/settings/store.ts +25 -25
  186. package/src/console/share/share-stats.ts +22 -4
  187. package/src/console/share/share-usage.ts +30 -4
  188. package/src/console/shared/cursor.ts +15 -0
  189. package/src/console/updates/repository-updates.ts +40 -39
  190. package/src/console/updates/routes.ts +12 -0
  191. package/src/main.ts +13 -5
  192. package/src/network/pool/resolver.ts +1104 -1104
  193. package/src/observability/client-name.ts +22 -0
  194. package/src/observability/event-log.ts +5 -29
  195. package/src/observability/event-query.ts +690 -0
  196. package/src/observability/log-ring.ts +26 -2
  197. package/src/observability/log-sanitize.ts +118 -0
  198. package/src/observability/logger.ts +17 -13
  199. package/src/observability/metrics.ts +35 -0
  200. package/src/observability/payload-capture.ts +114 -41
  201. package/src/observability/payload-store.ts +249 -24
  202. package/src/observability/raw-event-writer.ts +118 -0
  203. package/src/observability/runtime-metrics.ts +71 -1
  204. package/src/observability/telemetry-buffer.ts +100 -17
  205. package/src/observability/telemetry-reconciliation.ts +417 -0
  206. package/src/persistence/boot.ts +20 -9
  207. package/src/persistence/db-pg.ts +13 -0
  208. package/src/persistence/db-sqlite.ts +569 -497
  209. package/src/persistence/dialect.ts +3 -2
  210. package/src/persistence/migrate.ts +181 -181
  211. package/src/persistence/schema.ts +1496 -1406
  212. package/src/persistence/shared-cache.ts +5 -1
  213. package/src/persistence/stores/api-key-store.ts +581 -581
  214. package/src/persistence/stores/telemetry-store.ts +124 -63
  215. package/src/protocol/reasoning-text.ts +30 -0
  216. package/src/protocol/registry.ts +2 -0
  217. package/src/protocol/response/chat.ts +33 -7
  218. package/src/protocol/response/codex.ts +14 -2
  219. package/src/protocol/response/messages.ts +5 -2
  220. package/src/providers/authentication/oauth-flow-store.ts +3 -10
  221. package/src/providers/bundled-discovery-providers.ts +122 -122
  222. package/src/providers/default-registry.ts +14 -0
  223. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  224. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  225. package/src/providers/discovery/probe-phases.ts +43 -7
  226. package/src/providers/discovery/probing-service.ts +70 -32
  227. package/src/providers/integrations/antigravity/antigravity.ts +9 -2
  228. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +85 -17
  229. package/src/providers/integrations/buddy/buddy-chat-shared.ts +934 -934
  230. package/src/providers/integrations/buddy/buddy-checkin.ts +5 -9
  231. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +3 -7
  232. package/src/providers/integrations/buddy/buddy-quota-shared.ts +3 -1
  233. package/src/providers/integrations/buddy/capabilities.ts +4 -0
  234. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +57 -49
  235. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -180
  236. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -206
  237. package/src/providers/integrations/buddy/workbuddy/quota.ts +161 -161
  238. package/src/providers/integrations/claude/claude-quota.ts +2 -2
  239. package/src/providers/integrations/claude/claude-user-profiles.ts +3 -2
  240. package/src/providers/integrations/claude/claude.ts +3 -4
  241. package/src/providers/integrations/cline/cline.ts +94 -8
  242. package/src/providers/integrations/codex/codex.ts +61 -37
  243. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -368
  244. package/src/providers/integrations/cursor/cursor-http2.ts +300 -300
  245. package/src/providers/integrations/cursor/cursor-identity.ts +2 -4
  246. package/src/providers/integrations/cursor/cursor-request.ts +11 -0
  247. package/src/providers/integrations/cursor/cursor.ts +29 -17
  248. package/src/providers/integrations/cursor/protocol/framing.ts +129 -129
  249. package/src/providers/integrations/cursor/protocol/messages.ts +2380 -2380
  250. package/src/providers/integrations/cursor/protocol/struct.ts +305 -305
  251. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +275 -0
  252. package/src/providers/integrations/github/github.ts +3 -1
  253. package/src/providers/integrations/grok/grok-quota.ts +279 -279
  254. package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -73
  255. package/src/providers/integrations/grok/grok-ratelimit.ts +218 -218
  256. package/src/providers/integrations/hermes.ts +7 -1
  257. package/src/providers/integrations/inferhub.ts +201 -73
  258. package/src/providers/integrations/kilo/kilo.ts +152 -152
  259. package/src/providers/integrations/kiro/kiro-machine-id.ts +2 -4
  260. package/src/providers/integrations/opencode/provider.ts +2 -0
  261. package/src/providers/integrations/openrouter/provider.ts +129 -129
  262. package/src/providers/integrations/qoder/qoder-quota.ts +193 -192
  263. package/src/providers/integrations/qoder/qoder-realm.ts +106 -106
  264. package/src/providers/integrations/trae/trae-headers.ts +17 -48
  265. package/src/providers/integrations/trae/trae-oauth.ts +4 -26
  266. package/src/providers/integrations/trae/trae-quota.ts +389 -384
  267. package/src/providers/integrations/trae/trae-realm.ts +15 -2
  268. package/src/providers/integrations/trae/trae.ts +22 -24
  269. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +100 -24
  270. package/src/providers/integrations/zcode/oauth.ts +1 -1
  271. package/src/providers/operations/account-health-service.ts +605 -279
  272. package/src/providers/provider-metadata.ts +12 -1
  273. package/src/providers/provider-model-definition.ts +373 -373
  274. package/src/providers/provider-probe.ts +3 -0
  275. package/src/providers/quota/quota-contracts.ts +3 -7
  276. package/src/providers/search/search-provider.ts +2 -6
  277. package/src/security/admission/contracts.ts +10 -0
  278. package/src/security/admission/in-memory-store.ts +89 -14
  279. package/src/security/admission/lua.ts +191 -182
  280. package/src/security/admission/redis-store.ts +30 -0
  281. package/src/security/admission/service.ts +18 -0
  282. package/src/security/api-key-auth-cache.ts +96 -0
  283. package/src/security/api-key-auth.ts +11 -100
  284. package/src/security/client-router-fingerprint.ts +3 -7
  285. package/src/security/ip-boundary.ts +7 -3
  286. package/src/shared/coerce.ts +67 -0
  287. package/src/shared/hash.ts +6 -0
  288. package/src/shared/time.ts +7 -0
  289. package/src/transport/dispatch/attempt-finalize.ts +26 -138
  290. package/src/transport/dispatch/attempt-loop.ts +103 -81
  291. package/src/transport/dispatch/capture-policy.ts +78 -0
  292. package/src/transport/dispatch/proxy-request.ts +4 -2
  293. package/src/transport/dispatch/streaming/encoder.ts +111 -5
  294. package/src/transport/dispatch/streaming/stream.ts +19 -2
  295. package/src/transport/dispatch/streaming/thinking-loop.ts +300 -0
  296. package/src/transport/failure-policy.ts +27 -0
  297. package/src/transport/guards/abuse-guard.ts +2 -2
  298. package/src/transport/guards/auth-guard.ts +17 -0
  299. package/src/transport/guards/body-policy.ts +3 -2
  300. package/src/transport/guards/concurrency-guard.ts +89 -13
  301. package/src/transport/guards/early-rejection-capture.ts +43 -3
  302. package/src/transport/guards/error-lifecycle.ts +10 -2
  303. package/src/transport/guards/guard-errors.ts +23 -0
  304. package/src/transport/guards/headroom-guard.ts +41 -7
  305. package/src/transport/guards/pipeline.ts +24 -0
  306. package/src/transport/guards/request-context.ts +2 -1
  307. package/src/transport/routing/admission.ts +51 -9
  308. package/src/transport/routing/bounded-lru.ts +49 -0
  309. package/src/transport/routing/candidate-index.ts +88 -0
  310. package/src/transport/routing/reservations.ts +121 -7
  311. package/src/transport/routing/round-robin.ts +10 -22
  312. package/src/transport/routing/route-catalog.ts +26 -13
  313. package/src/transport/routing/route-model.ts +22 -2
  314. package/src/transport/routing/router.ts +53 -31
  315. package/src/transport/surface/chat/encode.ts +2 -3
  316. package/src/transport/surface/chat/parse.ts +2 -1
  317. package/src/transport/surface/dialects.ts +11 -3
  318. package/src/transport/surface/messages/encode.ts +2 -1
  319. package/src/transport/surface/messages/parse.ts +3 -1
  320. package/src/transport/surface/messages/stream.ts +2 -6
  321. package/src/workers/maintenance-lease.ts +200 -0
  322. package/src/workers/scheduler.ts +101 -1
  323. package/dist/dashboard/assets/BannedPage-Brvuj_Eb.js.gz +0 -0
  324. package/dist/dashboard/assets/CliToolDetailPage-CqfXtI3y.js.gz +0 -0
  325. package/dist/dashboard/assets/CliToolsPage-GQeS91bg.js.gz +0 -0
  326. package/dist/dashboard/assets/CombosPage-BDRsTXBB.js.gz +0 -0
  327. package/dist/dashboard/assets/ConsoleLogPage-zP8AFHX0.js.gz +0 -0
  328. package/dist/dashboard/assets/CustomizationPage-BmfrNZ14.js.gz +0 -0
  329. package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js +0 -1
  330. package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js.gz +0 -0
  331. package/dist/dashboard/assets/LoginPage-DoreIgm8.js.gz +0 -0
  332. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
  333. package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js +0 -1
  334. package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js.gz +0 -0
  335. package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js +0 -3
  336. package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js.gz +0 -0
  337. package/dist/dashboard/assets/ProvidersPage-BnoPgA7w.js.gz +0 -0
  338. package/dist/dashboard/assets/ProxyPage-Bq_TGgdb.js.gz +0 -0
  339. package/dist/dashboard/assets/QuotaPage-D9DHXvom.js +0 -1
  340. package/dist/dashboard/assets/QuotaPage-D9DHXvom.js.gz +0 -0
  341. package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js +0 -1
  342. package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js.gz +0 -0
  343. package/dist/dashboard/assets/SetupPage-Day3mCOn.js.gz +0 -0
  344. package/dist/dashboard/assets/SortableList-DQxllnB5.js.gz +0 -0
  345. package/dist/dashboard/assets/UsagePage-DXa1oR-4.js.gz +0 -0
  346. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  347. package/dist/dashboard/assets/app-CX_Z8cMs.css +0 -2
  348. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  349. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  350. package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
  351. package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
  352. package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
  353. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  354. package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
  355. package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
  356. package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
  357. package/dist/dashboard/assets/entry-B9Xvtnfj.js +0 -1
  358. package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
  359. package/dist/dashboard/assets/entry-ByMGkR3C.js +0 -4
  360. package/dist/dashboard/assets/entry-ByMGkR3C.js.gz +0 -0
  361. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  362. package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
  363. package/dist/dashboard/assets/index-z3zDOSMM.js.gz +0 -0
  364. package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
  365. package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
  366. package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
  367. package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
  368. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  369. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  370. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  371. package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
  372. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  373. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  374. package/dist/dashboard/assets/select-C6MMiaio.js.gz +0 -0
  375. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  376. package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
  377. package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
  378. package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
  379. package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
  380. package/scripts/build/aot.ts +0 -143
  381. package/scripts/build/build.ts +0 -24
  382. package/scripts/build/compile.ts +0 -88
  383. package/scripts/build/restart.ts +0 -120
  384. package/scripts/build/start.ts +0 -25
  385. package/src/observability/event-compaction.ts +0 -317
  386. package/src/observability/event-day-index.ts +0 -440
@@ -1,237 +1,237 @@
1
- // Registers the tray with the OS login/startup facility.
2
- //
3
- // The tray only runs while someone starts it, so a gateway that is meant to be
4
- // always-on needs the OS to start it. Each platform has its own place for that,
5
- // and they differ in what "disable" means:
6
- //
7
- // - **Windows** — a value under `HKCU\\Software\\Microsoft\\Windows\\
8
- // CurrentVersion\\Run`. Task Manager's Startup tab lists it, so an operator
9
- // can disable it there without touching the registry by hand.
10
- // - **macOS** — a launch agent plist in `~/Library/LaunchAgents`.
11
- // - **Linux** — a `.desktop` file in `~/.config/autostart` (the freedesktop
12
- // spec, honoured by every mainstream desktop).
13
- //
14
- // This only ever writes the *user's* own startup location, never a system one,
15
- // so nothing here needs elevation and nothing here is forced on: removing the
16
- // entry is the documented way to turn it off, and the tray itself keeps working
17
- // when started by hand.
18
-
19
- import { existsSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
20
- import { homedir, platform } from "node:os";
21
- import { join } from "node:path";
22
-
23
- /** The launch label, used as the registry value name, plist label and file name. */
24
- const APP_ID = "cartethyia-tray";
25
-
26
- export interface AutostartState {
27
- readonly platform: string;
28
- readonly enabled: boolean;
29
- /** Where the entry lives, for the operator who wants to remove it by hand. */
30
- readonly location: string;
31
- /** Why it is not supported here, when it is not. */
32
- readonly reason?: string;
33
- }
34
-
35
- /**
36
- * The command the OS should run.
37
- *
38
- * Quoted once here rather than at each call site: the Windows registry value,
39
- * the plist arguments and the desktop `Exec` line each parse spaces
40
- * differently, and a path under `C:\\Users\\First Last\\...` silently becomes
41
- * two arguments otherwise.
42
- */
43
- function commandFor(executable: string, args: readonly string[]): string {
44
- const quoted = /\s/.test(executable) ? `"${executable}"` : executable;
45
- return [quoted, ...args.map((arg) => (/\s/.test(arg) ? `"${arg}"` : arg))].join(" ");
46
- }
47
-
48
- function windowsCommand(command: string): string[] {
49
- return [
50
- "reg",
51
- "add",
52
- "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
53
- "/v",
54
- APP_ID,
55
- "/t",
56
- "REG_SZ",
57
- "/d",
58
- command,
59
- "/f",
60
- ];
61
- }
62
-
63
- function launchAgentsPath(): string {
64
- return join(homedir(), "Library", "LaunchAgents", `${APP_ID}.plist`);
65
- }
66
-
67
- /** Escapes the five entities XML defines, so a path cannot break the plist. */
68
- function xmlEscape(value: string): string {
69
- return value
70
- .replaceAll("&", "&")
71
- .replaceAll("<", "&lt;")
72
- .replaceAll(">", "&gt;")
73
- .replaceAll('"', "&quot;")
74
- .replaceAll("'", "&apos;");
75
- }
76
-
77
- function plistFor(executable: string, args: readonly string[]): string {
78
- const programArgs = [executable, ...args]
79
- .map((part) => ` <string>${xmlEscape(part)}</string>`)
80
- .join("\n");
81
- return `<?xml version="1.0" encoding="UTF-8"?>
82
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
83
- <plist version="1.0">
84
- <dict>
85
- <key>Label</key>
86
- <string>${APP_ID}</string>
87
- <key>ProgramArguments</key>
88
- <array>
89
- ${programArgs}
90
- </array>
91
- <key>RunAtLoad</key>
92
- <true/>
93
- <!-- Restart only if it exits on its own; a crash loop is not a reason to
94
- respawn forever, and a stopped tray should stay stopped. -->
95
- <key>KeepAlive</key>
96
- <false/>
97
- </dict>
98
- </plist>
99
- `;
100
- }
101
-
102
- function desktopEntryFor(command: string): string {
103
- return `[Desktop Entry]
104
- Type=Application
105
- Name=Cartethyia Tray
106
- Exec=${command}
107
- Hidden=false
108
- NoDisplay=false
109
- X-GNOME-Autostart-enabled=true
110
- `;
111
- }
112
-
113
- /**
114
- * Enables autostart for the tray.
115
- *
116
- * Returns the resulting state rather than throwing, because a failure here must
117
- * not abort startup: the tray is still perfectly usable when launched by hand,
118
- * and an operator who cannot write to their own startup folder has a reason we
119
- * should report, not crash on.
120
- */
121
- export async function enableAutostart(
122
- executable: string,
123
- args: readonly string[],
124
- ): Promise<AutostartState> {
125
- const os = platform();
126
- const command = commandFor(executable, args);
127
-
128
- if (os === "win32") {
129
- const proc = Bun.spawn(windowsCommand(command), { stdout: "pipe", stderr: "pipe" });
130
- const code = await proc.exited;
131
- return {
132
- platform: os,
133
- enabled: code === 0,
134
- location: "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
135
- ...(code === 0
136
- ? {}
137
- : { reason: "reg add failed; the entry can be added by hand or via Task Manager" }),
138
- };
139
- }
140
-
141
- if (os === "darwin") {
142
- const path = launchAgentsPath();
143
- try {
144
- mkdirSync(join(homedir(), "Library", "LaunchAgents"), { recursive: true });
145
- writeFileSync(path, plistFor(executable, args), "utf8");
146
- return { platform: os, enabled: true, location: path };
147
- } catch (error) {
148
- return {
149
- platform: os,
150
- enabled: false,
151
- location: path,
152
- reason: error instanceof Error ? error.message : "could not write the launch agent",
153
- };
154
- }
155
- }
156
-
157
- if (os === "linux") {
158
- const dir = join(homedir(), ".config", "autostart");
159
- const path = join(dir, `${APP_ID}.desktop`);
160
- try {
161
- mkdirSync(dir, { recursive: true });
162
- writeFileSync(path, desktopEntryFor(command), "utf8");
163
- return { platform: os, enabled: true, location: path };
164
- } catch (error) {
165
- return {
166
- platform: os,
167
- enabled: false,
168
- location: path,
169
- reason: error instanceof Error ? error.message : "could not write the desktop entry",
170
- };
171
- }
172
- }
173
-
174
- return {
175
- platform: os,
176
- enabled: false,
177
- location: "",
178
- reason: `no supported autostart location on ${os}`,
179
- };
180
- }
181
-
182
- /** Removes the entry, so the tray stops starting with the session. */
183
- export async function disableAutostart(): Promise<AutostartState> {
184
- const os = platform();
185
-
186
- if (os === "win32") {
187
- const proc = Bun.spawn(
188
- [
189
- "reg",
190
- "delete",
191
- "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
192
- "/v",
193
- APP_ID,
194
- "/f",
195
- ],
196
- { stdout: "pipe", stderr: "pipe" },
197
- );
198
- // `reg delete` exits non-zero when the value was already absent, which is
199
- // the state the caller wanted anyway, so the code is not read.
200
- await proc.exited;
201
- return {
202
- platform: os,
203
- enabled: false,
204
- location: "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
205
- };
206
- }
207
-
208
- const path = os === "darwin" ? launchAgentsPath() : join(homedir(), ".config", "autostart", `${APP_ID}.desktop`);
209
- try {
210
- if (existsSync(path)) rmSync(path);
211
- return { platform: os, enabled: false, location: path };
212
- } catch (error) {
213
- return {
214
- platform: os,
215
- enabled: false,
216
- location: path,
217
- reason: error instanceof Error ? error.message : "could not remove the entry",
218
- };
219
- }
220
- }
221
-
222
- /** Whether an entry is currently registered. */
223
- export function autostartStatus(): AutostartState {
224
- const os = platform();
225
- if (os === "win32") {
226
- // Reading the registry needs a process, so this is reported as unknown
227
- // rather than guessed; `disableAutostart` is idempotent either way.
228
- return {
229
- platform: os,
230
- enabled: false,
231
- location: "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
232
- reason: "status is not readable synchronously; enable or disable to set it",
233
- };
234
- }
235
- const path = os === "darwin" ? launchAgentsPath() : join(homedir(), ".config", "autostart", `${APP_ID}.desktop`);
236
- return { platform: os, enabled: existsSync(path), location: path };
237
- }
1
+ // Registers the tray with the OS login/startup facility.
2
+ //
3
+ // The tray only runs while someone starts it, so a gateway that is meant to be
4
+ // always-on needs the OS to start it. Each platform has its own place for that,
5
+ // and they differ in what "disable" means:
6
+ //
7
+ // - **Windows** — a value under `HKCU\\Software\\Microsoft\\Windows\\
8
+ // CurrentVersion\\Run`. Task Manager's Startup tab lists it, so an operator
9
+ // can disable it there without touching the registry by hand.
10
+ // - **macOS** — a launch agent plist in `~/Library/LaunchAgents`.
11
+ // - **Linux** — a `.desktop` file in `~/.config/autostart` (the freedesktop
12
+ // spec, honoured by every mainstream desktop).
13
+ //
14
+ // This only ever writes the *user's* own startup location, never a system one,
15
+ // so nothing here needs elevation and nothing here is forced on: removing the
16
+ // entry is the documented way to turn it off, and the tray itself keeps working
17
+ // when started by hand.
18
+
19
+ import { existsSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
20
+ import { homedir, platform } from "node:os";
21
+ import { join } from "node:path";
22
+
23
+ /** The launch label, used as the registry value name, plist label and file name. */
24
+ const APP_ID = "cartethyia-tray";
25
+
26
+ export interface AutostartState {
27
+ readonly platform: string;
28
+ readonly enabled: boolean;
29
+ /** Where the entry lives, for the operator who wants to remove it by hand. */
30
+ readonly location: string;
31
+ /** Why it is not supported here, when it is not. */
32
+ readonly reason?: string;
33
+ }
34
+
35
+ /**
36
+ * The command the OS should run.
37
+ *
38
+ * Quoted once here rather than at each call site: the Windows registry value,
39
+ * the plist arguments and the desktop `Exec` line each parse spaces
40
+ * differently, and a path under `C:\\Users\\First Last\\...` silently becomes
41
+ * two arguments otherwise.
42
+ */
43
+ function commandFor(executable: string, args: readonly string[]): string {
44
+ const quoted = /\s/.test(executable) ? `"${executable}"` : executable;
45
+ return [quoted, ...args.map((arg) => (/\s/.test(arg) ? `"${arg}"` : arg))].join(" ");
46
+ }
47
+
48
+ function windowsCommand(command: string): string[] {
49
+ return [
50
+ "reg",
51
+ "add",
52
+ "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
53
+ "/v",
54
+ APP_ID,
55
+ "/t",
56
+ "REG_SZ",
57
+ "/d",
58
+ command,
59
+ "/f",
60
+ ];
61
+ }
62
+
63
+ function launchAgentsPath(): string {
64
+ return join(homedir(), "Library", "LaunchAgents", `${APP_ID}.plist`);
65
+ }
66
+
67
+ /** Escapes the five entities XML defines, so a path cannot break the plist. */
68
+ function xmlEscape(value: string): string {
69
+ return value
70
+ .replaceAll("&", "&amp;")
71
+ .replaceAll("<", "&lt;")
72
+ .replaceAll(">", "&gt;")
73
+ .replaceAll('"', "&quot;")
74
+ .replaceAll("'", "&apos;");
75
+ }
76
+
77
+ function plistFor(executable: string, args: readonly string[]): string {
78
+ const programArgs = [executable, ...args]
79
+ .map((part) => ` <string>${xmlEscape(part)}</string>`)
80
+ .join("\n");
81
+ return `<?xml version="1.0" encoding="UTF-8"?>
82
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
83
+ <plist version="1.0">
84
+ <dict>
85
+ <key>Label</key>
86
+ <string>${APP_ID}</string>
87
+ <key>ProgramArguments</key>
88
+ <array>
89
+ ${programArgs}
90
+ </array>
91
+ <key>RunAtLoad</key>
92
+ <true/>
93
+ <!-- Restart only if it exits on its own; a crash loop is not a reason to
94
+ respawn forever, and a stopped tray should stay stopped. -->
95
+ <key>KeepAlive</key>
96
+ <false/>
97
+ </dict>
98
+ </plist>
99
+ `;
100
+ }
101
+
102
+ function desktopEntryFor(command: string): string {
103
+ return `[Desktop Entry]
104
+ Type=Application
105
+ Name=Cartethyia Tray
106
+ Exec=${command}
107
+ Hidden=false
108
+ NoDisplay=false
109
+ X-GNOME-Autostart-enabled=true
110
+ `;
111
+ }
112
+
113
+ /**
114
+ * Enables autostart for the tray.
115
+ *
116
+ * Returns the resulting state rather than throwing, because a failure here must
117
+ * not abort startup: the tray is still perfectly usable when launched by hand,
118
+ * and an operator who cannot write to their own startup folder has a reason we
119
+ * should report, not crash on.
120
+ */
121
+ export async function enableAutostart(
122
+ executable: string,
123
+ args: readonly string[],
124
+ ): Promise<AutostartState> {
125
+ const os = platform();
126
+ const command = commandFor(executable, args);
127
+
128
+ if (os === "win32") {
129
+ const proc = Bun.spawn(windowsCommand(command), { stdout: "pipe", stderr: "pipe" });
130
+ const code = await proc.exited;
131
+ return {
132
+ platform: os,
133
+ enabled: code === 0,
134
+ location: "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
135
+ ...(code === 0
136
+ ? {}
137
+ : { reason: "reg add failed; the entry can be added by hand or via Task Manager" }),
138
+ };
139
+ }
140
+
141
+ if (os === "darwin") {
142
+ const path = launchAgentsPath();
143
+ try {
144
+ mkdirSync(join(homedir(), "Library", "LaunchAgents"), { recursive: true });
145
+ writeFileSync(path, plistFor(executable, args), "utf8");
146
+ return { platform: os, enabled: true, location: path };
147
+ } catch (error) {
148
+ return {
149
+ platform: os,
150
+ enabled: false,
151
+ location: path,
152
+ reason: error instanceof Error ? error.message : "could not write the launch agent",
153
+ };
154
+ }
155
+ }
156
+
157
+ if (os === "linux") {
158
+ const dir = join(homedir(), ".config", "autostart");
159
+ const path = join(dir, `${APP_ID}.desktop`);
160
+ try {
161
+ mkdirSync(dir, { recursive: true });
162
+ writeFileSync(path, desktopEntryFor(command), "utf8");
163
+ return { platform: os, enabled: true, location: path };
164
+ } catch (error) {
165
+ return {
166
+ platform: os,
167
+ enabled: false,
168
+ location: path,
169
+ reason: error instanceof Error ? error.message : "could not write the desktop entry",
170
+ };
171
+ }
172
+ }
173
+
174
+ return {
175
+ platform: os,
176
+ enabled: false,
177
+ location: "",
178
+ reason: `no supported autostart location on ${os}`,
179
+ };
180
+ }
181
+
182
+ /** Removes the entry, so the tray stops starting with the session. */
183
+ export async function disableAutostart(): Promise<AutostartState> {
184
+ const os = platform();
185
+
186
+ if (os === "win32") {
187
+ const proc = Bun.spawn(
188
+ [
189
+ "reg",
190
+ "delete",
191
+ "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
192
+ "/v",
193
+ APP_ID,
194
+ "/f",
195
+ ],
196
+ { stdout: "pipe", stderr: "pipe" },
197
+ );
198
+ // `reg delete` exits non-zero when the value was already absent, which is
199
+ // the state the caller wanted anyway, so the code is not read.
200
+ await proc.exited;
201
+ return {
202
+ platform: os,
203
+ enabled: false,
204
+ location: "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
205
+ };
206
+ }
207
+
208
+ const path = os === "darwin" ? launchAgentsPath() : join(homedir(), ".config", "autostart", `${APP_ID}.desktop`);
209
+ try {
210
+ if (existsSync(path)) rmSync(path);
211
+ return { platform: os, enabled: false, location: path };
212
+ } catch (error) {
213
+ return {
214
+ platform: os,
215
+ enabled: false,
216
+ location: path,
217
+ reason: error instanceof Error ? error.message : "could not remove the entry",
218
+ };
219
+ }
220
+ }
221
+
222
+ /** Whether an entry is currently registered. */
223
+ export function autostartStatus(): AutostartState {
224
+ const os = platform();
225
+ if (os === "win32") {
226
+ // Reading the registry needs a process, so this is reported as unknown
227
+ // rather than guessed; `disableAutostart` is idempotent either way.
228
+ return {
229
+ platform: os,
230
+ enabled: false,
231
+ location: "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
232
+ reason: "status is not readable synchronously; enable or disable to set it",
233
+ };
234
+ }
235
+ const path = os === "darwin" ? launchAgentsPath() : join(homedir(), ".config", "autostart", `${APP_ID}.desktop`);
236
+ return { platform: os, enabled: existsSync(path), location: path };
237
+ }