libre-webui 0.21.3 → 0.22.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 (945) hide show
  1. package/README.md +308 -328
  2. package/backend/dist/cli/migrateSqliteToPostgres.d.ts +2 -0
  3. package/backend/dist/cli/migrateSqliteToPostgres.d.ts.map +1 -0
  4. package/backend/dist/cli/migrateSqliteToPostgres.js +113 -0
  5. package/backend/dist/cli/migrateSqliteToPostgres.js.map +1 -0
  6. package/backend/dist/cli/recoveryBackup.d.ts +3 -0
  7. package/backend/dist/cli/recoveryBackup.d.ts.map +1 -0
  8. package/backend/dist/cli/recoveryBackup.js +251 -0
  9. package/backend/dist/cli/recoveryBackup.js.map +1 -0
  10. package/backend/dist/cli/recoveryInventory.d.ts +2 -0
  11. package/backend/dist/cli/recoveryInventory.d.ts.map +1 -0
  12. package/backend/dist/cli/recoveryInventory.js +109 -0
  13. package/backend/dist/cli/recoveryInventory.js.map +1 -0
  14. package/backend/dist/db.d.ts +27 -0
  15. package/backend/dist/db.d.ts.map +1 -1
  16. package/backend/dist/db.js +333 -16
  17. package/backend/dist/db.js.map +1 -1
  18. package/backend/dist/env.d.ts.map +1 -1
  19. package/backend/dist/env.js +12 -2
  20. package/backend/dist/env.js.map +1 -1
  21. package/backend/dist/index.d.ts.map +1 -1
  22. package/backend/dist/index.js +235 -47
  23. package/backend/dist/index.js.map +1 -1
  24. package/backend/dist/main.d.ts +2 -0
  25. package/backend/dist/main.d.ts.map +1 -0
  26. package/backend/dist/main.js +137 -0
  27. package/backend/dist/main.js.map +1 -0
  28. package/backend/dist/middleware/auth.d.ts.map +1 -1
  29. package/backend/dist/middleware/auth.js +7 -3
  30. package/backend/dist/middleware/auth.js.map +1 -1
  31. package/backend/dist/middleware/chatCancellationAdmission.d.ts +7 -0
  32. package/backend/dist/middleware/chatCancellationAdmission.d.ts.map +1 -0
  33. package/backend/dist/middleware/chatCancellationAdmission.js +17 -0
  34. package/backend/dist/middleware/chatCancellationAdmission.js.map +1 -0
  35. package/backend/dist/middleware/coordinatedRateLimit.d.ts +18 -0
  36. package/backend/dist/middleware/coordinatedRateLimit.d.ts.map +1 -0
  37. package/backend/dist/middleware/coordinatedRateLimit.js +52 -0
  38. package/backend/dist/middleware/coordinatedRateLimit.js.map +1 -0
  39. package/backend/dist/middleware/sharedRateLimit.d.ts +26 -0
  40. package/backend/dist/middleware/sharedRateLimit.d.ts.map +1 -0
  41. package/backend/dist/middleware/sharedRateLimit.js +99 -0
  42. package/backend/dist/middleware/sharedRateLimit.js.map +1 -0
  43. package/backend/dist/models/personaModel.d.ts +1 -26
  44. package/backend/dist/models/personaModel.d.ts.map +1 -1
  45. package/backend/dist/models/personaModel.js +54 -247
  46. package/backend/dist/models/personaModel.js.map +1 -1
  47. package/backend/dist/models/userModel.d.ts +23 -66
  48. package/backend/dist/models/userModel.d.ts.map +1 -1
  49. package/backend/dist/models/userModel.js +110 -187
  50. package/backend/dist/models/userModel.js.map +1 -1
  51. package/backend/dist/persistence/chatGenerationTypes.d.ts +24 -0
  52. package/backend/dist/persistence/chatGenerationTypes.d.ts.map +1 -0
  53. package/backend/dist/persistence/chatGenerationTypes.js +7 -0
  54. package/backend/dist/persistence/chatGenerationTypes.js.map +1 -0
  55. package/backend/dist/persistence/extensionTypes.d.ts +185 -0
  56. package/backend/dist/persistence/extensionTypes.d.ts.map +1 -0
  57. package/backend/dist/persistence/extensionTypes.js +13 -0
  58. package/backend/dist/persistence/extensionTypes.js.map +1 -0
  59. package/backend/dist/persistence/identityDeletionTypes.d.ts +16 -0
  60. package/backend/dist/persistence/identityDeletionTypes.d.ts.map +1 -0
  61. package/backend/dist/persistence/identityDeletionTypes.js +7 -0
  62. package/backend/dist/persistence/identityDeletionTypes.js.map +1 -0
  63. package/backend/dist/persistence/index.d.ts +48 -0
  64. package/backend/dist/persistence/index.d.ts.map +1 -0
  65. package/backend/dist/persistence/index.js +159 -0
  66. package/backend/dist/persistence/index.js.map +1 -0
  67. package/backend/dist/persistence/postgresConfig.d.ts +32 -0
  68. package/backend/dist/persistence/postgresConfig.d.ts.map +1 -0
  69. package/backend/dist/persistence/postgresConfig.js +91 -0
  70. package/backend/dist/persistence/postgresConfig.js.map +1 -0
  71. package/backend/dist/persistence/postgresCoreMigration.d.ts +8 -0
  72. package/backend/dist/persistence/postgresCoreMigration.d.ts.map +1 -0
  73. package/backend/dist/persistence/postgresCoreMigration.js +179 -0
  74. package/backend/dist/persistence/postgresCoreMigration.js.map +1 -0
  75. package/backend/dist/persistence/postgresDatabase.d.ts +40 -0
  76. package/backend/dist/persistence/postgresDatabase.d.ts.map +1 -0
  77. package/backend/dist/persistence/postgresDatabase.js +148 -0
  78. package/backend/dist/persistence/postgresDatabase.js.map +1 -0
  79. package/backend/dist/persistence/postgresExtensionMigration.d.ts +4 -0
  80. package/backend/dist/persistence/postgresExtensionMigration.d.ts.map +1 -0
  81. package/backend/dist/persistence/postgresExtensionMigration.js +143 -0
  82. package/backend/dist/persistence/postgresExtensionMigration.js.map +1 -0
  83. package/backend/dist/persistence/postgresExtensionRepositories.d.ts +6 -0
  84. package/backend/dist/persistence/postgresExtensionRepositories.d.ts.map +1 -0
  85. package/backend/dist/persistence/postgresExtensionRepositories.js +550 -0
  86. package/backend/dist/persistence/postgresExtensionRepositories.js.map +1 -0
  87. package/backend/dist/persistence/postgresImportState.d.ts +9 -0
  88. package/backend/dist/persistence/postgresImportState.d.ts.map +1 -0
  89. package/backend/dist/persistence/postgresImportState.js +64 -0
  90. package/backend/dist/persistence/postgresImportState.js.map +1 -0
  91. package/backend/dist/persistence/postgresMigrationRegistry.d.ts +4 -0
  92. package/backend/dist/persistence/postgresMigrationRegistry.d.ts.map +1 -0
  93. package/backend/dist/persistence/postgresMigrationRegistry.js +33 -0
  94. package/backend/dist/persistence/postgresMigrationRegistry.js.map +1 -0
  95. package/backend/dist/persistence/postgresMigrationTypes.d.ts +24 -0
  96. package/backend/dist/persistence/postgresMigrationTypes.d.ts.map +1 -0
  97. package/backend/dist/persistence/postgresMigrationTypes.js +7 -0
  98. package/backend/dist/persistence/postgresMigrationTypes.js.map +1 -0
  99. package/backend/dist/persistence/postgresMigrations.d.ts +15 -0
  100. package/backend/dist/persistence/postgresMigrations.d.ts.map +1 -0
  101. package/backend/dist/persistence/postgresMigrations.js +333 -0
  102. package/backend/dist/persistence/postgresMigrations.js.map +1 -0
  103. package/backend/dist/persistence/postgresPersistence.d.ts +17 -0
  104. package/backend/dist/persistence/postgresPersistence.d.ts.map +1 -0
  105. package/backend/dist/persistence/postgresPersistence.js +332 -0
  106. package/backend/dist/persistence/postgresPersistence.js.map +1 -0
  107. package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts +4 -0
  108. package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts.map +1 -0
  109. package/backend/dist/persistence/postgresPluginDefinitionMigration.js +40 -0
  110. package/backend/dist/persistence/postgresPluginDefinitionMigration.js.map +1 -0
  111. package/backend/dist/persistence/postgresResourceRepositories.d.ts +7 -0
  112. package/backend/dist/persistence/postgresResourceRepositories.d.ts.map +1 -0
  113. package/backend/dist/persistence/postgresResourceRepositories.js +776 -0
  114. package/backend/dist/persistence/postgresResourceRepositories.js.map +1 -0
  115. package/backend/dist/persistence/postgresSchemaInspector.d.ts +14 -0
  116. package/backend/dist/persistence/postgresSchemaInspector.d.ts.map +1 -0
  117. package/backend/dist/persistence/postgresSchemaInspector.js +817 -0
  118. package/backend/dist/persistence/postgresSchemaInspector.js.map +1 -0
  119. package/backend/dist/persistence/resourceTypes.d.ts +207 -0
  120. package/backend/dist/persistence/resourceTypes.d.ts.map +1 -0
  121. package/backend/dist/persistence/resourceTypes.js +38 -0
  122. package/backend/dist/persistence/resourceTypes.js.map +1 -0
  123. package/backend/dist/persistence/sqliteExtensionRepositories.d.ts +4 -0
  124. package/backend/dist/persistence/sqliteExtensionRepositories.d.ts.map +1 -0
  125. package/backend/dist/persistence/sqliteExtensionRepositories.js +494 -0
  126. package/backend/dist/persistence/sqliteExtensionRepositories.js.map +1 -0
  127. package/backend/dist/persistence/sqliteMigrations.d.ts +93 -0
  128. package/backend/dist/persistence/sqliteMigrations.d.ts.map +1 -0
  129. package/backend/dist/persistence/sqliteMigrations.js +2232 -0
  130. package/backend/dist/persistence/sqliteMigrations.js.map +1 -0
  131. package/backend/dist/persistence/sqlitePersistence.d.ts +23 -0
  132. package/backend/dist/persistence/sqlitePersistence.d.ts.map +1 -0
  133. package/backend/dist/persistence/sqlitePersistence.js +596 -0
  134. package/backend/dist/persistence/sqlitePersistence.js.map +1 -0
  135. package/backend/dist/persistence/sqliteResourceRepositories.d.ts +4 -0
  136. package/backend/dist/persistence/sqliteResourceRepositories.d.ts.map +1 -0
  137. package/backend/dist/persistence/sqliteResourceRepositories.js +663 -0
  138. package/backend/dist/persistence/sqliteResourceRepositories.js.map +1 -0
  139. package/backend/dist/persistence/sqliteSyncExecutor.d.ts +5 -0
  140. package/backend/dist/persistence/sqliteSyncExecutor.d.ts.map +1 -0
  141. package/backend/dist/persistence/sqliteSyncExecutor.js +19 -0
  142. package/backend/dist/persistence/sqliteSyncExecutor.js.map +1 -0
  143. package/backend/dist/persistence/sqliteToPostgresMigration.d.ts +80 -0
  144. package/backend/dist/persistence/sqliteToPostgresMigration.d.ts.map +1 -0
  145. package/backend/dist/persistence/sqliteToPostgresMigration.js +1543 -0
  146. package/backend/dist/persistence/sqliteToPostgresMigration.js.map +1 -0
  147. package/backend/dist/persistence/types.d.ts +131 -0
  148. package/backend/dist/persistence/types.d.ts.map +1 -0
  149. package/backend/dist/persistence/types.js +18 -0
  150. package/backend/dist/persistence/types.js.map +1 -0
  151. package/backend/dist/persistence/voiceProfileNameLookup.d.ts +9 -0
  152. package/backend/dist/persistence/voiceProfileNameLookup.d.ts.map +1 -0
  153. package/backend/dist/persistence/voiceProfileNameLookup.js +15 -0
  154. package/backend/dist/persistence/voiceProfileNameLookup.js.map +1 -0
  155. package/backend/dist/platform/coordination/index.d.ts +7 -0
  156. package/backend/dist/platform/coordination/index.d.ts.map +1 -0
  157. package/backend/dist/platform/coordination/index.js +24 -0
  158. package/backend/dist/platform/coordination/index.js.map +1 -0
  159. package/backend/dist/platform/coordination/localCoordinator.d.ts +49 -0
  160. package/backend/dist/platform/coordination/localCoordinator.d.ts.map +1 -0
  161. package/backend/dist/platform/coordination/localCoordinator.js +380 -0
  162. package/backend/dist/platform/coordination/localCoordinator.js.map +1 -0
  163. package/backend/dist/platform/coordination/redisCoordinator.d.ts +83 -0
  164. package/backend/dist/platform/coordination/redisCoordinator.d.ts.map +1 -0
  165. package/backend/dist/platform/coordination/redisCoordinator.js +726 -0
  166. package/backend/dist/platform/coordination/redisCoordinator.js.map +1 -0
  167. package/backend/dist/platform/coordination/service.d.ts +11 -0
  168. package/backend/dist/platform/coordination/service.d.ts.map +1 -0
  169. package/backend/dist/platform/coordination/service.js +55 -0
  170. package/backend/dist/platform/coordination/service.js.map +1 -0
  171. package/backend/dist/platform/coordination/sharedAdmission.d.ts +53 -0
  172. package/backend/dist/platform/coordination/sharedAdmission.d.ts.map +1 -0
  173. package/backend/dist/platform/coordination/sharedAdmission.js +194 -0
  174. package/backend/dist/platform/coordination/sharedAdmission.js.map +1 -0
  175. package/backend/dist/platform/coordination/types.d.ts +76 -0
  176. package/backend/dist/platform/coordination/types.d.ts.map +1 -0
  177. package/backend/dist/platform/coordination/types.js +32 -0
  178. package/backend/dist/platform/coordination/types.js.map +1 -0
  179. package/backend/dist/platform/events/durableEventGateway.d.ts +54 -0
  180. package/backend/dist/platform/events/durableEventGateway.d.ts.map +1 -0
  181. package/backend/dist/platform/events/durableEventGateway.js +262 -0
  182. package/backend/dist/platform/events/durableEventGateway.js.map +1 -0
  183. package/backend/dist/platform/events/index.d.ts +3 -0
  184. package/backend/dist/platform/events/index.d.ts.map +1 -0
  185. package/backend/dist/platform/events/index.js +8 -0
  186. package/backend/dist/platform/events/index.js.map +1 -0
  187. package/backend/dist/platform/events/service.d.ts +8 -0
  188. package/backend/dist/platform/events/service.d.ts.map +1 -0
  189. package/backend/dist/platform/events/service.js +25 -0
  190. package/backend/dist/platform/events/service.js.map +1 -0
  191. package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts +3 -0
  192. package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts.map +1 -0
  193. package/backend/dist/platform/jobs/chatGenerationEnqueuer.js +55 -0
  194. package/backend/dist/platform/jobs/chatGenerationEnqueuer.js.map +1 -0
  195. package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts +3 -0
  196. package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts.map +1 -0
  197. package/backend/dist/platform/jobs/documentIngestionEnqueuer.js +38 -0
  198. package/backend/dist/platform/jobs/documentIngestionEnqueuer.js.map +1 -0
  199. package/backend/dist/platform/jobs/domainJobContracts.d.ts +30 -0
  200. package/backend/dist/platform/jobs/domainJobContracts.d.ts.map +1 -0
  201. package/backend/dist/platform/jobs/domainJobContracts.js +53 -0
  202. package/backend/dist/platform/jobs/domainJobContracts.js.map +1 -0
  203. package/backend/dist/platform/jobs/domainJobHandlers.d.ts +11 -0
  204. package/backend/dist/platform/jobs/domainJobHandlers.d.ts.map +1 -0
  205. package/backend/dist/platform/jobs/domainJobHandlers.js +612 -0
  206. package/backend/dist/platform/jobs/domainJobHandlers.js.map +1 -0
  207. package/backend/dist/platform/jobs/durableEventIdentity.d.ts +8 -0
  208. package/backend/dist/platform/jobs/durableEventIdentity.d.ts.map +1 -0
  209. package/backend/dist/platform/jobs/durableEventIdentity.js +33 -0
  210. package/backend/dist/platform/jobs/durableEventIdentity.js.map +1 -0
  211. package/backend/dist/platform/jobs/durableJobRuntime.d.ts +57 -0
  212. package/backend/dist/platform/jobs/durableJobRuntime.d.ts.map +1 -0
  213. package/backend/dist/platform/jobs/durableJobRuntime.js +131 -0
  214. package/backend/dist/platform/jobs/durableJobRuntime.js.map +1 -0
  215. package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts +28 -0
  216. package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts.map +1 -0
  217. package/backend/dist/platform/jobs/durableJobRuntimeBackend.js +62 -0
  218. package/backend/dist/platform/jobs/durableJobRuntimeBackend.js.map +1 -0
  219. package/backend/dist/platform/jobs/durableJobService.d.ts +85 -0
  220. package/backend/dist/platform/jobs/durableJobService.d.ts.map +1 -0
  221. package/backend/dist/platform/jobs/durableJobService.js +726 -0
  222. package/backend/dist/platform/jobs/durableJobService.js.map +1 -0
  223. package/backend/dist/platform/jobs/durableJobTypes.d.ts +195 -0
  224. package/backend/dist/platform/jobs/durableJobTypes.d.ts.map +1 -0
  225. package/backend/dist/platform/jobs/durableJobTypes.js +72 -0
  226. package/backend/dist/platform/jobs/durableJobTypes.js.map +1 -0
  227. package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts +87 -0
  228. package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts.map +1 -0
  229. package/backend/dist/platform/jobs/embeddedDurableJobWorker.js +429 -0
  230. package/backend/dist/platform/jobs/embeddedDurableJobWorker.js.map +1 -0
  231. package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts +3 -0
  232. package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts.map +1 -0
  233. package/backend/dist/platform/jobs/identityDeletionEnqueuer.js +36 -0
  234. package/backend/dist/platform/jobs/identityDeletionEnqueuer.js.map +1 -0
  235. package/backend/dist/platform/jobs/index.d.ts +18 -0
  236. package/backend/dist/platform/jobs/index.d.ts.map +1 -0
  237. package/backend/dist/platform/jobs/index.js +34 -0
  238. package/backend/dist/platform/jobs/index.js.map +1 -0
  239. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts +4 -0
  240. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts.map +1 -0
  241. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js +25 -0
  242. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js.map +1 -0
  243. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts +4 -0
  244. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts.map +1 -0
  245. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js +23 -0
  246. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js.map +1 -0
  247. package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts +11 -0
  248. package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts.map +1 -0
  249. package/backend/dist/platform/jobs/postgresDurableJobMigration.js +106 -0
  250. package/backend/dist/platform/jobs/postgresDurableJobMigration.js.map +1 -0
  251. package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts +88 -0
  252. package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts.map +1 -0
  253. package/backend/dist/platform/jobs/postgresDurableJobRepository.js +1185 -0
  254. package/backend/dist/platform/jobs/postgresDurableJobRepository.js.map +1 -0
  255. package/backend/dist/platform/jobs/postgresDurableJobService.d.ts +86 -0
  256. package/backend/dist/platform/jobs/postgresDurableJobService.d.ts.map +1 -0
  257. package/backend/dist/platform/jobs/postgresDurableJobService.js +696 -0
  258. package/backend/dist/platform/jobs/postgresDurableJobService.js.map +1 -0
  259. package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts +53 -0
  260. package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts.map +1 -0
  261. package/backend/dist/platform/jobs/postgresDurableJobWorker.js +393 -0
  262. package/backend/dist/platform/jobs/postgresDurableJobWorker.js.map +1 -0
  263. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts +3 -0
  264. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts.map +1 -0
  265. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js +43 -0
  266. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js.map +1 -0
  267. package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts +166 -0
  268. package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts.map +1 -0
  269. package/backend/dist/platform/jobs/sqliteDurableJobRepository.js +1008 -0
  270. package/backend/dist/platform/jobs/sqliteDurableJobRepository.js.map +1 -0
  271. package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts +4 -0
  272. package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts.map +1 -0
  273. package/backend/dist/platform/jobs/videoGenerationEnqueuer.js +46 -0
  274. package/backend/dist/platform/jobs/videoGenerationEnqueuer.js.map +1 -0
  275. package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts +3 -0
  276. package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts.map +1 -0
  277. package/backend/dist/platform/jobs/workExecutionEnqueuer.js +38 -0
  278. package/backend/dist/platform/jobs/workExecutionEnqueuer.js.map +1 -0
  279. package/backend/dist/platform/ollamaRuntimeConfig.d.ts +40 -0
  280. package/backend/dist/platform/ollamaRuntimeConfig.d.ts.map +1 -0
  281. package/backend/dist/platform/ollamaRuntimeConfig.js +72 -0
  282. package/backend/dist/platform/ollamaRuntimeConfig.js.map +1 -0
  283. package/backend/dist/platform/recovery/backupArchive.d.ts +120 -0
  284. package/backend/dist/platform/recovery/backupArchive.d.ts.map +1 -0
  285. package/backend/dist/platform/recovery/backupArchive.js +842 -0
  286. package/backend/dist/platform/recovery/backupArchive.js.map +1 -0
  287. package/backend/dist/platform/recovery/index.d.ts +3 -0
  288. package/backend/dist/platform/recovery/index.d.ts.map +1 -0
  289. package/backend/dist/platform/recovery/index.js +8 -0
  290. package/backend/dist/platform/recovery/index.js.map +1 -0
  291. package/backend/dist/platform/recovery/teamBackupArchive.d.ts +98 -0
  292. package/backend/dist/platform/recovery/teamBackupArchive.d.ts.map +1 -0
  293. package/backend/dist/platform/recovery/teamBackupArchive.js +1203 -0
  294. package/backend/dist/platform/recovery/teamBackupArchive.js.map +1 -0
  295. package/backend/dist/platform/runtimeConfig.d.ts +70 -0
  296. package/backend/dist/platform/runtimeConfig.d.ts.map +1 -0
  297. package/backend/dist/platform/runtimeConfig.js +205 -0
  298. package/backend/dist/platform/runtimeConfig.js.map +1 -0
  299. package/backend/dist/platform/storage/aesGcmKeyring.d.ts +26 -0
  300. package/backend/dist/platform/storage/aesGcmKeyring.d.ts.map +1 -0
  301. package/backend/dist/platform/storage/aesGcmKeyring.js +135 -0
  302. package/backend/dist/platform/storage/aesGcmKeyring.js.map +1 -0
  303. package/backend/dist/platform/storage/blobReferenceRepository.d.ts +36 -0
  304. package/backend/dist/platform/storage/blobReferenceRepository.d.ts.map +1 -0
  305. package/backend/dist/platform/storage/blobReferenceRepository.js +117 -0
  306. package/backend/dist/platform/storage/blobReferenceRepository.js.map +1 -0
  307. package/backend/dist/platform/storage/blobStore.d.ts +111 -0
  308. package/backend/dist/platform/storage/blobStore.d.ts.map +1 -0
  309. package/backend/dist/platform/storage/blobStore.js +46 -0
  310. package/backend/dist/platform/storage/blobStore.js.map +1 -0
  311. package/backend/dist/platform/storage/documentVectorIndex.d.ts +44 -0
  312. package/backend/dist/platform/storage/documentVectorIndex.d.ts.map +1 -0
  313. package/backend/dist/platform/storage/documentVectorIndex.js +110 -0
  314. package/backend/dist/platform/storage/documentVectorIndex.js.map +1 -0
  315. package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts +82 -0
  316. package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts.map +1 -0
  317. package/backend/dist/platform/storage/durableBlobQuotaPolicy.js +583 -0
  318. package/backend/dist/platform/storage/durableBlobQuotaPolicy.js.map +1 -0
  319. package/backend/dist/platform/storage/index.d.ts +19 -0
  320. package/backend/dist/platform/storage/index.d.ts.map +1 -0
  321. package/backend/dist/platform/storage/index.js +35 -0
  322. package/backend/dist/platform/storage/index.js.map +1 -0
  323. package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts +120 -0
  324. package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts.map +1 -0
  325. package/backend/dist/platform/storage/localEncryptedBlobStore.js +1205 -0
  326. package/backend/dist/platform/storage/localEncryptedBlobStore.js.map +1 -0
  327. package/backend/dist/platform/storage/personaMemoryIndexing.d.ts +12 -0
  328. package/backend/dist/platform/storage/personaMemoryIndexing.d.ts.map +1 -0
  329. package/backend/dist/platform/storage/personaMemoryIndexing.js +25 -0
  330. package/backend/dist/platform/storage/personaMemoryIndexing.js.map +1 -0
  331. package/backend/dist/platform/storage/pgVectorStore.d.ts +37 -0
  332. package/backend/dist/platform/storage/pgVectorStore.d.ts.map +1 -0
  333. package/backend/dist/platform/storage/pgVectorStore.js +493 -0
  334. package/backend/dist/platform/storage/pgVectorStore.js.map +1 -0
  335. package/backend/dist/platform/storage/platformDomainRepositories.d.ts +244 -0
  336. package/backend/dist/platform/storage/platformDomainRepositories.d.ts.map +1 -0
  337. package/backend/dist/platform/storage/platformDomainRepositories.js +7 -0
  338. package/backend/dist/platform/storage/platformDomainRepositories.js.map +1 -0
  339. package/backend/dist/platform/storage/platformStorageRuntime.d.ts +35 -0
  340. package/backend/dist/platform/storage/platformStorageRuntime.d.ts.map +1 -0
  341. package/backend/dist/platform/storage/platformStorageRuntime.js +299 -0
  342. package/backend/dist/platform/storage/platformStorageRuntime.js.map +1 -0
  343. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts +4 -0
  344. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts.map +1 -0
  345. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js +1017 -0
  346. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js.map +1 -0
  347. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts +4 -0
  348. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts.map +1 -0
  349. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js +40 -0
  350. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js.map +1 -0
  351. package/backend/dist/platform/storage/resourceContentCleanup.d.ts +29 -0
  352. package/backend/dist/platform/storage/resourceContentCleanup.d.ts.map +1 -0
  353. package/backend/dist/platform/storage/resourceContentCleanup.js +100 -0
  354. package/backend/dist/platform/storage/resourceContentCleanup.js.map +1 -0
  355. package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts +14 -0
  356. package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts.map +1 -0
  357. package/backend/dist/platform/storage/resourceDeletionLifecycle.js +31 -0
  358. package/backend/dist/platform/storage/resourceDeletionLifecycle.js.map +1 -0
  359. package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts +140 -0
  360. package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts.map +1 -0
  361. package/backend/dist/platform/storage/s3EncryptedBlobStore.js +1309 -0
  362. package/backend/dist/platform/storage/s3EncryptedBlobStore.js.map +1 -0
  363. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts +71 -0
  364. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts.map +1 -0
  365. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js +766 -0
  366. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js.map +1 -0
  367. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts +4 -0
  368. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts.map +1 -0
  369. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js +1037 -0
  370. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js.map +1 -0
  371. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts +25 -0
  372. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts.map +1 -0
  373. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js +1292 -0
  374. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js.map +1 -0
  375. package/backend/dist/platform/storage/storageFactory.d.ts +81 -0
  376. package/backend/dist/platform/storage/storageFactory.d.ts.map +1 -0
  377. package/backend/dist/platform/storage/storageFactory.js +518 -0
  378. package/backend/dist/platform/storage/storageFactory.js.map +1 -0
  379. package/backend/dist/platform/storage/storageSchemaContracts.d.ts +22 -0
  380. package/backend/dist/platform/storage/storageSchemaContracts.d.ts.map +1 -0
  381. package/backend/dist/platform/storage/storageSchemaContracts.js +299 -0
  382. package/backend/dist/platform/storage/storageSchemaContracts.js.map +1 -0
  383. package/backend/dist/platform/storage/vectorStore.d.ts +117 -0
  384. package/backend/dist/platform/storage/vectorStore.d.ts.map +1 -0
  385. package/backend/dist/platform/storage/vectorStore.js +40 -0
  386. package/backend/dist/platform/storage/vectorStore.js.map +1 -0
  387. package/backend/dist/platform/workPersistence/index.d.ts +9 -0
  388. package/backend/dist/platform/workPersistence/index.d.ts.map +1 -0
  389. package/backend/dist/platform/workPersistence/index.js +14 -0
  390. package/backend/dist/platform/workPersistence/index.js.map +1 -0
  391. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts +9 -0
  392. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts.map +1 -0
  393. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js +47 -0
  394. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js.map +1 -0
  395. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts +3 -0
  396. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts.map +1 -0
  397. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js +28 -0
  398. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js.map +1 -0
  399. package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts +3 -0
  400. package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts.map +1 -0
  401. package/backend/dist/platform/workPersistence/postgresWorkMigration.js +101 -0
  402. package/backend/dist/platform/workPersistence/postgresWorkMigration.js.map +1 -0
  403. package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts +79 -0
  404. package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts.map +1 -0
  405. package/backend/dist/platform/workPersistence/postgresWorkPersistence.js +521 -0
  406. package/backend/dist/platform/workPersistence/postgresWorkPersistence.js.map +1 -0
  407. package/backend/dist/platform/workPersistence/service.d.ts +6 -0
  408. package/backend/dist/platform/workPersistence/service.d.ts.map +1 -0
  409. package/backend/dist/platform/workPersistence/service.js +27 -0
  410. package/backend/dist/platform/workPersistence/service.js.map +1 -0
  411. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts +77 -0
  412. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts.map +1 -0
  413. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js +463 -0
  414. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js.map +1 -0
  415. package/backend/dist/platform/workPersistence/types.d.ts +159 -0
  416. package/backend/dist/platform/workPersistence/types.d.ts.map +1 -0
  417. package/backend/dist/platform/workPersistence/types.js +13 -0
  418. package/backend/dist/platform/workPersistence/types.js.map +1 -0
  419. package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts +13 -0
  420. package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts.map +1 -0
  421. package/backend/dist/platform/workPersistence/workExecutionTypes.js +7 -0
  422. package/backend/dist/platform/workPersistence/workExecutionTypes.js.map +1 -0
  423. package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts +8 -0
  424. package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts.map +1 -0
  425. package/backend/dist/platform/workPersistence/workMessageContentCodec.js +25 -0
  426. package/backend/dist/platform/workPersistence/workMessageContentCodec.js.map +1 -0
  427. package/backend/dist/platform/workPersistence/workTextSafety.d.ts +3 -0
  428. package/backend/dist/platform/workPersistence/workTextSafety.d.ts.map +1 -0
  429. package/backend/dist/platform/workPersistence/workTextSafety.js +8 -0
  430. package/backend/dist/platform/workPersistence/workTextSafety.js.map +1 -0
  431. package/backend/dist/routes/agentCli.js +1 -1
  432. package/backend/dist/routes/agentCli.js.map +1 -1
  433. package/backend/dist/routes/artifacts.d.ts.map +1 -1
  434. package/backend/dist/routes/artifacts.js +2 -1
  435. package/backend/dist/routes/artifacts.js.map +1 -1
  436. package/backend/dist/routes/auth.d.ts.map +1 -1
  437. package/backend/dist/routes/auth.js +64 -18
  438. package/backend/dist/routes/auth.js.map +1 -1
  439. package/backend/dist/routes/chat.d.ts.map +1 -1
  440. package/backend/dist/routes/chat.js +519 -85
  441. package/backend/dist/routes/chat.js.map +1 -1
  442. package/backend/dist/routes/documents.d.ts.map +1 -1
  443. package/backend/dist/routes/documents.js +134 -28
  444. package/backend/dist/routes/documents.js.map +1 -1
  445. package/backend/dist/routes/embeddings.d.ts.map +1 -1
  446. package/backend/dist/routes/embeddings.js +2 -1
  447. package/backend/dist/routes/embeddings.js.map +1 -1
  448. package/backend/dist/routes/health.d.ts +3 -0
  449. package/backend/dist/routes/health.d.ts.map +1 -0
  450. package/backend/dist/routes/health.js +52 -0
  451. package/backend/dist/routes/health.js.map +1 -0
  452. package/backend/dist/routes/huggingfaceHub.d.ts.map +1 -1
  453. package/backend/dist/routes/huggingfaceHub.js +2 -1
  454. package/backend/dist/routes/huggingfaceHub.js.map +1 -1
  455. package/backend/dist/routes/imageGen.d.ts.map +1 -1
  456. package/backend/dist/routes/imageGen.js +42 -10
  457. package/backend/dist/routes/imageGen.js.map +1 -1
  458. package/backend/dist/routes/jobs.d.ts +3 -0
  459. package/backend/dist/routes/jobs.d.ts.map +1 -0
  460. package/backend/dist/routes/jobs.js +117 -0
  461. package/backend/dist/routes/jobs.js.map +1 -0
  462. package/backend/dist/routes/libreClaw.d.ts.map +1 -1
  463. package/backend/dist/routes/libreClaw.js +10 -7
  464. package/backend/dist/routes/libreClaw.js.map +1 -1
  465. package/backend/dist/routes/media.d.ts.map +1 -1
  466. package/backend/dist/routes/media.js +523 -77
  467. package/backend/dist/routes/media.js.map +1 -1
  468. package/backend/dist/routes/notes.d.ts.map +1 -1
  469. package/backend/dist/routes/notes.js +21 -21
  470. package/backend/dist/routes/notes.js.map +1 -1
  471. package/backend/dist/routes/ollama.d.ts.map +1 -1
  472. package/backend/dist/routes/ollama.js +40 -12
  473. package/backend/dist/routes/ollama.js.map +1 -1
  474. package/backend/dist/routes/personas.d.ts.map +1 -1
  475. package/backend/dist/routes/personas.js +4 -2
  476. package/backend/dist/routes/personas.js.map +1 -1
  477. package/backend/dist/routes/plugins.d.ts.map +1 -1
  478. package/backend/dist/routes/plugins.js +79 -51
  479. package/backend/dist/routes/plugins.js.map +1 -1
  480. package/backend/dist/routes/preferences.d.ts.map +1 -1
  481. package/backend/dist/routes/preferences.js +290 -25
  482. package/backend/dist/routes/preferences.js.map +1 -1
  483. package/backend/dist/routes/search.d.ts.map +1 -1
  484. package/backend/dist/routes/search.js +23 -14
  485. package/backend/dist/routes/search.js.map +1 -1
  486. package/backend/dist/routes/stt.d.ts +9 -0
  487. package/backend/dist/routes/stt.d.ts.map +1 -0
  488. package/backend/dist/routes/stt.js +217 -0
  489. package/backend/dist/routes/stt.js.map +1 -0
  490. package/backend/dist/routes/systemDiagnostics.d.ts.map +1 -1
  491. package/backend/dist/routes/systemDiagnostics.js +2 -1
  492. package/backend/dist/routes/systemDiagnostics.js.map +1 -1
  493. package/backend/dist/routes/tts.d.ts.map +1 -1
  494. package/backend/dist/routes/tts.js +577 -28
  495. package/backend/dist/routes/tts.js.map +1 -1
  496. package/backend/dist/routes/users.d.ts.map +1 -1
  497. package/backend/dist/routes/users.js +16 -25
  498. package/backend/dist/routes/users.js.map +1 -1
  499. package/backend/dist/routes/work.d.ts.map +1 -1
  500. package/backend/dist/routes/work.js +167 -113
  501. package/backend/dist/routes/work.js.map +1 -1
  502. package/backend/dist/services/agentAccessService.d.ts +2 -2
  503. package/backend/dist/services/agentAccessService.d.ts.map +1 -1
  504. package/backend/dist/services/agentAccessService.js +5 -14
  505. package/backend/dist/services/agentAccessService.js.map +1 -1
  506. package/backend/dist/services/agentCliService.d.ts +3 -2
  507. package/backend/dist/services/agentCliService.d.ts.map +1 -1
  508. package/backend/dist/services/agentCliService.js +44 -16
  509. package/backend/dist/services/agentCliService.js.map +1 -1
  510. package/backend/dist/services/assistantCompletionService.d.ts +2 -1
  511. package/backend/dist/services/assistantCompletionService.d.ts.map +1 -1
  512. package/backend/dist/services/assistantCompletionService.js +7 -3
  513. package/backend/dist/services/assistantCompletionService.js.map +1 -1
  514. package/backend/dist/services/authService.d.ts +7 -2
  515. package/backend/dist/services/authService.d.ts.map +1 -1
  516. package/backend/dist/services/authService.js +23 -10
  517. package/backend/dist/services/authService.js.map +1 -1
  518. package/backend/dist/services/chatGenerationService.d.ts +5 -4
  519. package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
  520. package/backend/dist/services/chatGenerationService.js +23 -17
  521. package/backend/dist/services/chatGenerationService.js.map +1 -1
  522. package/backend/dist/services/chatRequestService.d.ts +4 -3
  523. package/backend/dist/services/chatRequestService.d.ts.map +1 -1
  524. package/backend/dist/services/chatRequestService.js +3 -3
  525. package/backend/dist/services/chatRequestService.js.map +1 -1
  526. package/backend/dist/services/chatService.d.ts +66 -16
  527. package/backend/dist/services/chatService.d.ts.map +1 -1
  528. package/backend/dist/services/chatService.js +402 -111
  529. package/backend/dist/services/chatService.js.map +1 -1
  530. package/backend/dist/services/codexOAuthService.d.ts +2 -2
  531. package/backend/dist/services/codexOAuthService.d.ts.map +1 -1
  532. package/backend/dist/services/codexOAuthService.js +63 -7
  533. package/backend/dist/services/codexOAuthService.js.map +1 -1
  534. package/backend/dist/services/dataArchiveService.d.ts +88 -0
  535. package/backend/dist/services/dataArchiveService.d.ts.map +1 -0
  536. package/backend/dist/services/dataArchiveService.js +1027 -0
  537. package/backend/dist/services/dataArchiveService.js.map +1 -0
  538. package/backend/dist/services/documentService.d.ts +67 -14
  539. package/backend/dist/services/documentService.d.ts.map +1 -1
  540. package/backend/dist/services/documentService.js +938 -193
  541. package/backend/dist/services/documentService.js.map +1 -1
  542. package/backend/dist/services/durableChatCompletion.d.ts +16 -0
  543. package/backend/dist/services/durableChatCompletion.d.ts.map +1 -0
  544. package/backend/dist/services/durableChatCompletion.js +34 -0
  545. package/backend/dist/services/durableChatCompletion.js.map +1 -0
  546. package/backend/dist/services/durableChatGenerationService.d.ts +19 -0
  547. package/backend/dist/services/durableChatGenerationService.d.ts.map +1 -0
  548. package/backend/dist/services/durableChatGenerationService.js +341 -0
  549. package/backend/dist/services/durableChatGenerationService.js.map +1 -0
  550. package/backend/dist/services/embeddingService.d.ts +1 -1
  551. package/backend/dist/services/embeddingService.d.ts.map +1 -1
  552. package/backend/dist/services/embeddingService.js +16 -13
  553. package/backend/dist/services/embeddingService.js.map +1 -1
  554. package/backend/dist/services/encryptionService.d.ts +28 -1
  555. package/backend/dist/services/encryptionService.d.ts.map +1 -1
  556. package/backend/dist/services/encryptionService.js +131 -51
  557. package/backend/dist/services/encryptionService.js.map +1 -1
  558. package/backend/dist/services/followUpService.d.ts +1 -1
  559. package/backend/dist/services/followUpService.d.ts.map +1 -1
  560. package/backend/dist/services/followUpService.js +1 -1
  561. package/backend/dist/services/followUpService.js.map +1 -1
  562. package/backend/dist/services/galleryService.d.ts +38 -37
  563. package/backend/dist/services/galleryService.d.ts.map +1 -1
  564. package/backend/dist/services/galleryService.js +356 -251
  565. package/backend/dist/services/galleryService.js.map +1 -1
  566. package/backend/dist/services/healthService.d.ts +65 -0
  567. package/backend/dist/services/healthService.d.ts.map +1 -0
  568. package/backend/dist/services/healthService.js +379 -0
  569. package/backend/dist/services/healthService.js.map +1 -0
  570. package/backend/dist/services/legacyCiphertextIntegrity.d.ts +40 -0
  571. package/backend/dist/services/legacyCiphertextIntegrity.d.ts.map +1 -0
  572. package/backend/dist/services/legacyCiphertextIntegrity.js +406 -0
  573. package/backend/dist/services/legacyCiphertextIntegrity.js.map +1 -0
  574. package/backend/dist/services/mediaGenerationJobService.d.ts +27 -5
  575. package/backend/dist/services/mediaGenerationJobService.d.ts.map +1 -1
  576. package/backend/dist/services/mediaGenerationJobService.js +185 -55
  577. package/backend/dist/services/mediaGenerationJobService.js.map +1 -1
  578. package/backend/dist/services/memoryService.d.ts +7 -83
  579. package/backend/dist/services/memoryService.d.ts.map +1 -1
  580. package/backend/dist/services/memoryService.js +428 -573
  581. package/backend/dist/services/memoryService.js.map +1 -1
  582. package/backend/dist/services/memoryUtils.d.ts.map +1 -1
  583. package/backend/dist/services/memoryUtils.js +8 -1
  584. package/backend/dist/services/memoryUtils.js.map +1 -1
  585. package/backend/dist/services/modelAccessService.d.ts +3 -3
  586. package/backend/dist/services/modelAccessService.d.ts.map +1 -1
  587. package/backend/dist/services/modelAccessService.js +8 -16
  588. package/backend/dist/services/modelAccessService.js.map +1 -1
  589. package/backend/dist/services/mutationEngineService.d.ts +0 -7
  590. package/backend/dist/services/mutationEngineService.d.ts.map +1 -1
  591. package/backend/dist/services/mutationEngineService.js +7 -78
  592. package/backend/dist/services/mutationEngineService.js.map +1 -1
  593. package/backend/dist/services/ollamaService.d.ts +4 -4
  594. package/backend/dist/services/ollamaService.d.ts.map +1 -1
  595. package/backend/dist/services/ollamaService.js +62 -31
  596. package/backend/dist/services/ollamaService.js.map +1 -1
  597. package/backend/dist/services/personaService.d.ts.map +1 -1
  598. package/backend/dist/services/personaService.js +19 -54
  599. package/backend/dist/services/personaService.js.map +1 -1
  600. package/backend/dist/services/pluginActivationService.d.ts +6 -5
  601. package/backend/dist/services/pluginActivationService.d.ts.map +1 -1
  602. package/backend/dist/services/pluginActivationService.js +36 -76
  603. package/backend/dist/services/pluginActivationService.js.map +1 -1
  604. package/backend/dist/services/pluginAudioGenerationService.d.ts +11 -6
  605. package/backend/dist/services/pluginAudioGenerationService.d.ts.map +1 -1
  606. package/backend/dist/services/pluginAudioGenerationService.js +74 -16
  607. package/backend/dist/services/pluginAudioGenerationService.js.map +1 -1
  608. package/backend/dist/services/pluginCacheInvalidation.d.ts +38 -0
  609. package/backend/dist/services/pluginCacheInvalidation.d.ts.map +1 -0
  610. package/backend/dist/services/pluginCacheInvalidation.js +198 -0
  611. package/backend/dist/services/pluginCacheInvalidation.js.map +1 -0
  612. package/backend/dist/services/pluginCapabilityRegistryService.d.ts +3 -3
  613. package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
  614. package/backend/dist/services/pluginCapabilityRegistryService.js +11 -7
  615. package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
  616. package/backend/dist/services/pluginCredentialsService.d.ts +9 -8
  617. package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
  618. package/backend/dist/services/pluginCredentialsService.js +48 -89
  619. package/backend/dist/services/pluginCredentialsService.js.map +1 -1
  620. package/backend/dist/services/pluginEmbeddingService.d.ts +8 -7
  621. package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
  622. package/backend/dist/services/pluginEmbeddingService.js +13 -11
  623. package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
  624. package/backend/dist/services/pluginImageGenerationService.d.ts +10 -8
  625. package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
  626. package/backend/dist/services/pluginImageGenerationService.js +119 -14
  627. package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
  628. package/backend/dist/services/pluginSTTService.d.ts +47 -0
  629. package/backend/dist/services/pluginSTTService.d.ts.map +1 -0
  630. package/backend/dist/services/pluginSTTService.js +199 -0
  631. package/backend/dist/services/pluginSTTService.js.map +1 -0
  632. package/backend/dist/services/pluginService.d.ts +94 -40
  633. package/backend/dist/services/pluginService.d.ts.map +1 -1
  634. package/backend/dist/services/pluginService.js +799 -274
  635. package/backend/dist/services/pluginService.js.map +1 -1
  636. package/backend/dist/services/pluginTTSService.d.ts +26 -8
  637. package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
  638. package/backend/dist/services/pluginTTSService.js +277 -25
  639. package/backend/dist/services/pluginTTSService.js.map +1 -1
  640. package/backend/dist/services/pluginUsageService.d.ts +4 -4
  641. package/backend/dist/services/pluginUsageService.d.ts.map +1 -1
  642. package/backend/dist/services/pluginUsageService.js +44 -93
  643. package/backend/dist/services/pluginUsageService.js.map +1 -1
  644. package/backend/dist/services/pluginVariablesService.d.ts +14 -7
  645. package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
  646. package/backend/dist/services/pluginVariablesService.js +116 -81
  647. package/backend/dist/services/pluginVariablesService.js.map +1 -1
  648. package/backend/dist/services/pluginVideoGenerationService.d.ts +19 -8
  649. package/backend/dist/services/pluginVideoGenerationService.d.ts.map +1 -1
  650. package/backend/dist/services/pluginVideoGenerationService.js +116 -20
  651. package/backend/dist/services/pluginVideoGenerationService.js.map +1 -1
  652. package/backend/dist/services/preferencesService.d.ts +31 -21
  653. package/backend/dist/services/preferencesService.d.ts.map +1 -1
  654. package/backend/dist/services/preferencesService.js +104 -102
  655. package/backend/dist/services/preferencesService.js.map +1 -1
  656. package/backend/dist/services/recoveryInventoryService.d.ts +244 -0
  657. package/backend/dist/services/recoveryInventoryService.d.ts.map +1 -0
  658. package/backend/dist/services/recoveryInventoryService.js +1436 -0
  659. package/backend/dist/services/recoveryInventoryService.js.map +1 -0
  660. package/backend/dist/services/simpleGitHubOAuth.js +3 -3
  661. package/backend/dist/services/simpleGitHubOAuth.js.map +1 -1
  662. package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -1
  663. package/backend/dist/services/simpleHuggingFaceOAuth.js +3 -3
  664. package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -1
  665. package/backend/dist/services/systemDiagnosticsService.d.ts.map +1 -1
  666. package/backend/dist/services/systemDiagnosticsService.js +2 -2
  667. package/backend/dist/services/systemDiagnosticsService.js.map +1 -1
  668. package/backend/dist/services/systemSettingsService.d.ts +5 -0
  669. package/backend/dist/services/systemSettingsService.d.ts.map +1 -0
  670. package/backend/dist/services/systemSettingsService.js +24 -0
  671. package/backend/dist/services/systemSettingsService.js.map +1 -0
  672. package/backend/dist/services/titleGenerationService.d.ts +1 -1
  673. package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
  674. package/backend/dist/services/titleGenerationService.js +1 -1
  675. package/backend/dist/services/titleGenerationService.js.map +1 -1
  676. package/backend/dist/services/voiceProfileService.d.ts +44 -0
  677. package/backend/dist/services/voiceProfileService.d.ts.map +1 -0
  678. package/backend/dist/services/voiceProfileService.js +195 -0
  679. package/backend/dist/services/voiceProfileService.js.map +1 -0
  680. package/backend/dist/services/webSearchService.d.ts +7 -7
  681. package/backend/dist/services/webSearchService.d.ts.map +1 -1
  682. package/backend/dist/services/webSearchService.js +40 -35
  683. package/backend/dist/services/webSearchService.js.map +1 -1
  684. package/backend/dist/services/websocketTicketService.d.ts +39 -0
  685. package/backend/dist/services/websocketTicketService.d.ts.map +1 -0
  686. package/backend/dist/services/websocketTicketService.js +183 -0
  687. package/backend/dist/services/websocketTicketService.js.map +1 -0
  688. package/backend/dist/services/workAccessService.d.ts +3 -3
  689. package/backend/dist/services/workAccessService.d.ts.map +1 -1
  690. package/backend/dist/services/workAccessService.js +8 -16
  691. package/backend/dist/services/workAccessService.js.map +1 -1
  692. package/backend/dist/services/workAdminService.d.ts +3 -3
  693. package/backend/dist/services/workAdminService.d.ts.map +1 -1
  694. package/backend/dist/services/workAdminService.js +4 -4
  695. package/backend/dist/services/workAdminService.js.map +1 -1
  696. package/backend/dist/services/workAgentService.d.ts +25 -1
  697. package/backend/dist/services/workAgentService.d.ts.map +1 -1
  698. package/backend/dist/services/workAgentService.js +294 -126
  699. package/backend/dist/services/workAgentService.js.map +1 -1
  700. package/backend/dist/services/workEventService.d.ts +15 -2
  701. package/backend/dist/services/workEventService.d.ts.map +1 -1
  702. package/backend/dist/services/workEventService.js +201 -3
  703. package/backend/dist/services/workEventService.js.map +1 -1
  704. package/backend/dist/services/workKubernetesDriver.d.ts +8 -7
  705. package/backend/dist/services/workKubernetesDriver.d.ts.map +1 -1
  706. package/backend/dist/services/workKubernetesDriver.js +65 -21
  707. package/backend/dist/services/workKubernetesDriver.js.map +1 -1
  708. package/backend/dist/services/workModelProviderService.d.ts +2 -2
  709. package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
  710. package/backend/dist/services/workModelProviderService.js +38 -34
  711. package/backend/dist/services/workModelProviderService.js.map +1 -1
  712. package/backend/dist/services/workPolicyService.d.ts +7 -7
  713. package/backend/dist/services/workPolicyService.d.ts.map +1 -1
  714. package/backend/dist/services/workPolicyService.js +50 -51
  715. package/backend/dist/services/workPolicyService.js.map +1 -1
  716. package/backend/dist/services/workPreviewProxyService.d.ts +8 -8
  717. package/backend/dist/services/workPreviewProxyService.d.ts.map +1 -1
  718. package/backend/dist/services/workPreviewProxyService.js +47 -44
  719. package/backend/dist/services/workPreviewProxyService.js.map +1 -1
  720. package/backend/dist/services/workRuntimeDriver.d.ts +21 -18
  721. package/backend/dist/services/workRuntimeDriver.d.ts.map +1 -1
  722. package/backend/dist/services/workRuntimeDriver.js +69 -20
  723. package/backend/dist/services/workRuntimeDriver.js.map +1 -1
  724. package/backend/dist/services/workRuntimeService.d.ts +18 -13
  725. package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
  726. package/backend/dist/services/workRuntimeService.js +438 -194
  727. package/backend/dist/services/workRuntimeService.js.map +1 -1
  728. package/backend/dist/services/workRuntimeShared.d.ts +2 -0
  729. package/backend/dist/services/workRuntimeShared.d.ts.map +1 -1
  730. package/backend/dist/services/workRuntimeShared.js.map +1 -1
  731. package/backend/dist/services/workTaskService.d.ts +42 -36
  732. package/backend/dist/services/workTaskService.d.ts.map +1 -1
  733. package/backend/dist/services/workTaskService.js +445 -350
  734. package/backend/dist/services/workTaskService.js.map +1 -1
  735. package/backend/dist/services/workTerminalService.d.ts +1 -1
  736. package/backend/dist/services/workTerminalService.d.ts.map +1 -1
  737. package/backend/dist/services/workTerminalService.js +33 -6
  738. package/backend/dist/services/workTerminalService.js.map +1 -1
  739. package/backend/dist/storage.d.ts +72 -40
  740. package/backend/dist/storage.d.ts.map +1 -1
  741. package/backend/dist/storage.js +312 -660
  742. package/backend/dist/storage.js.map +1 -1
  743. package/backend/dist/types/index.d.ts +28 -0
  744. package/backend/dist/types/index.d.ts.map +1 -1
  745. package/backend/dist/types/index.js.map +1 -1
  746. package/backend/dist/types/work.d.ts +7 -2
  747. package/backend/dist/types/work.d.ts.map +1 -1
  748. package/backend/dist/utils/chatCancellation.d.ts +48 -0
  749. package/backend/dist/utils/chatCancellation.d.ts.map +1 -0
  750. package/backend/dist/utils/chatCancellation.js +152 -0
  751. package/backend/dist/utils/chatCancellation.js.map +1 -0
  752. package/backend/dist/utils/chatDocumentContext.d.ts +1 -1
  753. package/backend/dist/utils/chatDocumentContext.d.ts.map +1 -1
  754. package/backend/dist/utils/chatDocumentContext.js +11 -5
  755. package/backend/dist/utils/chatDocumentContext.js.map +1 -1
  756. package/backend/dist/utils/chatStreamCoalescer.d.ts +15 -0
  757. package/backend/dist/utils/chatStreamCoalescer.d.ts.map +1 -0
  758. package/backend/dist/utils/chatStreamCoalescer.js +59 -0
  759. package/backend/dist/utils/chatStreamCoalescer.js.map +1 -0
  760. package/backend/dist/utils/dataDirectory.d.ts +49 -0
  761. package/backend/dist/utils/dataDirectory.d.ts.map +1 -0
  762. package/backend/dist/utils/dataDirectory.js +291 -0
  763. package/backend/dist/utils/dataDirectory.js.map +1 -0
  764. package/backend/dist/utils/generationUtils.d.ts.map +1 -1
  765. package/backend/dist/utils/generationUtils.js +18 -6
  766. package/backend/dist/utils/generationUtils.js.map +1 -1
  767. package/backend/dist/utils/jwt.d.ts.map +1 -1
  768. package/backend/dist/utils/jwt.js +2 -3
  769. package/backend/dist/utils/jwt.js.map +1 -1
  770. package/backend/dist/utils/ollamaModelDefaults.d.ts.map +1 -1
  771. package/backend/dist/utils/ollamaModelDefaults.js +2 -7
  772. package/backend/dist/utils/ollamaModelDefaults.js.map +1 -1
  773. package/backend/dist/utils/ollamaStreaming.d.ts +2 -1
  774. package/backend/dist/utils/ollamaStreaming.d.ts.map +1 -1
  775. package/backend/dist/utils/ollamaStreaming.js +49 -11
  776. package/backend/dist/utils/ollamaStreaming.js.map +1 -1
  777. package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -1
  778. package/backend/dist/utils/pluginConnectionVariables.js +11 -3
  779. package/backend/dist/utils/pluginConnectionVariables.js.map +1 -1
  780. package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -1
  781. package/backend/dist/utils/pluginDefinitionTrust.js +4 -3
  782. package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -1
  783. package/backend/dist/utils/pluginStreaming.d.ts +2 -1
  784. package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
  785. package/backend/dist/utils/pluginStreaming.js +5 -1
  786. package/backend/dist/utils/pluginStreaming.js.map +1 -1
  787. package/backend/dist/utils/pluginUpload.d.ts +1 -0
  788. package/backend/dist/utils/pluginUpload.d.ts.map +1 -1
  789. package/backend/dist/utils/pluginUpload.js +9 -2
  790. package/backend/dist/utils/pluginUpload.js.map +1 -1
  791. package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
  792. package/backend/dist/utils/pluginValidation.js +29 -1
  793. package/backend/dist/utils/pluginValidation.js.map +1 -1
  794. package/backend/dist/utils/sttAudioUpload.d.ts +24 -0
  795. package/backend/dist/utils/sttAudioUpload.d.ts.map +1 -0
  796. package/backend/dist/utils/sttAudioUpload.js +500 -0
  797. package/backend/dist/utils/sttAudioUpload.js.map +1 -0
  798. package/backend/dist/utils/ttsVoiceCloneUpload.d.ts +34 -0
  799. package/backend/dist/utils/ttsVoiceCloneUpload.d.ts.map +1 -0
  800. package/backend/dist/utils/ttsVoiceCloneUpload.js +224 -0
  801. package/backend/dist/utils/ttsVoiceCloneUpload.js.map +1 -0
  802. package/backend/dist/utils/websocketMessages.d.ts +2 -1
  803. package/backend/dist/utils/websocketMessages.d.ts.map +1 -1
  804. package/backend/dist/utils/websocketMessages.js +16 -2
  805. package/backend/dist/utils/websocketMessages.js.map +1 -1
  806. package/backend/dist/websocketServer.d.ts +4 -1
  807. package/backend/dist/websocketServer.d.ts.map +1 -1
  808. package/backend/dist/websocketServer.js +290 -44
  809. package/backend/dist/websocketServer.js.map +1 -1
  810. package/backend/dist/workTerminalServer.d.ts +9 -0
  811. package/backend/dist/workTerminalServer.d.ts.map +1 -1
  812. package/backend/dist/workTerminalServer.js +221 -52
  813. package/backend/dist/workTerminalServer.js.map +1 -1
  814. package/backend/dist/worker.d.ts +2 -0
  815. package/backend/dist/worker.d.ts.map +1 -0
  816. package/backend/dist/worker.js +250 -0
  817. package/backend/dist/worker.js.map +1 -0
  818. package/backend/package.json +19 -9
  819. package/bin/cli.js +126 -99
  820. package/bin/runtime-paths.js +108 -0
  821. package/frontend/dist/artifact-runtime/.build-fingerprint +1 -1
  822. package/frontend/dist/artifact-runtime/framer-motion.js +5 -5
  823. package/frontend/dist/artifact-runtime/lucide-react.js +1 -1
  824. package/frontend/dist/assets/index-CUhEG7E2.js +33 -0
  825. package/frontend/dist/assets/index-kxtZQLV6.css +1 -0
  826. package/frontend/dist/assets/{markdown-math-ClQbWekD.css → markdown-math-ClTedVi7.css} +1 -1
  827. package/frontend/dist/index.html +18 -18
  828. package/frontend/dist/js/{ArtifactContainer-Dy2Q0iIL.js → ArtifactContainer-BTEDhBnv.js} +1 -1
  829. package/frontend/dist/js/{ArtifactDemoPage-K79dWshB.js → ArtifactDemoPage-B0gN3YTl.js} +1 -1
  830. package/frontend/dist/js/{ArtifactSandboxFrame-DhqLNUtY.js → ArtifactSandboxFrame-CLBXQkZs.js} +3 -3
  831. package/frontend/dist/js/{ArtifactSlideOutPanel-Cl8JG7bz.js → ArtifactSlideOutPanel-CfqHPFdE.js} +1 -1
  832. package/frontend/dist/js/{Button-CTXHujOd.js → Button-BV44cTnj.js} +1 -1
  833. package/frontend/dist/js/ChatPage-DIkAXZWA.js +23 -0
  834. package/frontend/dist/js/{FirstTimeSetup-kHhRzGJ8.js → FirstTimeSetup-B8phXGNA.js} +1 -1
  835. package/frontend/dist/js/GalleryPage-W4uI043I.js +1 -0
  836. package/frontend/dist/js/{HomePage-C1L8WAXL.js → HomePage-DlxehbyO.js} +1 -1
  837. package/frontend/dist/js/{LibreClawPage-Dyua8IUu.js → LibreClawPage-CgD0_G_F.js} +1 -1
  838. package/frontend/dist/js/{ModelManagerModals-CuMRGUd-.js → ModelManagerModals-D7jIT3v1.js} +1 -1
  839. package/frontend/dist/js/{ModelSelector-CqHc-Ln4.js → ModelSelector-BYxJU1UV.js} +1 -1
  840. package/frontend/dist/js/ModelsPage-C4XdCKP5.js +2 -0
  841. package/frontend/dist/js/NotesPage-CDECOl4V.js +1 -0
  842. package/frontend/dist/js/{OptimizedSyntaxHighlighter-CWYUn9Oe.js → OptimizedSyntaxHighlighter-XwqZEoTf.js} +1 -1
  843. package/frontend/dist/js/{PersonasPage-D_6WBCH5.js → PersonasPage-CjSLPrgS.js} +2 -2
  844. package/frontend/dist/js/PluginUsagePage-DJOXJuH4.js +1 -0
  845. package/frontend/dist/js/RichMessageContent-Debeh6bi.js +3 -0
  846. package/frontend/dist/js/SettingsModal-cUqAeYUP.js +1 -0
  847. package/frontend/dist/js/{SettingsToggle-DLHlCDBl.js → SettingsToggle-WTa0rgvY.js} +1 -1
  848. package/frontend/dist/js/{SystemPage-BMWEet9e.js → SystemPage-DxPw0GS7.js} +1 -1
  849. package/frontend/dist/js/UserManagementPage-CEdYFe_Z.js +1 -0
  850. package/frontend/dist/js/WorkPage-DDVeuG_9.js +6 -0
  851. package/frontend/dist/js/api-IzobHGND.js +14 -0
  852. package/frontend/dist/js/appStore-DKwC2vgn.js +2 -0
  853. package/frontend/dist/js/ar-xTSvTq05.js +2 -0
  854. package/frontend/dist/js/authStore-OaTuapL7.js +4 -0
  855. package/frontend/dist/js/{babel-CmENXdZw.js → babel-D24oDI9y.js} +1 -1
  856. package/frontend/dist/js/bn-iYAsohEA.js +2 -0
  857. package/frontend/dist/js/chatStore-DXGUVLXD.js +3 -0
  858. package/frontend/dist/js/{config-DkV1ka7I.js → config-DPEEuTAe.js} +1 -1
  859. package/frontend/dist/js/cs-YBHN88Hb.js +2 -0
  860. package/frontend/dist/js/da-D7qlLy_k.js +2 -0
  861. package/frontend/dist/js/de-DV671k2c.js +2 -0
  862. package/frontend/dist/js/es-kyBgzNq-.js +2 -0
  863. package/frontend/dist/js/{estree-D5KP-qbw.js → estree-ChwJsD2w.js} +1 -1
  864. package/frontend/dist/js/fr-Cw1vut7I.js +2 -0
  865. package/frontend/dist/js/hi-DWEFC024.js +2 -0
  866. package/frontend/dist/js/{html-Cm9c2akd.js → html-DFrVjciF.js} +1 -1
  867. package/frontend/dist/js/id-DlMHjjy0.js +2 -0
  868. package/frontend/dist/js/is-B9E_a7dG.js +2 -0
  869. package/frontend/dist/js/it-DawmVbLC.js +2 -0
  870. package/frontend/dist/js/ja-DmVvwY3W.js +2 -0
  871. package/frontend/dist/js/ko-DzOPpkVs.js +2 -0
  872. package/frontend/dist/js/{markdown-B2u7CnKN.js → markdown-FLLx7b67.js} +1 -1
  873. package/frontend/dist/js/markdown-core-BmPPZiuD.js +31 -0
  874. package/frontend/dist/js/{markdown-math-B7FlYsmr.js → markdown-math-mH7AZ_mb.js} +6 -6
  875. package/frontend/dist/js/{messageCodeStyles-DalG2j6U.js → messageCodeStyles-CBkkZY4n.js} +1 -1
  876. package/frontend/dist/js/ms-DpsaOPht.js +2 -0
  877. package/frontend/dist/js/nl-B1d8W22n.js +2 -0
  878. package/frontend/dist/js/pl-nCncRVgt.js +2 -0
  879. package/frontend/dist/js/{postcss-B5WIGhAY.js → postcss-Bx9CTcIc.js} +1 -1
  880. package/frontend/dist/js/pt-DHw8fGuu.js +2 -0
  881. package/frontend/dist/js/{react-vendor-DPNXrO-8.js → react-vendor-C5yShNlM.js} +1 -1
  882. package/frontend/dist/js/{router-vendor-Ca9zqOqT.js → router-vendor-CbPDks39.js} +1 -1
  883. package/frontend/dist/js/ru-Derl_YP_.js +2 -0
  884. package/frontend/dist/js/{standalone-Dwm1daef.js → standalone-i8-5bg5p.js} +1 -1
  885. package/frontend/dist/js/sv-pJAfBVo0.js +2 -0
  886. package/frontend/dist/js/{syntax-highlight-Ca9bHsaz.js → syntax-highlight-3EEX6CGL.js} +3 -3
  887. package/frontend/dist/js/th-C_7fIGnk.js +2 -0
  888. package/frontend/dist/js/tr-CPqsJvaP.js +2 -0
  889. package/frontend/dist/js/{typescript-CwieSptM.js → typescript-CQ3x-Uni.js} +1 -1
  890. package/frontend/dist/js/{ui-BnDZpjfc.js → ui-BHhR3Vok.js} +2 -2
  891. package/frontend/dist/js/ui-vendor-D3Ahl1x5.js +177 -0
  892. package/frontend/dist/js/uk-3o8P_kFi.js +2 -0
  893. package/frontend/dist/js/{useTranslation-CXY69qNk.js → useTranslation-C3ei3mJq.js} +1 -1
  894. package/frontend/dist/js/{utils-BM0_0iFj.js → utils-CuC1beTY.js} +1 -1
  895. package/frontend/dist/js/{utils-vendor-1zob7nK9.js → utils-vendor-BBa8OxtB.js} +1 -1
  896. package/frontend/dist/js/vi-Dv6N7OVD.js +2 -0
  897. package/frontend/dist/js/{workApi-BOS7crs9.js → workApi-Czu69yWS.js} +2 -2
  898. package/frontend/dist/js/{yaml-QD4znPfZ.js → yaml-DioTxVLA.js} +1 -1
  899. package/frontend/dist/js/zh-qg5iqtPi.js +2 -0
  900. package/package.json +16 -5
  901. package/plugins/huggingface.json +12 -3
  902. package/plugins/llama-cpp.json +18 -6
  903. package/plugins/longcat-audiodit.json +114 -0
  904. package/plugins/openai.json +18 -0
  905. package/frontend/dist/assets/index-BBpNbfKW.js +0 -16
  906. package/frontend/dist/assets/index-BLATyFmD.css +0 -1
  907. package/frontend/dist/js/ChatPage-BBayfMLS.js +0 -16
  908. package/frontend/dist/js/GalleryPage-By8VI39Q.js +0 -1
  909. package/frontend/dist/js/ModelsPage-ODeXhDDk.js +0 -2
  910. package/frontend/dist/js/NotesPage-CApzDjOq.js +0 -1
  911. package/frontend/dist/js/PluginUsagePage-kutS6SOd.js +0 -1
  912. package/frontend/dist/js/RichMessageContent-g6WT75Te.js +0 -3
  913. package/frontend/dist/js/SettingsModal-B7z51BCx.js +0 -1
  914. package/frontend/dist/js/UserManagementPage-D08lM51c.js +0 -1
  915. package/frontend/dist/js/WorkPage-DdVLefsK.js +0 -6
  916. package/frontend/dist/js/api-CLEmGcEh.js +0 -14
  917. package/frontend/dist/js/appStore-CGdhvp9P.js +0 -2
  918. package/frontend/dist/js/ar-BTmB2WVm.js +0 -2
  919. package/frontend/dist/js/authStore-Dh3beEOq.js +0 -4
  920. package/frontend/dist/js/bn-CQnH7YVT.js +0 -2
  921. package/frontend/dist/js/chatStore-CDeYWL_q.js +0 -3
  922. package/frontend/dist/js/cs-oTTZkQXr.js +0 -2
  923. package/frontend/dist/js/da-Br0gB6J6.js +0 -2
  924. package/frontend/dist/js/de-DE2iztTF.js +0 -2
  925. package/frontend/dist/js/es-DgthfVtl.js +0 -2
  926. package/frontend/dist/js/fr-BjxjFwPh.js +0 -2
  927. package/frontend/dist/js/hi-D1q7E-9N.js +0 -2
  928. package/frontend/dist/js/id-CDJZqLTF.js +0 -2
  929. package/frontend/dist/js/is-BU7Um_Tq.js +0 -2
  930. package/frontend/dist/js/it-CdAxr8P_.js +0 -2
  931. package/frontend/dist/js/ja-BLbQwz9u.js +0 -2
  932. package/frontend/dist/js/ko-CY5lpkAe.js +0 -2
  933. package/frontend/dist/js/markdown-core-DHnR5Hw8.js +0 -16
  934. package/frontend/dist/js/ms-tQ8AYXEQ.js +0 -2
  935. package/frontend/dist/js/nl-CRNi2oWT.js +0 -2
  936. package/frontend/dist/js/pl-CWtFRS_W.js +0 -2
  937. package/frontend/dist/js/pt-C7SPoLF8.js +0 -2
  938. package/frontend/dist/js/ru-Dz4AX8xc.js +0 -2
  939. package/frontend/dist/js/sv-ETy5-boa.js +0 -2
  940. package/frontend/dist/js/th-DpuMqvxU.js +0 -2
  941. package/frontend/dist/js/tr-C-1AYAqg.js +0 -2
  942. package/frontend/dist/js/ui-vendor-xUzKqAXI.js +0 -177
  943. package/frontend/dist/js/uk-CyS680gr.js +0 -2
  944. package/frontend/dist/js/vi-BG8HuiTz.js +0 -2
  945. package/frontend/dist/js/zh-NCs2mkHj.js +0 -2
@@ -23,24 +23,97 @@ import codexOAuthService, { CODEX_OAUTH_PLUGIN_ID, } from './codexOAuthService.j
23
23
  import { userModel } from '../models/userModel.js';
24
24
  import pluginCredentialsService from './pluginCredentialsService.js';
25
25
  import pluginVariablesService from './pluginVariablesService.js';
26
+ import { ensurePluginCacheInvalidationSubscription, publishPluginCacheInvalidation, registerPluginCacheInvalidationListener, } from './pluginCacheInvalidation.js';
26
27
  import pluginActivationService from './pluginActivationService.js';
27
28
  import { PluginAudioGenerationService } from './pluginAudioGenerationService.js';
28
29
  import { PluginCapabilityRegistryService } from './pluginCapabilityRegistryService.js';
29
30
  import { PluginEmbeddingService } from './pluginEmbeddingService.js';
30
31
  import { PluginImageGenerationService } from './pluginImageGenerationService.js';
32
+ import { PluginSTTService } from './pluginSTTService.js';
31
33
  import { PluginTTSService } from './pluginTTSService.js';
32
34
  import { PluginVideoGenerationService } from './pluginVideoGenerationService.js';
33
35
  import { applyPluginDefinitionPolicy, buildPluginChatPayload, convertProviderResponse, getOpenAICompatibleSamplingParameters, resolvePluginChatParameters, toOpenAICompatibleMessages, } from '../utils/pluginChatAdapter.js';
34
36
  import { streamAnthropicResponse, streamOpenAICompatibleResponse, streamOpenAIResponsesResponse, } from '../utils/pluginStreamAdapter.js';
35
37
  import { applyModelEndpointTemplate, assertSafePluginEndpoint, buildPluginAuthHeaders, buildPluginModelDiscoveryHeaders, pluginRequiresApiKey, resolvePluginApiConfig, resolvePluginEndpoint, resolvePluginModelsEndpoint, validatePluginModel, } from '../utils/pluginValidation.js';
36
38
  import { createLogger } from '../utils/logger.js';
39
+ import { isChatGenerationCancelled, throwIfChatGenerationCancelled, } from '../utils/chatCancellation.js';
37
40
  import { resolveBundledPluginsDir } from '../utils/packagePaths.js';
38
- import { getDatabaseSafe } from '../db.js';
41
+ import { BACKEND_DIRECTORY, PROJECT_DIRECTORY, resolveDataDirectory, resolveLegacyPluginsDirectories, resolvePhysicalPathCandidate, resolvePluginsDirectory, } from '../utils/dataDirectory.js';
42
+ import { getPersistence } from '../persistence/index.js';
39
43
  import { createOpenAIResponsesStateScope, createPluginCredentialFingerprint, OPENAI_RESPONSES_INCOMPLETE_REASON_METADATA_KEY, } from '../utils/openAIResponsesAdapter.js';
40
44
  import { getPluginConnectionVariableNames } from '../utils/pluginConnectionVariables.js';
41
45
  import pluginUsageService from './pluginUsageService.js';
42
46
  import { getPluginDefinitionFingerprint, matchesBundledPluginTrustAnchor, } from '../utils/pluginDefinitionTrust.js';
47
+ import { encryptionService } from './encryptionService.js';
43
48
  const logger = createLogger('plugins');
49
+ const hasSymlinkPathComponentFromRoot = (root, target) => {
50
+ const resolvedRoot = path.resolve(root);
51
+ const resolvedTarget = path.resolve(target);
52
+ const relative = path.relative(resolvedRoot, resolvedTarget);
53
+ if (relative === '..' ||
54
+ relative.startsWith(`..${path.sep}`) ||
55
+ path.isAbsolute(relative)) {
56
+ return false;
57
+ }
58
+ let current = resolvedRoot;
59
+ for (const component of relative.split(path.sep)) {
60
+ if (!component)
61
+ continue;
62
+ current = path.join(current, component);
63
+ try {
64
+ if (fs.lstatSync(current).isSymbolicLink())
65
+ return true;
66
+ }
67
+ catch (error) {
68
+ if (error.code === 'ENOENT')
69
+ return false;
70
+ throw error;
71
+ }
72
+ }
73
+ return false;
74
+ };
75
+ const isRegularPluginDirectory = (directory) => {
76
+ try {
77
+ const stat = fs.lstatSync(directory);
78
+ return stat.isDirectory() && !stat.isSymbolicLink();
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ };
84
+ const isRegularPluginDefinition = (filePath) => {
85
+ try {
86
+ if (!isRegularPluginDirectory(path.dirname(filePath)))
87
+ return false;
88
+ const stat = fs.lstatSync(filePath);
89
+ return stat.isFile() && !stat.isSymbolicLink();
90
+ }
91
+ catch {
92
+ return false;
93
+ }
94
+ };
95
+ const readRegularPluginDefinition = (filePath) => {
96
+ if (!isRegularPluginDirectory(path.dirname(filePath))) {
97
+ throw new Error('Plugin definition directory is not a regular directory');
98
+ }
99
+ const namedStat = fs.lstatSync(filePath);
100
+ if (!namedStat.isFile() || namedStat.isSymbolicLink()) {
101
+ throw new Error('Plugin definition is not a regular file');
102
+ }
103
+ const descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
104
+ try {
105
+ const openedStat = fs.fstatSync(descriptor);
106
+ if (!openedStat.isFile() ||
107
+ openedStat.dev !== namedStat.dev ||
108
+ openedStat.ino !== namedStat.ino) {
109
+ throw new Error('Plugin definition changed during inspection');
110
+ }
111
+ return fs.readFileSync(descriptor, 'utf8');
112
+ }
113
+ finally {
114
+ fs.closeSync(descriptor);
115
+ }
116
+ };
44
117
  const readPositiveIntEnv = (name, fallback) => {
45
118
  const parsed = Number(process.env[name]);
46
119
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
@@ -84,6 +157,9 @@ function getPluginRoutingAuthProjection(plugin) {
84
157
  endpoint: capability.endpoint ?? null,
85
158
  models_endpoint: capability.models_endpoint ?? null,
86
159
  endpoint_variable: config.endpoint_variable ?? capability.endpoint_variable ?? null,
160
+ models_endpoint_variable: config.models_endpoint_variable ?? null,
161
+ voice_clone_endpoint: config.voice_clone_endpoint ?? null,
162
+ voice_clone_endpoint_variable: config.voice_clone_endpoint_variable ?? null,
87
163
  };
88
164
  });
89
165
  const definitions = new Map((plugin.variables || []).map(definition => [definition.name, definition]));
@@ -119,7 +195,7 @@ function getPluginRoutingAuthProjection(plugin) {
119
195
  });
120
196
  }
121
197
  export class PluginService {
122
- constructor() {
198
+ constructor(options = {}) {
123
199
  this.discoveredModelsCache = new Map();
124
200
  this.discoveredModelsUpdatedAt = new Map();
125
201
  this.discoveryAttemptedAt = new Map();
@@ -128,84 +204,229 @@ export class PluginService {
128
204
  this.discoveredCapabilityModelsUpdatedAt = new Map();
129
205
  this.capabilityDiscoveryAttemptedAt = new Map();
130
206
  this.inflightCapabilityDiscovery = new Map();
207
+ this.discoveryCacheRevisions = new Map();
208
+ this.capabilityDiscoveryCacheRevisions = new Map();
131
209
  this.bundledRoutingProjectionCache = new Map();
210
+ this.sharedDefinitionIds = new Set();
211
+ this.sharedPluginDefinitions =
212
+ getPersistence(encryptionService).dialect === 'postgres';
132
213
  this.bundledPluginsDir = resolveBundledPluginsDir(import.meta.url);
133
- this.legacyPluginsDir = path.join(process.cwd(), 'plugins');
134
- this.pluginsDir =
135
- process.env.PLUGINS_DIR ||
136
- (process.env.DATA_DIR
137
- ? path.join(process.env.DATA_DIR, 'plugins')
138
- : this.legacyPluginsDir);
139
- this.pluginReadDirs = Array.from(new Set([this.bundledPluginsDir, this.legacyPluginsDir, this.pluginsDir]));
140
- this.ensurePluginsDirectory();
141
- pluginActivationService.migrateLegacyStatus([this.pluginsDir, this.legacyPluginsDir], pluginId => this.canMigrateLegacyActivation(pluginId));
214
+ this.pluginsDir = resolvePluginsDirectory();
215
+ this.legacyPluginsDirs =
216
+ options.legacyPluginsDirectories ?? resolveLegacyPluginsDirectories();
217
+ const activePluginDirectories = new Set([this.bundledPluginsDir, this.pluginsDir, ...this.legacyPluginsDirs].map(directory => resolvePhysicalPathCandidate(directory)));
218
+ this.historicalPluginConflictDirs = options.legacyPluginsDirectories
219
+ ? []
220
+ : resolveLegacyPluginsDirectories(process.env, {
221
+ historicalWorkingDirectory: process.cwd(),
222
+ }).filter(directory => !activePluginDirectories.has(resolvePhysicalPathCandidate(directory)));
223
+ this.pluginReadDirs = this.sharedPluginDefinitions
224
+ ? [this.bundledPluginsDir]
225
+ : Array.from(new Set([
226
+ this.bundledPluginsDir,
227
+ ...this.legacyPluginsDirs,
228
+ this.pluginsDir,
229
+ ]));
230
+ if (this.sharedPluginDefinitions) {
231
+ this.assertNoLocalCustomDefinitions();
232
+ }
233
+ else {
234
+ this.ensurePluginsDirectory();
235
+ }
142
236
  this.embeddingService = new PluginEmbeddingService({
143
- getAllPlugins: userId => this.getActivePlugins(userId),
237
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
144
238
  getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
145
239
  getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
146
240
  validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
147
241
  recordUsage: usage => pluginUsageService.record(usage),
148
242
  });
149
243
  this.ttsService = new PluginTTSService({
150
- getAllPlugins: userId => this.getActivePlugins(userId),
151
- getPlugin: (id, userId) => this.getPlugin(id, userId),
244
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
245
+ getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
246
+ getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
247
+ getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
248
+ validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
249
+ recordUsage: usage => pluginUsageService.record(usage),
250
+ });
251
+ this.sttService = new PluginSTTService({
252
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
253
+ getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
152
254
  getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
153
255
  getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
154
256
  validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
155
257
  recordUsage: usage => pluginUsageService.record(usage),
156
258
  });
157
259
  this.imageGenerationService = new PluginImageGenerationService({
158
- getAllPlugins: userId => this.getActivePlugins(userId),
159
- getPlugin: (id, userId) => this.getPlugin(id, userId),
260
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
261
+ getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
160
262
  getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
161
263
  getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
162
264
  validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
163
265
  recordUsage: usage => pluginUsageService.record(usage),
164
266
  });
165
267
  this.audioGenerationService = new PluginAudioGenerationService({
166
- getAllPlugins: userId => this.getActivePlugins(userId),
167
- getPlugin: (id, userId) => this.getPlugin(id, userId),
268
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
269
+ getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
168
270
  getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
169
271
  getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
170
272
  validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
171
273
  recordUsage: usage => pluginUsageService.record(usage),
172
274
  });
173
275
  this.videoGenerationService = new PluginVideoGenerationService({
174
- getAllPlugins: userId => this.getActivePlugins(userId),
175
- getPlugin: (id, userId) => this.getPlugin(id, userId),
276
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
277
+ getPlugin: (id, userId) => this.getPluginUnchecked(id, userId),
176
278
  getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
177
279
  getPluginVariables: (plugin, userId) => this.getPluginVariables(plugin, userId),
178
280
  validateEndpointUrl: endpoint => this.validateEndpointUrl(endpoint),
179
281
  recordUsage: usage => pluginUsageService.record(usage),
180
282
  });
181
283
  this.capabilityRegistryService = new PluginCapabilityRegistryService({
182
- getAllPlugins: userId => this.getActivePlugins(userId),
284
+ getAllPlugins: userId => this.getActivePluginsUnchecked(userId),
183
285
  getApiKey: (plugin, userId) => this.getApiKey(plugin, userId),
184
286
  });
185
287
  }
288
+ repositories() {
289
+ return getPersistence(encryptionService).repositories.extensions;
290
+ }
291
+ async ensureCacheInvalidation() {
292
+ this.removeCacheInvalidationListener ?? (this.removeCacheInvalidationListener = registerPluginCacheInvalidationListener(invalidation => this.invalidateRuntimeCaches(invalidation)));
293
+ await ensurePluginCacheInvalidationSubscription();
294
+ }
295
+ bumpDiscoveryRevision(key) {
296
+ this.discoveryCacheRevisions.set(key, (this.discoveryCacheRevisions.get(key) ?? 0) + 1);
297
+ }
298
+ bumpCapabilityDiscoveryRevision(key) {
299
+ this.capabilityDiscoveryCacheRevisions.set(key, (this.capabilityDiscoveryCacheRevisions.get(key) ?? 0) + 1);
300
+ }
301
+ invalidateRuntimeCaches(invalidation) {
302
+ const completionKeys = new Set([
303
+ ...this.discoveredModelsCache.keys(),
304
+ ...this.discoveredModelsUpdatedAt.keys(),
305
+ ...this.discoveryAttemptedAt.keys(),
306
+ ...this.inflightDiscovery.keys(),
307
+ ...this.discoveryCacheRevisions.keys(),
308
+ ]);
309
+ const capabilityKeys = new Set([
310
+ ...this.discoveredCapabilityModelsCache.keys(),
311
+ ...this.discoveredCapabilityModelsUpdatedAt.keys(),
312
+ ...this.capabilityDiscoveryAttemptedAt.keys(),
313
+ ...this.inflightCapabilityDiscovery.keys(),
314
+ ...this.capabilityDiscoveryCacheRevisions.keys(),
315
+ ]);
316
+ const completionMatches = (key) => {
317
+ if (invalidation.scope === 'plugin-user') {
318
+ return (key ===
319
+ this.discoveredModelsCacheKey(invalidation.pluginId, invalidation.userId));
320
+ }
321
+ if (invalidation.scope === 'plugin') {
322
+ return key.endsWith(`:${invalidation.pluginId}`);
323
+ }
324
+ return key.startsWith(`${invalidation.userId}:`);
325
+ };
326
+ const capabilityMatches = (key) => {
327
+ if (invalidation.scope === 'plugin-user') {
328
+ return key.startsWith(`${invalidation.userId}:${invalidation.pluginId}:`);
329
+ }
330
+ if (invalidation.scope === 'plugin') {
331
+ return key.includes(`:${invalidation.pluginId}:`);
332
+ }
333
+ return key.startsWith(`${invalidation.userId}:`);
334
+ };
335
+ for (const key of completionKeys) {
336
+ if (!completionMatches(key))
337
+ continue;
338
+ this.discoveredModelsCache.delete(key);
339
+ this.discoveredModelsUpdatedAt.delete(key);
340
+ this.discoveryAttemptedAt.delete(key);
341
+ this.inflightDiscovery.delete(key);
342
+ this.bumpDiscoveryRevision(key);
343
+ }
344
+ for (const key of capabilityKeys) {
345
+ if (!capabilityMatches(key))
346
+ continue;
347
+ this.discoveredCapabilityModelsCache.delete(key);
348
+ this.discoveredCapabilityModelsUpdatedAt.delete(key);
349
+ this.capabilityDiscoveryAttemptedAt.delete(key);
350
+ this.inflightCapabilityDiscovery.delete(key);
351
+ this.bumpCapabilityDiscoveryRevision(key);
352
+ }
353
+ }
354
+ ensureLegacyActivationMigration() {
355
+ if (this.sharedPluginDefinitions)
356
+ return Promise.resolve();
357
+ this.legacyActivationMigration ?? (this.legacyActivationMigration = pluginActivationService.migrateLegacyStatus([...this.pluginReadDirs]
358
+ .reverse()
359
+ .filter(pluginsDir => path.resolve(pluginsDir) !== path.resolve(this.bundledPluginsDir)), pluginId => this.canMigrateLegacyActivation(pluginId)));
360
+ return this.legacyActivationMigration;
361
+ }
362
+ /**
363
+ * Team replicas must never pick a provider definition from node-local disk.
364
+ * Refuse startup when an old writable definition is present so an operator
365
+ * has to migrate it deliberately instead of getting replica-dependent
366
+ * routing, credentials, or activation state.
367
+ */
368
+ assertNoLocalCustomDefinitions() {
369
+ const bundledDirectory = path.resolve(this.bundledPluginsDir);
370
+ const directories = new Set([
371
+ this.pluginsDir,
372
+ ...this.legacyPluginsDirs,
373
+ ...this.historicalPluginConflictDirs,
374
+ ]);
375
+ for (const directory of directories) {
376
+ if (path.resolve(directory) === bundledDirectory)
377
+ continue;
378
+ let entries;
379
+ try {
380
+ const stat = fs.lstatSync(directory);
381
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
382
+ throw new Error(`Plugin definition path ${directory} is not a physical directory`);
383
+ }
384
+ entries = fs.readdirSync(directory, { withFileTypes: true });
385
+ }
386
+ catch (error) {
387
+ if (error.code === 'ENOENT')
388
+ continue;
389
+ throw error;
390
+ }
391
+ if (entries.some(entry => entry.name.endsWith('.json'))) {
392
+ throw new Error(`Local custom plugin definitions exist at ${directory}. PostgreSQL mode requires definitions in the shared database; run the SQLite-to-PostgreSQL migration with the plugin directory before starting any replica.`);
393
+ }
394
+ }
395
+ }
396
+ parseSharedPluginDefinition(row) {
397
+ this.sharedDefinitionIds.add(row.plugin_id);
398
+ if (row.approved_by_user_id === null || row.approved_at === null) {
399
+ return null;
400
+ }
401
+ try {
402
+ const plugin = JSON.parse(row.definition_json);
403
+ if (!this.validatePlugin(plugin) ||
404
+ plugin.id !== row.plugin_id ||
405
+ getPluginDefinitionFingerprint(plugin) !== row.definition_fingerprint) {
406
+ return null;
407
+ }
408
+ return applyPluginDefinitionPolicy(plugin);
409
+ }
410
+ catch {
411
+ return null;
412
+ }
413
+ }
186
414
  discoveredModelsCacheKey(pluginId, userId) {
187
415
  return `${userId}:${pluginId}`;
188
416
  }
189
417
  discoveredCapabilityModelsCacheKey(pluginId, capability, userId) {
190
418
  return `${userId}:${pluginId}:${capability}`;
191
419
  }
192
- getDiscoveredCapabilityModels(pluginId, capability, userId) {
420
+ async getDiscoveredCapabilityModels(pluginId, capability, userId) {
421
+ await this.ensureCacheInvalidation();
193
422
  const effectiveUserId = userId || 'default';
194
423
  const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, effectiveUserId);
195
- if (this.discoveredCapabilityModelsCache.has(cacheKey)) {
424
+ if (!this.sharedPluginDefinitions &&
425
+ this.discoveredCapabilityModelsCache.has(cacheKey)) {
196
426
  return this.discoveredCapabilityModelsCache.get(cacheKey) || undefined;
197
427
  }
198
- const db = getDatabaseSafe();
199
- if (!db) {
200
- this.discoveredCapabilityModelsCache.set(cacheKey, null);
201
- return undefined;
202
- }
203
428
  try {
204
- const row = db
205
- .prepare(`SELECT models_json, updated_at
206
- FROM plugin_discovered_capability_models
207
- WHERE user_id = ? AND plugin_id = ? AND capability = ?`)
208
- .get(effectiveUserId, pluginId, capability);
429
+ const row = await this.repositories().pluginDiscovery.getCapability(pluginId, capability, effectiveUserId);
209
430
  if (!row) {
210
431
  this.discoveredCapabilityModelsCache.set(cacheKey, null);
211
432
  return undefined;
@@ -228,38 +449,38 @@ export class PluginService {
228
449
  return undefined;
229
450
  }
230
451
  }
231
- storeDiscoveredCapabilityModels(pluginId, capability, models, userId) {
452
+ async storeDiscoveredCapabilityModels(pluginId, capability, models, userId) {
453
+ await this.ensureCacheInvalidation();
232
454
  const effectiveUserId = userId || 'default';
233
455
  const uniqueModels = Array.from(new Set(models));
234
456
  const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, effectiveUserId);
235
457
  const discoveredAt = Date.now();
458
+ await this.repositories().pluginDiscovery.upsertCapability({
459
+ user_id: effectiveUserId,
460
+ plugin_id: pluginId,
461
+ capability,
462
+ models_json: JSON.stringify(uniqueModels),
463
+ updated_at: discoveredAt,
464
+ });
236
465
  this.discoveredCapabilityModelsCache.set(cacheKey, uniqueModels);
237
466
  this.discoveredCapabilityModelsUpdatedAt.set(cacheKey, discoveredAt);
238
- const db = getDatabaseSafe();
239
- if (!db)
240
- return;
241
- db.prepare(`INSERT INTO plugin_discovered_capability_models
242
- (user_id, plugin_id, capability, models_json, updated_at)
243
- VALUES (?, ?, ?, ?, ?)
244
- ON CONFLICT(user_id, plugin_id, capability) DO UPDATE SET
245
- models_json = excluded.models_json,
246
- updated_at = excluded.updated_at`).run(effectiveUserId, pluginId, capability, JSON.stringify(uniqueModels), discoveredAt);
247
- }
248
- getDiscoveredModels(pluginId, userId) {
467
+ await publishPluginCacheInvalidation({
468
+ version: 1,
469
+ scope: 'plugin-user',
470
+ pluginId,
471
+ userId: effectiveUserId,
472
+ });
473
+ }
474
+ async getDiscoveredModels(pluginId, userId) {
475
+ await this.ensureCacheInvalidation();
249
476
  const effectiveUserId = userId || 'default';
250
477
  const cacheKey = this.discoveredModelsCacheKey(pluginId, effectiveUserId);
251
- if (this.discoveredModelsCache.has(cacheKey)) {
478
+ if (!this.sharedPluginDefinitions &&
479
+ this.discoveredModelsCache.has(cacheKey)) {
252
480
  return this.discoveredModelsCache.get(cacheKey) || undefined;
253
481
  }
254
- const db = getDatabaseSafe();
255
- if (!db) {
256
- this.discoveredModelsCache.set(cacheKey, null);
257
- return undefined;
258
- }
259
482
  try {
260
- const row = db
261
- .prepare('SELECT models_json, updated_at FROM plugin_discovered_models WHERE user_id = ? AND plugin_id = ?')
262
- .get(effectiveUserId, pluginId);
483
+ const row = await this.repositories().pluginDiscovery.get(pluginId, effectiveUserId);
263
484
  if (!row) {
264
485
  this.discoveredModelsCache.set(cacheKey, null);
265
486
  return undefined;
@@ -284,44 +505,52 @@ export class PluginService {
284
505
  return undefined;
285
506
  }
286
507
  }
287
- storeDiscoveredModels(pluginId, models, userId) {
508
+ async storeDiscoveredModels(pluginId, models, userId) {
509
+ await this.ensureCacheInvalidation();
288
510
  const effectiveUserId = userId || 'default';
289
511
  const uniqueModels = Array.from(new Set(models));
290
512
  const cacheKey = this.discoveredModelsCacheKey(pluginId, effectiveUserId);
291
513
  const discoveredAt = Date.now();
292
- this.discoveredModelsCache.set(cacheKey, uniqueModels);
293
- this.discoveredModelsUpdatedAt.set(cacheKey, discoveredAt);
294
- const db = getDatabaseSafe();
295
- if (!db)
296
- return;
297
514
  try {
298
- db.prepare(`INSERT INTO plugin_discovered_models
299
- (user_id, plugin_id, models_json, updated_at)
300
- VALUES (?, ?, ?, ?)
301
- ON CONFLICT(user_id, plugin_id) DO UPDATE SET
302
- models_json = excluded.models_json,
303
- updated_at = excluded.updated_at`).run(effectiveUserId, pluginId, JSON.stringify(uniqueModels), discoveredAt);
515
+ await this.repositories().pluginDiscovery.upsert({
516
+ user_id: effectiveUserId,
517
+ plugin_id: pluginId,
518
+ models_json: JSON.stringify(uniqueModels),
519
+ updated_at: discoveredAt,
520
+ });
521
+ this.discoveredModelsCache.set(cacheKey, uniqueModels);
522
+ this.discoveredModelsUpdatedAt.set(cacheKey, discoveredAt);
523
+ await publishPluginCacheInvalidation({
524
+ version: 1,
525
+ scope: 'plugin-user',
526
+ pluginId,
527
+ userId: effectiveUserId,
528
+ });
304
529
  }
305
530
  catch (error) {
306
531
  logger.warn('Failed to persist discovered models for plugin %s:', pluginId, error);
307
532
  }
308
533
  }
309
- clearDiscoveredModels(pluginId, userId) {
310
- this.clearDiscoveredCapabilityModels(pluginId, userId);
311
- const db = getDatabaseSafe();
534
+ async clearDiscoveredModels(pluginId, userId) {
535
+ await this.ensureCacheInvalidation();
536
+ await this.clearDiscoveredCapabilityModels(pluginId, userId);
312
537
  if (userId) {
313
538
  const cacheKey = this.discoveredModelsCacheKey(pluginId, userId);
314
539
  this.discoveredModelsCache.set(cacheKey, null);
315
540
  this.discoveredModelsUpdatedAt.delete(cacheKey);
316
541
  this.discoveryAttemptedAt.delete(cacheKey);
317
- if (!db)
318
- return;
319
542
  try {
320
- db.prepare('DELETE FROM plugin_discovered_models WHERE user_id = ? AND plugin_id = ?').run(userId, pluginId);
543
+ await this.repositories().pluginDiscovery.delete(pluginId, userId);
321
544
  }
322
545
  catch (error) {
323
546
  logger.warn('Failed to clear discovered models for plugin %s:', pluginId, error);
324
547
  }
548
+ await publishPluginCacheInvalidation({
549
+ version: 1,
550
+ scope: 'plugin-user',
551
+ pluginId,
552
+ userId,
553
+ });
325
554
  return;
326
555
  }
327
556
  for (const key of this.discoveredModelsCache.keys()) {
@@ -331,54 +560,65 @@ export class PluginService {
331
560
  this.discoveryAttemptedAt.delete(key);
332
561
  }
333
562
  }
334
- if (!db)
335
- return;
336
563
  try {
337
- db.prepare('DELETE FROM plugin_discovered_models WHERE plugin_id = ?').run(pluginId);
564
+ await this.repositories().pluginDiscovery.delete(pluginId);
338
565
  }
339
566
  catch (error) {
340
567
  logger.warn('Failed to clear discovered models for plugin %s:', pluginId, error);
341
568
  }
569
+ await publishPluginCacheInvalidation({
570
+ version: 1,
571
+ scope: 'plugin',
572
+ pluginId,
573
+ });
342
574
  }
343
- clearDiscoveredCapabilityModels(pluginId, userId) {
344
- const db = getDatabaseSafe();
575
+ async clearDiscoveredCapabilityModels(pluginId, userId) {
345
576
  if (userId) {
346
- for (const capability of ['image', 'tts', 'audio', 'video']) {
577
+ for (const capability of [
578
+ 'image',
579
+ 'stt',
580
+ 'tts',
581
+ 'audio',
582
+ 'video',
583
+ ]) {
347
584
  const key = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId);
348
585
  this.discoveredCapabilityModelsCache.delete(key);
349
586
  this.discoveredCapabilityModelsUpdatedAt.delete(key);
350
587
  this.capabilityDiscoveryAttemptedAt.delete(key);
351
588
  }
352
- if (db) {
353
- db.prepare(`DELETE FROM plugin_discovered_capability_models
354
- WHERE user_id = ? AND plugin_id = ?`).run(userId, pluginId);
355
- }
589
+ // The discovery repository removes both completion and capability rows
590
+ // atomically, which prevents stale partial catalogs after reset.
591
+ await this.repositories().pluginDiscovery.delete(pluginId, userId);
356
592
  return;
357
593
  }
358
594
  for (const key of this.discoveredCapabilityModelsCache.keys()) {
359
- if (['image', 'tts', 'audio', 'video'].some(capability => key.endsWith(`:${pluginId}:${capability}`))) {
595
+ if (['image', 'stt', 'tts', 'audio', 'video'].some(capability => key.endsWith(`:${pluginId}:${capability}`))) {
360
596
  this.discoveredCapabilityModelsCache.delete(key);
361
597
  this.discoveredCapabilityModelsUpdatedAt.delete(key);
362
598
  this.capabilityDiscoveryAttemptedAt.delete(key);
363
599
  }
364
600
  }
365
- if (db) {
366
- db.prepare('DELETE FROM plugin_discovered_capability_models WHERE plugin_id = ?').run(pluginId);
367
- }
601
+ await this.repositories().pluginDiscovery.delete(pluginId);
368
602
  }
369
- applyDiscoveredModels(plugin, userId) {
370
- if (!this.canUseStoredConnectionOverrides(userId) &&
371
- pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin))) {
603
+ async applyDiscoveredModels(plugin, userId) {
604
+ if (!(await this.canUseStoredConnectionOverrides(userId)) &&
605
+ (await pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin)))) {
372
606
  return plugin;
373
607
  }
374
- const models = this.getDiscoveredModels(plugin.id, userId);
608
+ const models = await this.getDiscoveredModels(plugin.id, userId);
375
609
  const capabilities = plugin.capabilities
376
610
  ? { ...plugin.capabilities }
377
611
  : undefined;
378
612
  if (capabilities) {
379
- for (const capability of ['image', 'tts', 'audio', 'video']) {
613
+ for (const capability of [
614
+ 'image',
615
+ 'stt',
616
+ 'tts',
617
+ 'audio',
618
+ 'video',
619
+ ]) {
380
620
  const definition = capabilities[capability];
381
- const discovered = this.getDiscoveredCapabilityModels(plugin.id, capability, userId);
621
+ const discovered = await this.getDiscoveredCapabilityModels(plugin.id, capability, userId);
382
622
  if (definition && discovered) {
383
623
  capabilities[capability] = {
384
624
  ...definition,
@@ -394,8 +634,76 @@ export class PluginService {
394
634
  };
395
635
  }
396
636
  ensurePluginsDirectory() {
397
- if (!fs.existsSync(this.pluginsDir)) {
637
+ const dataDirectory = resolveDataDirectory();
638
+ const configuredRelativeToData = path.relative(dataDirectory, this.pluginsDir);
639
+ const configuredPathRoot = configuredRelativeToData === '' ||
640
+ (configuredRelativeToData !== '..' &&
641
+ !configuredRelativeToData.startsWith(`..${path.sep}`) &&
642
+ !path.isAbsolute(configuredRelativeToData))
643
+ ? dataDirectory
644
+ : process.env.PLUGINS_DIR?.trim() &&
645
+ !path.isAbsolute(process.env.PLUGINS_DIR.trim())
646
+ ? PROJECT_DIRECTORY
647
+ : path.dirname(this.pluginsDir);
648
+ try {
649
+ if (hasSymlinkPathComponentFromRoot(configuredPathRoot, this.pluginsDir)) {
650
+ throw new Error('PLUGINS_DIR cannot contain a symbolic-link path component');
651
+ }
652
+ const pluginsStat = fs.lstatSync(this.pluginsDir);
653
+ if (!pluginsStat.isDirectory() || pluginsStat.isSymbolicLink()) {
654
+ throw new Error('PLUGINS_DIR must be a physical directory, not a symlink or special file');
655
+ }
656
+ }
657
+ catch (error) {
658
+ if (error.code !== 'ENOENT')
659
+ throw error;
398
660
  fs.mkdirSync(this.pluginsDir, { recursive: true });
661
+ const createdStat = fs.lstatSync(this.pluginsDir);
662
+ if (!createdStat.isDirectory() || createdStat.isSymbolicLink()) {
663
+ throw new Error('PLUGINS_DIR could not be created safely');
664
+ }
665
+ }
666
+ for (const legacyDirectory of this.legacyPluginsDirs) {
667
+ const relativeToBackend = path.relative(BACKEND_DIRECTORY, legacyDirectory);
668
+ const legacyRoot = relativeToBackend === '' ||
669
+ (relativeToBackend !== '..' &&
670
+ !relativeToBackend.startsWith(`..${path.sep}`) &&
671
+ !path.isAbsolute(relativeToBackend))
672
+ ? BACKEND_DIRECTORY
673
+ : path.dirname(legacyDirectory);
674
+ if (hasSymlinkPathComponentFromRoot(legacyRoot, legacyDirectory)) {
675
+ throw new Error('A legacy plugin path contains a symbolic-link component; refusing to follow it');
676
+ }
677
+ const legacyStat = (() => {
678
+ try {
679
+ return fs.lstatSync(legacyDirectory);
680
+ }
681
+ catch (error) {
682
+ if (error.code === 'ENOENT')
683
+ return null;
684
+ throw error;
685
+ }
686
+ })();
687
+ if (legacyStat &&
688
+ (!legacyStat.isDirectory() || legacyStat.isSymbolicLink())) {
689
+ throw new Error('A legacy plugin path is not a physical directory; refusing to follow it');
690
+ }
691
+ }
692
+ for (const historicalDirectory of this.historicalPluginConflictDirs) {
693
+ let historicalEntries;
694
+ try {
695
+ historicalEntries = fs.readdirSync(historicalDirectory, {
696
+ withFileTypes: true,
697
+ });
698
+ }
699
+ catch (error) {
700
+ if (error.code === 'ENOENT')
701
+ continue;
702
+ throw new Error(`Historical plugin directory ${historicalDirectory} cannot be inspected safely`);
703
+ }
704
+ if (historicalEntries.some(entry => entry.name.endsWith('.json'))) {
705
+ throw new Error(`Legacy plugin definitions exist at ${historicalDirectory}, where the relative PLUGINS_DIR previously resolved from the caller working directory. Move them into ${this.pluginsDir} or configure an absolute PLUGINS_DIR; Libre will not silently choose between them.`);
706
+ }
399
707
  }
400
708
  }
401
709
  bundledPluginPath(id) {
@@ -405,19 +713,12 @@ export class PluginService {
405
713
  return (path.resolve(filePath) === this.bundledPluginPath(plugin.id) &&
406
714
  matchesBundledPluginTrustAnchor(plugin));
407
715
  }
408
- isPluginDefinitionApproved(plugin, filePath) {
716
+ async isPluginDefinitionApproved(plugin, filePath) {
409
717
  if (this.isAnchoredBundledDefinition(plugin, filePath)) {
410
718
  return true;
411
719
  }
412
- const db = getDatabaseSafe();
413
- if (!db)
414
- return false;
415
720
  try {
416
- const row = db
417
- .prepare(`SELECT definition_fingerprint, source_path
418
- FROM plugin_definition_approvals
419
- WHERE plugin_id = ?`)
420
- .get(plugin.id);
721
+ const row = await this.repositories().pluginApprovals.find(plugin.id);
421
722
  return (row?.definition_fingerprint ===
422
723
  getPluginDefinitionFingerprint(plugin) &&
423
724
  row.source_path === path.resolve(filePath));
@@ -427,46 +728,30 @@ export class PluginService {
427
728
  return false;
428
729
  }
429
730
  }
430
- approvePluginDefinition(plugin, filePath, userId) {
431
- if (!this.canUseStoredConnectionOverrides(userId)) {
731
+ async approvePluginDefinition(plugin, filePath, userId) {
732
+ if (!(await this.canUseStoredConnectionOverrides(userId))) {
432
733
  throw new Error('Administrator approval is required');
433
734
  }
434
- const db = getDatabaseSafe();
435
- if (!db) {
436
- throw new Error('Database not available for plugin approval');
437
- }
438
- db.prepare(`INSERT INTO plugin_definition_approvals
439
- (plugin_id, definition_fingerprint, source_path,
440
- approved_by_user_id, approved_at)
441
- VALUES (?, ?, ?, ?, ?)
442
- ON CONFLICT(plugin_id) DO UPDATE SET
443
- definition_fingerprint = excluded.definition_fingerprint,
444
- source_path = excluded.source_path,
445
- approved_by_user_id = excluded.approved_by_user_id,
446
- approved_at = excluded.approved_at`).run(plugin.id, getPluginDefinitionFingerprint(plugin), path.resolve(filePath), userId, Date.now());
447
- }
448
- removePluginDefinitionApproval(pluginId) {
449
- const db = getDatabaseSafe();
450
- if (!db)
451
- return;
452
- db.prepare('DELETE FROM plugin_definition_approvals WHERE plugin_id = ?').run(pluginId);
735
+ await this.repositories().pluginApprovals.upsert({
736
+ plugin_id: plugin.id,
737
+ definition_fingerprint: getPluginDefinitionFingerprint(plugin),
738
+ source_path: path.resolve(filePath),
739
+ approved_by_user_id: userId,
740
+ approved_at: Date.now(),
741
+ });
453
742
  }
454
- revokePluginDefinitionConsent(pluginId) {
455
- const db = getDatabaseSafe();
456
- if (!db) {
457
- throw new Error('Database not available for plugin approval');
458
- }
459
- db.transaction(() => {
460
- db.prepare('DELETE FROM plugin_activations WHERE plugin_id = ?').run(pluginId);
461
- db.prepare('DELETE FROM plugin_definition_approvals WHERE plugin_id = ?').run(pluginId);
462
- })();
743
+ async removePluginDefinitionApproval(pluginId) {
744
+ await this.repositories().pluginApprovals.delete(pluginId);
745
+ }
746
+ async revokePluginDefinitionConsent(pluginId) {
747
+ await this.repositories().pluginApprovals.revokeConsent(pluginId);
463
748
  }
464
749
  canMigrateLegacyActivation(pluginId) {
465
750
  const effectivePath = this.resolveEffectivePluginFilePath(pluginId);
466
751
  if (!effectivePath)
467
752
  return false;
468
753
  try {
469
- const parsedPlugin = JSON.parse(fs.readFileSync(effectivePath, 'utf8'));
754
+ const parsedPlugin = JSON.parse(readRegularPluginDefinition(effectivePath));
470
755
  return (this.validatePlugin(parsedPlugin) &&
471
756
  parsedPlugin.id === pluginId &&
472
757
  this.isAnchoredBundledDefinition(parsedPlugin, effectivePath));
@@ -482,9 +767,31 @@ export class PluginService {
482
767
  for (const pluginsDir of [...this.pluginReadDirs].reverse()) {
483
768
  const resolvedDirectory = path.resolve(pluginsDir);
484
769
  const candidate = path.resolve(pluginsDir, `${sanitizedId}.json`);
485
- if (candidate.startsWith(resolvedDirectory) && fs.existsSync(candidate)) {
770
+ if (!candidate.startsWith(resolvedDirectory))
771
+ continue;
772
+ const directoryStat = (() => {
773
+ try {
774
+ return fs.lstatSync(pluginsDir);
775
+ }
776
+ catch {
777
+ return null;
778
+ }
779
+ })();
780
+ if (directoryStat &&
781
+ (!directoryStat.isDirectory() || directoryStat.isSymbolicLink())) {
782
+ // Preserve precedence while forcing the no-follow reader to reject the
783
+ // unsafe path instead of falling back to a lower-priority definition.
486
784
  return candidate;
487
785
  }
786
+ try {
787
+ fs.lstatSync(candidate);
788
+ // Return invalid named entries too. The strict reader will reject them,
789
+ // preventing a symlink/special-file shadow from revealing a bundled ID.
790
+ return candidate;
791
+ }
792
+ catch {
793
+ // Continue to lower-priority sources only when the named entry is absent.
794
+ }
488
795
  }
489
796
  return null;
490
797
  }
@@ -503,7 +810,7 @@ export class PluginService {
503
810
  return null;
504
811
  }
505
812
  try {
506
- const parsedPlugin = JSON.parse(fs.readFileSync(bundledPath, 'utf8'));
813
+ const parsedPlugin = JSON.parse(readRegularPluginDefinition(bundledPath));
507
814
  if (!this.validatePlugin(parsedPlugin) ||
508
815
  parsedPlugin.id !== sanitizedId ||
509
816
  !matchesBundledPluginTrustAnchor(parsedPlugin)) {
@@ -521,6 +828,10 @@ export class PluginService {
521
828
  }
522
829
  }
523
830
  usesTrustedBundledRouting(plugin) {
831
+ if (this.sharedPluginDefinitions &&
832
+ this.sharedDefinitionIds.has(plugin.id)) {
833
+ return false;
834
+ }
524
835
  const effectivePath = this.resolveEffectivePluginFilePath(plugin.id);
525
836
  const bundledPath = this.bundledPluginPath(plugin.id);
526
837
  if (!effectivePath || effectivePath !== bundledPath)
@@ -529,18 +840,12 @@ export class PluginService {
529
840
  return (bundledProjection !== null &&
530
841
  getPluginRoutingAuthProjection(plugin) === bundledProjection);
531
842
  }
532
- isPluginActive(pluginId, userId) {
533
- return pluginActivationService.getActivePluginIds(userId).has(pluginId);
843
+ async isPluginActive(pluginId, userId) {
844
+ return (await pluginActivationService.getActivePluginIds(userId)).has(pluginId);
534
845
  }
535
- canUseStoredConnectionOverrides(userId) {
536
- const db = getDatabaseSafe();
537
- if (!db)
538
- return false;
846
+ async canUseStoredConnectionOverrides(userId) {
539
847
  try {
540
- const row = db
541
- .prepare('SELECT role FROM users WHERE id = ?')
542
- .get(userId || 'default');
543
- return row?.role === 'admin';
848
+ return ((await userModel.getUserById(userId || 'default'))?.role === 'admin');
544
849
  }
545
850
  catch (error) {
546
851
  logger.warn('Failed to resolve plugin routing permission:', error);
@@ -553,7 +858,7 @@ export class PluginService {
553
858
  * @param userId Optional user ID for per-user credentials
554
859
  * @returns The API key or null if not found
555
860
  */
556
- getApiKey(plugin, userId) {
861
+ async getApiKey(plugin, userId) {
557
862
  if (plugin.id === CODEX_OAUTH_PLUGIN_ID) {
558
863
  // Resolved from the server's Codex CLI sign-in, never user credentials.
559
864
  // A writable same-ID definition must never receive the server user's
@@ -563,13 +868,13 @@ export class PluginService {
563
868
  ? codexOAuthService.getCachedAccessToken()
564
869
  : null;
565
870
  }
566
- const hasHonoredConnectionOverride = this.canUseStoredConnectionOverrides(userId) &&
567
- pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin));
871
+ const hasHonoredConnectionOverride = (await this.canUseStoredConnectionOverrides(userId)) &&
872
+ (await pluginVariablesService.hasStoredConnectionOverride(plugin.id, userId, plugin.variables, getPluginConnectionVariableNames(plugin)));
568
873
  const usesTrustedBundledRouting = this.usesTrustedBundledRouting(plugin);
569
874
  const allowTrustedFallback = usesTrustedBundledRouting && !hasHonoredConnectionOverride;
570
875
  return pluginCredentialsService.getApiKey(plugin.id, plugin.auth.key_env, userId, {
571
876
  allowEnvironmentFallback: allowTrustedFallback,
572
- expectedRoutingAuthFingerprint: this.getCredentialRoutingAuthFingerprint(plugin, userId),
877
+ expectedRoutingAuthFingerprint: await this.getCredentialRoutingAuthFingerprint(plugin, userId),
573
878
  allowLegacyUnboundCredential: allowTrustedFallback,
574
879
  });
575
880
  }
@@ -577,8 +882,8 @@ export class PluginService {
577
882
  * Bind a user credential to the exact routing/authentication contract in
578
883
  * effect when they save it. Generation controls are intentionally excluded.
579
884
  */
580
- getCredentialRoutingAuthFingerprint(plugin, userId) {
581
- const variables = this.getPluginVariables(plugin, userId);
885
+ async getCredentialRoutingAuthFingerprint(plugin, userId) {
886
+ const variables = await this.getPluginVariables(plugin, userId);
582
887
  const effectiveConnectionValues = Array.from(getPluginConnectionVariableNames(plugin), name => {
583
888
  const definition = plugin.variables?.find(candidate => candidate.name === name);
584
889
  if (!definition)
@@ -588,11 +893,18 @@ export class PluginService {
588
893
  value: variables[name] ?? definition.default ?? '',
589
894
  };
590
895
  });
591
- const effectivePath = this.resolveEffectivePluginFilePath(plugin.id);
896
+ const sharedDefinition = this.sharedPluginDefinitions
897
+ ? await this.repositories().pluginDefinitions.find(plugin.id)
898
+ : null;
899
+ if (sharedDefinition)
900
+ this.sharedDefinitionIds.add(plugin.id);
901
+ const effectivePath = sharedDefinition
902
+ ? null
903
+ : this.resolveEffectivePluginFilePath(plugin.id);
592
904
  let effectiveDefinitionFingerprint = getPluginDefinitionFingerprint(plugin);
593
905
  if (effectivePath) {
594
906
  try {
595
- const effectiveDefinition = JSON.parse(fs.readFileSync(effectivePath, 'utf8'));
907
+ const effectiveDefinition = JSON.parse(readRegularPluginDefinition(effectivePath));
596
908
  if (this.validatePlugin(effectiveDefinition) &&
597
909
  effectiveDefinition.id === plugin.id) {
598
910
  effectiveDefinitionFingerprint =
@@ -608,7 +920,11 @@ export class PluginService {
608
920
  plugin_id: plugin.id,
609
921
  plugin_type: plugin.type,
610
922
  trusted_bundled_source: this.usesTrustedBundledRouting(plugin),
611
- effective_source_path: effectivePath ? path.resolve(effectivePath) : null,
923
+ effective_source_path: sharedDefinition
924
+ ? 'database:plugin_definitions'
925
+ : effectivePath
926
+ ? path.resolve(effectivePath)
927
+ : null,
612
928
  effective_definition_fingerprint: effectiveDefinitionFingerprint,
613
929
  routing_auth_projection: getPluginRoutingAuthProjection(plugin),
614
930
  effective_connection_values: effectiveConnectionValues,
@@ -618,12 +934,12 @@ export class PluginService {
618
934
  /**
619
935
  * Get resolved variable values for a plugin (decrypted, typed).
620
936
  */
621
- getPluginVariables(plugin, userId) {
937
+ async getPluginVariables(plugin, userId) {
622
938
  if (!plugin.variables || plugin.variables.length === 0) {
623
939
  return {};
624
940
  }
625
- const variables = pluginVariablesService.getResolvedVariables(plugin.id, plugin.variables, userId);
626
- if (this.canUseStoredConnectionOverrides(userId))
941
+ const variables = await pluginVariablesService.getResolvedVariables(plugin.id, plugin.variables, userId);
942
+ if (await this.canUseStoredConnectionOverrides(userId))
627
943
  return variables;
628
944
  return Object.fromEntries(Object.entries(variables).map(([name, value]) => {
629
945
  if (!getPluginConnectionVariableNames(plugin).has(name)) {
@@ -646,8 +962,8 @@ export class PluginService {
646
962
  * boundary ordered prevents a rejected override from ever selecting an
647
963
  * environment credential.
648
964
  */
649
- resolveOperationEndpoint(plugin, userId) {
650
- return resolvePluginApiConfig(plugin, this.getPluginVariables(plugin, userId)).endpoint;
965
+ async resolveOperationEndpoint(plugin, userId) {
966
+ return resolvePluginApiConfig(plugin, await this.getPluginVariables(plugin, userId)).endpoint;
651
967
  }
652
968
  /**
653
969
  * Attempt to auto-discover available models from a plugin's full API endpoint.
@@ -665,12 +981,16 @@ export class PluginService {
665
981
  * is fresh.
666
982
  */
667
983
  async discoverModelsResult(pluginId, userId) {
984
+ await this.ensureCacheInvalidation();
668
985
  const cacheKey = this.discoveredModelsCacheKey(pluginId, userId || 'default');
669
986
  const inflight = this.inflightDiscovery.get(cacheKey);
670
987
  if (inflight)
671
988
  return inflight;
672
- const attempt = this.runModelDiscovery(pluginId, userId).finally(() => {
673
- this.inflightDiscovery.delete(cacheKey);
989
+ const revision = this.discoveryCacheRevisions.get(cacheKey) ?? 0;
990
+ const attempt = this.runModelDiscovery(pluginId, userId, revision).finally(() => {
991
+ if (this.inflightDiscovery.get(cacheKey) === attempt) {
992
+ this.inflightDiscovery.delete(cacheKey);
993
+ }
674
994
  });
675
995
  this.inflightDiscovery.set(cacheKey, attempt);
676
996
  return attempt;
@@ -680,13 +1000,13 @@ export class PluginService {
680
1000
  * immediately; stored ones age out after the TTL. Both cases are gated by a
681
1001
  * per-plugin backoff so a failing provider is not probed on every request.
682
1002
  */
683
- isModelDiscoveryDue(pluginId, userId) {
1003
+ async isModelDiscoveryDue(pluginId, userId) {
684
1004
  const cacheKey = this.discoveredModelsCacheKey(pluginId, userId || 'default');
685
1005
  const attemptedAt = this.discoveryAttemptedAt.get(cacheKey);
686
1006
  if (attemptedAt && Date.now() - attemptedAt < modelDiscoveryRetryMs()) {
687
1007
  return false;
688
1008
  }
689
- const models = this.getDiscoveredModels(pluginId, userId);
1009
+ const models = await this.getDiscoveredModels(pluginId, userId);
690
1010
  const updatedAt = this.discoveredModelsUpdatedAt.get(cacheKey);
691
1011
  if (!models || !updatedAt)
692
1012
  return true;
@@ -699,8 +1019,13 @@ export class PluginService {
699
1019
  * the next request.
700
1020
  */
701
1021
  async refreshStaleModels(userId) {
702
- const due = this.getActivePlugins(userId).filter(plugin => (plugin.type === 'completion' || plugin.type === 'chat') &&
703
- this.isModelDiscoveryDue(plugin.id, userId));
1022
+ const due = [];
1023
+ for (const plugin of await this.getActivePlugins(userId)) {
1024
+ if ((plugin.type === 'completion' || plugin.type === 'chat') &&
1025
+ (await this.isModelDiscoveryDue(plugin.id, userId))) {
1026
+ due.push(plugin);
1027
+ }
1028
+ }
704
1029
  if (due.length === 0)
705
1030
  return;
706
1031
  const refreshes = Promise.all(due.map(plugin => this.discoverModels(plugin.id, userId).catch(() => [])));
@@ -710,30 +1035,39 @@ export class PluginService {
710
1035
  ]);
711
1036
  }
712
1037
  async discoverCapabilityModels(pluginId, capability, userId) {
1038
+ await this.ensureCacheInvalidation();
713
1039
  const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
714
1040
  const inflight = this.inflightCapabilityDiscovery.get(cacheKey);
715
1041
  if (inflight)
716
1042
  return inflight;
717
- const attempt = this.runCapabilityModelDiscovery(pluginId, capability, userId).finally(() => this.inflightCapabilityDiscovery.delete(cacheKey));
1043
+ const revision = this.capabilityDiscoveryCacheRevisions.get(cacheKey) ?? 0;
1044
+ const attempt = this.runCapabilityModelDiscovery(pluginId, capability, userId, revision).finally(() => {
1045
+ if (this.inflightCapabilityDiscovery.get(cacheKey) === attempt) {
1046
+ this.inflightCapabilityDiscovery.delete(cacheKey);
1047
+ }
1048
+ });
718
1049
  this.inflightCapabilityDiscovery.set(cacheKey, attempt);
719
1050
  return attempt;
720
1051
  }
721
- isCapabilityModelDiscoveryDue(pluginId, capability, userId) {
1052
+ async isCapabilityModelDiscoveryDue(pluginId, capability, userId) {
722
1053
  const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
723
1054
  const attemptedAt = this.capabilityDiscoveryAttemptedAt.get(cacheKey);
724
1055
  if (attemptedAt && Date.now() - attemptedAt < modelDiscoveryRetryMs()) {
725
1056
  return false;
726
1057
  }
727
- const models = this.getDiscoveredCapabilityModels(pluginId, capability, userId);
1058
+ const models = await this.getDiscoveredCapabilityModels(pluginId, capability, userId);
728
1059
  const updatedAt = this.discoveredCapabilityModelsUpdatedAt.get(cacheKey);
729
1060
  return (!models || !updatedAt || Date.now() - updatedAt >= modelDiscoveryTtlMs());
730
1061
  }
731
1062
  async refreshStaleCapabilityModels(capability, userId) {
732
- const due = this.getActivePlugins(userId).filter(plugin => {
1063
+ const due = [];
1064
+ for (const plugin of await this.getActivePlugins(userId)) {
733
1065
  const definition = plugin.capabilities?.[capability];
734
- return (Boolean(definition?.models_endpoint) &&
735
- this.isCapabilityModelDiscoveryDue(plugin.id, capability, userId));
736
- });
1066
+ if (Boolean(definition?.models_endpoint) &&
1067
+ (await this.isCapabilityModelDiscoveryDue(plugin.id, capability, userId))) {
1068
+ due.push(plugin);
1069
+ }
1070
+ }
737
1071
  if (due.length === 0)
738
1072
  return;
739
1073
  const refreshes = Promise.all(due.map(plugin => this.discoverCapabilityModels(plugin.id, capability, userId).catch(() => undefined)));
@@ -742,8 +1076,8 @@ export class PluginService {
742
1076
  new Promise(resolve => setTimeout(resolve, modelDiscoveryRefreshDeadlineMs()).unref?.()),
743
1077
  ]);
744
1078
  }
745
- async runCapabilityModelDiscovery(pluginId, capability, userId) {
746
- const plugin = this.getPlugin(pluginId, userId);
1079
+ async runCapabilityModelDiscovery(pluginId, capability, userId, expectedRevision) {
1080
+ const plugin = await this.getPlugin(pluginId, userId);
747
1081
  const definition = plugin?.capabilities?.[capability];
748
1082
  if (!plugin || !definition) {
749
1083
  return {
@@ -757,9 +1091,20 @@ export class PluginService {
757
1091
  }
758
1092
  const cacheKey = this.discoveredCapabilityModelsCacheKey(pluginId, capability, userId || 'default');
759
1093
  this.capabilityDiscoveryAttemptedAt.set(cacheKey, Date.now());
760
- const modelsEndpoint = definition.models_endpoint;
1094
+ const config = definition.config && typeof definition.config === 'object'
1095
+ ? definition.config
1096
+ : {};
1097
+ const modelsEndpointVariable = config.models_endpoint_variable;
1098
+ const pluginVariables = await this.getPluginVariables(plugin, userId);
1099
+ const modelsEndpointOverride = typeof modelsEndpointVariable === 'string'
1100
+ ? pluginVariables[modelsEndpointVariable]
1101
+ : undefined;
1102
+ const modelsEndpoint = typeof modelsEndpointOverride === 'string' &&
1103
+ modelsEndpointOverride.trim().length > 0
1104
+ ? this.validateEndpointUrl(modelsEndpointOverride.trim())
1105
+ : definition.models_endpoint;
761
1106
  assertSafePluginEndpoint(modelsEndpoint, `${capability} model discovery endpoint`);
762
- const apiKey = this.getApiKey(plugin, userId);
1107
+ const apiKey = await this.getApiKey(plugin, userId);
763
1108
  if (pluginRequiresApiKey(plugin) && !apiKey) {
764
1109
  return {
765
1110
  models: definition.model_map,
@@ -787,7 +1132,15 @@ export class PluginService {
787
1132
  };
788
1133
  }
789
1134
  const previous = definition.model_map;
790
- this.storeDiscoveredCapabilityModels(pluginId, capability, models, userId);
1135
+ if ((this.capabilityDiscoveryCacheRevisions.get(cacheKey) ?? 0) !==
1136
+ expectedRevision) {
1137
+ return {
1138
+ models: previous,
1139
+ outcome: 'unavailable',
1140
+ reason: 'Provider configuration changed during discovery',
1141
+ };
1142
+ }
1143
+ await this.storeDiscoveredCapabilityModels(pluginId, capability, models, userId);
791
1144
  return {
792
1145
  models,
793
1146
  outcome: JSON.stringify(previous) === JSON.stringify(models)
@@ -816,19 +1169,19 @@ export class PluginService {
816
1169
  }
817
1170
  return 'No API key is configured for this provider.';
818
1171
  }
819
- async runModelDiscovery(pluginId, userId) {
820
- const plugin = this.getPlugin(pluginId, userId);
1172
+ async runModelDiscovery(pluginId, userId, expectedRevision) {
1173
+ const plugin = await this.getPlugin(pluginId, userId);
821
1174
  if (!plugin) {
822
1175
  return { models: [], outcome: 'unavailable', reason: 'Plugin not found' };
823
1176
  }
824
1177
  this.discoveryAttemptedAt.set(this.discoveredModelsCacheKey(pluginId, userId || 'default'), Date.now());
825
- const pluginVars = this.getPluginVariables(plugin, userId);
1178
+ const pluginVars = await this.getPluginVariables(plugin, userId);
826
1179
  const { endpoint: effectiveEndpoint } = resolvePluginApiConfig(plugin, pluginVars);
827
1180
  const modelsEndpoint = resolvePluginModelsEndpoint(effectiveEndpoint, typeof pluginVars.models_endpoint === 'string'
828
1181
  ? pluginVars.models_endpoint
829
1182
  : undefined);
830
1183
  assertSafePluginEndpoint(modelsEndpoint, 'model discovery endpoint');
831
- const apiKey = this.getApiKey(plugin, userId);
1184
+ const apiKey = await this.getApiKey(plugin, userId);
832
1185
  if (pluginRequiresApiKey(plugin) && !apiKey) {
833
1186
  logger.debug('[Plugin] Model discovery for %s has no usable API key; keeping the existing catalog', pluginId);
834
1187
  return {
@@ -851,8 +1204,17 @@ export class PluginService {
851
1204
  if (models.length > 0) {
852
1205
  logger.debug('[Plugin] Auto-discovered %d models for %s:', models.length, pluginId, models);
853
1206
  const previousModels = plugin.model_map;
854
- this.storeDiscoveredModels(pluginId, models, userId);
855
- const stored = this.getDiscoveredModels(pluginId, userId) || models;
1207
+ const cacheKey = this.discoveredModelsCacheKey(pluginId, userId || 'default');
1208
+ if ((this.discoveryCacheRevisions.get(cacheKey) ?? 0) !==
1209
+ expectedRevision) {
1210
+ return {
1211
+ models: previousModels,
1212
+ outcome: 'unavailable',
1213
+ reason: 'Provider configuration changed during discovery',
1214
+ };
1215
+ }
1216
+ await this.storeDiscoveredModels(pluginId, models, userId);
1217
+ const stored = (await this.getDiscoveredModels(pluginId, userId)) || models;
856
1218
  return {
857
1219
  models: stored,
858
1220
  outcome: JSON.stringify(stored) === JSON.stringify(previousModels)
@@ -874,26 +1236,46 @@ export class PluginService {
874
1236
  }
875
1237
  }
876
1238
  // List all installed plugins
877
- getAllPlugins(userId) {
1239
+ async getAllPluginsUnchecked(userId) {
1240
+ await this.ensureLegacyActivationMigration();
878
1241
  const plugins = new Map();
879
- const activePluginIds = pluginActivationService.getActivePluginIds(userId);
1242
+ const activePluginIds = await pluginActivationService.getActivePluginIds(userId);
880
1243
  for (const pluginsDir of this.pluginReadDirs) {
881
- if (!fs.existsSync(pluginsDir)) {
1244
+ const directoryStat = (() => {
1245
+ try {
1246
+ return fs.lstatSync(pluginsDir);
1247
+ }
1248
+ catch {
1249
+ return null;
1250
+ }
1251
+ })();
1252
+ if (!directoryStat) {
1253
+ continue;
1254
+ }
1255
+ if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
1256
+ plugins.clear();
1257
+ logger.error('Ignoring unsafe plugin directory %s and every lower-priority definition', pluginsDir);
882
1258
  continue;
883
1259
  }
884
1260
  try {
885
- const files = fs.readdirSync(pluginsDir);
886
- for (const file of files) {
1261
+ const entries = fs.readdirSync(pluginsDir, { withFileTypes: true });
1262
+ for (const entry of entries) {
1263
+ const file = entry.name;
887
1264
  if (file.endsWith('.json') && !file.startsWith('.')) {
888
1265
  const filenameId = path.basename(file, '.json');
889
1266
  try {
890
1267
  const filePath = path.join(pluginsDir, file);
891
- const content = fs.readFileSync(filePath, 'utf8');
1268
+ if (!entry.isFile() || entry.isSymbolicLink()) {
1269
+ plugins.delete(filenameId);
1270
+ logger.error('Ignoring non-regular plugin definition %s', filePath);
1271
+ continue;
1272
+ }
1273
+ const content = readRegularPluginDefinition(filePath);
892
1274
  const parsedPlugin = JSON.parse(content);
893
1275
  // Validate plugin structure
894
1276
  if (this.validatePlugin(parsedPlugin) &&
895
1277
  parsedPlugin.id === filenameId) {
896
- if (!this.isPluginDefinitionApproved(parsedPlugin, filePath)) {
1278
+ if (!(await this.isPluginDefinitionApproved(parsedPlugin, filePath))) {
897
1279
  // A later writable definition shadows an earlier bundled
898
1280
  // definition even while quarantined.
899
1281
  plugins.delete(parsedPlugin.id);
@@ -901,7 +1283,7 @@ export class PluginService {
901
1283
  }
902
1284
  const plugin = applyPluginDefinitionPolicy(parsedPlugin);
903
1285
  plugin.active = activePluginIds.has(plugin.id);
904
- plugins.set(plugin.id, this.applyDiscoveredModels(plugin, userId));
1286
+ plugins.set(plugin.id, await this.applyDiscoveredModels(plugin, userId));
905
1287
  }
906
1288
  else if (parsedPlugin.id !== filenameId) {
907
1289
  plugins.delete(filenameId);
@@ -924,41 +1306,84 @@ export class PluginService {
924
1306
  logger.error(`Failed to read plugins directory ${pluginsDir}:`, error);
925
1307
  }
926
1308
  }
927
- return Array.from(plugins.values()).filter(plugin => this.isPluginVisibleToUser(plugin, userId));
1309
+ if (this.sharedPluginDefinitions) {
1310
+ const definitions = await this.repositories().pluginDefinitions.list();
1311
+ const currentDefinitionIds = new Set(definitions.map(definition => definition.plugin_id));
1312
+ for (const pluginId of this.sharedDefinitionIds) {
1313
+ if (!currentDefinitionIds.has(pluginId)) {
1314
+ this.sharedDefinitionIds.delete(pluginId);
1315
+ }
1316
+ }
1317
+ for (const definition of definitions) {
1318
+ // The shared row has precedence over bundled release assets even when
1319
+ // corrupt or unapproved, preserving quarantine rather than silently
1320
+ // changing the provider route on another replica.
1321
+ plugins.delete(definition.plugin_id);
1322
+ const plugin = this.parseSharedPluginDefinition(definition);
1323
+ if (!plugin) {
1324
+ logger.error('Ignoring invalid or unapproved shared plugin definition %s', definition.plugin_id);
1325
+ continue;
1326
+ }
1327
+ plugin.active = activePluginIds.has(plugin.id);
1328
+ plugins.set(plugin.id, await this.applyDiscoveredModels(plugin, userId));
1329
+ }
1330
+ }
1331
+ return Array.from(plugins.values());
1332
+ }
1333
+ async getAllPlugins(userId) {
1334
+ const plugins = await this.getAllPluginsUnchecked(userId);
1335
+ const visible = [];
1336
+ for (const plugin of plugins) {
1337
+ if (await this.isPluginVisibleToUser(plugin, userId)) {
1338
+ visible.push(plugin);
1339
+ }
1340
+ }
1341
+ return visible;
928
1342
  }
929
1343
  /**
930
1344
  * The codex-oauth plugin rides the server user's ChatGPT sign-in, so it is
931
1345
  * administrator-only and hidden entirely when no sign-in exists.
932
1346
  */
933
- isPluginVisibleToUser(plugin, userId) {
1347
+ async isPluginVisibleToUser(plugin, userId) {
934
1348
  if (plugin.id !== CODEX_OAUTH_PLUGIN_ID)
935
1349
  return true;
936
1350
  if (!codexOAuthService.isAvailable())
937
1351
  return false;
938
1352
  if (!userId)
939
1353
  return false;
940
- return userModel.getUserById(userId)?.role === 'admin';
1354
+ return (await userModel.getUserById(userId))?.role === 'admin';
941
1355
  }
942
1356
  // Get a specific plugin by ID
943
- getPlugin(id, userId) {
1357
+ async loadPlugin(id, userId) {
1358
+ await this.ensureLegacyActivationMigration();
944
1359
  // Sanitize the ID to prevent path traversal
945
1360
  const sanitizedId = sanitize(id);
946
1361
  if (!sanitizedId || sanitizedId !== id) {
947
1362
  logger.error('Invalid plugin ID provided:', id);
948
1363
  return null;
949
1364
  }
1365
+ if (this.sharedPluginDefinitions) {
1366
+ const definition = await this.repositories().pluginDefinitions.find(sanitizedId);
1367
+ if (definition) {
1368
+ const plugin = this.parseSharedPluginDefinition(definition);
1369
+ if (!plugin)
1370
+ return null;
1371
+ plugin.active = await this.isPluginActive(plugin.id, userId);
1372
+ return this.applyDiscoveredModels(plugin, userId);
1373
+ }
1374
+ this.sharedDefinitionIds.delete(sanitizedId);
1375
+ }
950
1376
  const filePath = this.resolveEffectivePluginFilePath(sanitizedId);
951
1377
  if (!filePath)
952
1378
  return null;
953
1379
  try {
954
- const content = fs.readFileSync(filePath, 'utf8');
1380
+ const content = readRegularPluginDefinition(filePath);
955
1381
  const parsedPlugin = JSON.parse(content);
956
1382
  if (this.validatePlugin(parsedPlugin) &&
957
1383
  parsedPlugin.id === sanitizedId &&
958
- this.isPluginDefinitionApproved(parsedPlugin, filePath) &&
959
- this.isPluginVisibleToUser(parsedPlugin, userId)) {
1384
+ (await this.isPluginDefinitionApproved(parsedPlugin, filePath))) {
960
1385
  const plugin = applyPluginDefinitionPolicy(parsedPlugin);
961
- plugin.active = this.isPluginActive(plugin.id, userId);
1386
+ plugin.active = await this.isPluginActive(plugin.id, userId);
962
1387
  return this.applyDiscoveredModels(plugin, userId);
963
1388
  }
964
1389
  }
@@ -967,15 +1392,29 @@ export class PluginService {
967
1392
  }
968
1393
  return null;
969
1394
  }
1395
+ async getPluginUnchecked(id, userId) {
1396
+ if (id === CODEX_OAUTH_PLUGIN_ID)
1397
+ return null;
1398
+ return this.loadPlugin(id, userId);
1399
+ }
1400
+ async getPlugin(id, userId) {
1401
+ const plugin = await this.loadPlugin(id, userId);
1402
+ if (!plugin || !(await this.isPluginVisibleToUser(plugin, userId))) {
1403
+ return null;
1404
+ }
1405
+ return plugin;
1406
+ }
970
1407
  // Install or update a plugin
971
- installPlugin(pluginData, approvedByUserId) {
1408
+ async installPlugin(pluginData, approvedByUserId) {
1409
+ if (!this.sharedPluginDefinitions)
1410
+ this.ensurePluginsDirectory();
972
1411
  if (!this.validatePlugin(pluginData)) {
973
1412
  throw new Error('Invalid plugin structure');
974
1413
  }
975
1414
  if (pluginData.id === CODEX_OAUTH_PLUGIN_ID) {
976
1415
  throw new Error('The bundled Codex OAuth plugin ID is reserved');
977
1416
  }
978
- if (!this.canUseStoredConnectionOverrides(approvedByUserId)) {
1417
+ if (!(await this.canUseStoredConnectionOverrides(approvedByUserId))) {
979
1418
  throw new Error('Administrator approval is required');
980
1419
  }
981
1420
  const now = Date.now();
@@ -988,6 +1427,20 @@ export class PluginService {
988
1427
  const safeId = plugin.id.replace(/[^a-zA-Z0-9_.-]/g, '');
989
1428
  if (safeId !== plugin.id)
990
1429
  throw new Error('Invalid plugin ID');
1430
+ if (this.sharedPluginDefinitions) {
1431
+ await this.repositories().pluginDefinitions.replaceApproved({
1432
+ plugin_id: plugin.id,
1433
+ definition_json: JSON.stringify(plugin, null, 2),
1434
+ definition_fingerprint: getPluginDefinitionFingerprint(plugin),
1435
+ approved_by_user_id: approvedByUserId,
1436
+ approved_at: now,
1437
+ created_at: plugin.created_at || now,
1438
+ updated_at: now,
1439
+ });
1440
+ this.sharedDefinitionIds.add(plugin.id);
1441
+ await this.clearDiscoveredModels(plugin.id);
1442
+ return plugin;
1443
+ }
991
1444
  const filePath = path.resolve(this.pluginsDir, `${safeId}.json`);
992
1445
  if (!filePath.startsWith(path.resolve(this.pluginsDir))) {
993
1446
  throw new Error('Path traversal detected');
@@ -995,8 +1448,8 @@ export class PluginService {
995
1448
  // Revoke definition approval and every user's activation before replacing
996
1449
  // bytes on disk. Any crash or write failure therefore leaves the provider
997
1450
  // quarantined and inactive.
998
- this.revokePluginDefinitionConsent(plugin.id);
999
- this.clearDiscoveredModels(plugin.id);
1451
+ await this.revokePluginDefinitionConsent(plugin.id);
1452
+ await this.clearDiscoveredModels(plugin.id);
1000
1453
  const temporaryPath = path.resolve(this.pluginsDir, `.${safeId}.${process.pid}.${Date.now()}.tmp`);
1001
1454
  try {
1002
1455
  fs.writeFileSync(temporaryPath, JSON.stringify(plugin, null, 2), {
@@ -1010,11 +1463,11 @@ export class PluginService {
1010
1463
  }
1011
1464
  throw error;
1012
1465
  }
1013
- this.approvePluginDefinition(plugin, filePath, approvedByUserId);
1466
+ await this.approvePluginDefinition(plugin, filePath, approvedByUserId);
1014
1467
  return plugin;
1015
1468
  }
1016
1469
  // Delete a plugin
1017
- deletePlugin(id) {
1470
+ async deletePlugin(id) {
1018
1471
  // Validate the ID parameter using a strict pattern (allows dots for version numbers like 1.6b)
1019
1472
  const idPattern = /^[a-zA-Z0-9._-]+$/;
1020
1473
  if (!idPattern.test(id)) {
@@ -1027,23 +1480,37 @@ export class PluginService {
1027
1480
  logger.error('Plugin ID failed sanitization:', id);
1028
1481
  return false;
1029
1482
  }
1483
+ if (this.sharedPluginDefinitions) {
1484
+ try {
1485
+ const removed = await this.repositories().pluginDefinitions.deleteWithState(id);
1486
+ if (!removed)
1487
+ return false;
1488
+ this.sharedDefinitionIds.delete(id);
1489
+ await this.clearDiscoveredModels(id);
1490
+ return true;
1491
+ }
1492
+ catch (error) {
1493
+ logger.error('Failed to delete shared plugin %s:', sanitizedId, error);
1494
+ return false;
1495
+ }
1496
+ }
1030
1497
  const bundledDirectory = path.resolve(this.bundledPluginsDir);
1031
- const writablePluginDirs = Array.from(new Set([this.pluginsDir, this.legacyPluginsDir])).filter(pluginsDir => path.resolve(pluginsDir) !== bundledDirectory);
1498
+ const writablePluginDirs = Array.from(new Set([this.pluginsDir, ...this.legacyPluginsDirs])).filter(pluginsDir => path.resolve(pluginsDir) !== bundledDirectory);
1032
1499
  const filePath = writablePluginDirs
1033
1500
  .map(pluginsDir => path.resolve(pluginsDir, `${sanitizedId}.json`))
1034
- .find(candidate => fs.existsSync(candidate));
1501
+ .find(candidate => isRegularPluginDefinition(candidate));
1035
1502
  if (!filePath) {
1036
1503
  logger.error('File path is invalid or does not exist:', filePath);
1037
1504
  return false;
1038
1505
  }
1039
1506
  try {
1040
1507
  fs.unlinkSync(filePath);
1041
- pluginActivationService.deletePlugin(id);
1042
- this.removePluginDefinitionApproval(id);
1508
+ await pluginActivationService.deletePlugin(id);
1509
+ await this.removePluginDefinitionApproval(id);
1043
1510
  // Clean up stored variables
1044
- pluginVariablesService.deletePluginVariables(id);
1045
- pluginCredentialsService.deleteAllPluginCredentials(id);
1046
- this.clearDiscoveredModels(id);
1511
+ await pluginVariablesService.deletePluginVariables(id);
1512
+ await pluginCredentialsService.deleteAllPluginCredentials(id);
1513
+ await this.clearDiscoveredModels(id);
1047
1514
  return true;
1048
1515
  }
1049
1516
  catch (error) {
@@ -1053,21 +1520,31 @@ export class PluginService {
1053
1520
  }
1054
1521
  // Activate a plugin
1055
1522
  async activatePlugin(id, userId) {
1056
- const plugin = this.getPlugin(id, userId);
1523
+ const plugin = await this.getPlugin(id, userId);
1057
1524
  if (!plugin) {
1058
1525
  throw new Error('Plugin not found');
1059
1526
  }
1060
- if (!pluginActivationService.activate(id, userId)) {
1527
+ if (!(await pluginActivationService.activate(id, userId))) {
1061
1528
  throw new Error('Failed to persist plugin activation');
1062
1529
  }
1063
1530
  // Wait for discovery so the activation response and the UI's first reload
1064
- // observe the same user-scoped model catalog.
1065
- await Promise.all([
1066
- this.discoverModels(id, userId).catch(() => []),
1067
- ...['image', 'tts', 'audio', 'video']
1068
- .filter(capability => plugin.capabilities?.[capability]?.models_endpoint)
1069
- .map(capability => this.discoverCapabilityModels(id, capability, userId).catch(() => undefined)),
1070
- ]);
1531
+ // observe the same user-scoped model catalog. These writes are deliberately
1532
+ // sequential: each persisted catalog publishes a cross-replica plugin-user
1533
+ // invalidation. Running sibling discoveries concurrently would make the
1534
+ // first completed catalog advance every sibling's configuration revision,
1535
+ // causing the remaining valid results to be discarded as stale.
1536
+ await this.discoverModels(id, userId).catch(() => []);
1537
+ for (const capability of [
1538
+ 'image',
1539
+ 'stt',
1540
+ 'tts',
1541
+ 'audio',
1542
+ 'video',
1543
+ ]) {
1544
+ if (!plugin.capabilities?.[capability]?.models_endpoint)
1545
+ continue;
1546
+ await this.discoverCapabilityModels(id, capability, userId).catch(() => undefined);
1547
+ }
1071
1548
  return true;
1072
1549
  }
1073
1550
  // Deactivate a specific plugin
@@ -1076,34 +1553,34 @@ export class PluginService {
1076
1553
  return pluginActivationService.deactivate(id, userId);
1077
1554
  }
1078
1555
  // Get the active plugin for a specific model
1079
- getActivePluginForModel(model, userId, pluginId) {
1556
+ async getActivePluginForModel(model, userId, pluginId) {
1080
1557
  if (pluginId) {
1081
- const plugin = this.getPlugin(pluginId, userId);
1558
+ const plugin = await this.getPlugin(pluginId, userId);
1082
1559
  if (!plugin) {
1083
1560
  throw new Error(`Plugin not found: ${pluginId}`);
1084
1561
  }
1085
- if (!this.isPluginActive(pluginId, userId)) {
1562
+ if (!(await this.isPluginActive(pluginId, userId))) {
1086
1563
  throw new Error(`Plugin is not active: ${pluginId}`);
1087
1564
  }
1088
1565
  if (!plugin.model_map.includes(model)) {
1089
1566
  throw new Error(`Model ${model} is not supported by plugin ${pluginId}`);
1090
1567
  }
1091
- this.resolveOperationEndpoint(plugin, userId);
1092
- const apiKey = this.getApiKey(plugin, userId);
1568
+ await this.resolveOperationEndpoint(plugin, userId);
1569
+ const apiKey = await this.getApiKey(plugin, userId);
1093
1570
  if (pluginRequiresApiKey(plugin) && !apiKey) {
1094
1571
  throw new Error(`API key not found for plugin ${pluginId} (save a provider credential in Settings)`);
1095
1572
  }
1096
1573
  return plugin;
1097
1574
  }
1098
1575
  // Only route through plugins the user explicitly activated.
1099
- const activePlugins = this.getActivePlugins(userId);
1576
+ const activePlugins = await this.getActivePlugins(userId);
1100
1577
  // Find the active plugin that supports this model
1101
1578
  for (const plugin of activePlugins) {
1102
1579
  if (plugin.model_map.includes(model)) {
1103
1580
  // Local OpenAI-compatible servers can explicitly opt out of auth by
1104
1581
  // leaving both auth fields empty.
1105
- this.resolveOperationEndpoint(plugin, userId);
1106
- const apiKey = this.getApiKey(plugin, userId);
1582
+ await this.resolveOperationEndpoint(plugin, userId);
1583
+ const apiKey = await this.getApiKey(plugin, userId);
1107
1584
  if (pluginRequiresApiKey(plugin) && !apiKey) {
1108
1585
  continue;
1109
1586
  }
@@ -1113,30 +1590,34 @@ export class PluginService {
1113
1590
  return null;
1114
1591
  }
1115
1592
  // Get all currently active plugins
1116
- getActivePlugins(userId) {
1117
- const allPlugins = this.getAllPlugins(userId);
1593
+ async getActivePlugins(userId) {
1594
+ const allPlugins = await this.getAllPlugins(userId);
1118
1595
  const activePlugins = allPlugins.filter(plugin => plugin.active);
1119
1596
  return activePlugins;
1120
1597
  }
1598
+ async getActivePluginsUnchecked(userId) {
1599
+ return (await this.getAllPluginsUnchecked(userId)).filter(plugin => plugin.active && plugin.id !== CODEX_OAUTH_PLUGIN_ID);
1600
+ }
1121
1601
  // Legacy method for backward compatibility - returns first active plugin
1122
- getActivePlugin(userId) {
1123
- const activePlugins = this.getActivePlugins(userId);
1602
+ async getActivePlugin(userId) {
1603
+ const activePlugins = await this.getActivePlugins(userId);
1124
1604
  return activePlugins.length > 0 ? activePlugins[0] : null;
1125
1605
  }
1126
1606
  // Get plugin status
1127
- getPluginStatus(userId) {
1128
- const plugins = this.getAllPlugins(userId);
1129
- return plugins.map(plugin => ({
1607
+ async getPluginStatus(userId) {
1608
+ const plugins = await this.getAllPlugins(userId);
1609
+ return Promise.all(plugins.map(async (plugin) => ({
1130
1610
  id: plugin.id,
1131
1611
  active: plugin.active || false,
1132
1612
  available: !pluginRequiresApiKey(plugin) ||
1133
- this.getApiKey(plugin, userId) !== null,
1134
- }));
1613
+ (await this.getApiKey(plugin, userId)) !== null,
1614
+ })));
1135
1615
  }
1136
1616
  // Execute a chat request through the active plugin
1137
- async executePluginRequest(model, messages, options = {}, userId, pluginId) {
1617
+ async executePluginRequest(model, messages, options = {}, userId, pluginId, signal) {
1618
+ throwIfChatGenerationCancelled(signal);
1138
1619
  validatePluginModel(model);
1139
- const activePlugin = this.getActivePluginForModel(model, userId, pluginId);
1620
+ const activePlugin = await this.getActivePluginForModel(model, userId, pluginId);
1140
1621
  if (!activePlugin) {
1141
1622
  throw new Error(`No active plugin found for model: ${model}`);
1142
1623
  }
@@ -1144,11 +1625,11 @@ export class PluginService {
1144
1625
  throw new Error(`Model ${model} is not supported by plugin ${activePlugin.id}`);
1145
1626
  }
1146
1627
  if (activePlugin.id === CODEX_OAUTH_PLUGIN_ID) {
1147
- await codexOAuthService.ensureFreshToken();
1628
+ await codexOAuthService.ensureFreshToken(signal);
1148
1629
  // The codex endpoint only answers as an SSE stream; aggregate it here
1149
1630
  // so non-streaming callers still get a complete response.
1150
1631
  let aggregated = '';
1151
- for await (const chunk of this.executePluginStreamRequest(model, messages, options, userId, activePlugin.id)) {
1632
+ for await (const chunk of this.executePluginStreamRequest(model, messages, options, userId, activePlugin.id, signal)) {
1152
1633
  if (chunk.type === 'content' && chunk.content) {
1153
1634
  aggregated += chunk.content;
1154
1635
  }
@@ -1157,11 +1638,11 @@ export class PluginService {
1157
1638
  choices: [{ message: { role: 'assistant', content: aggregated } }],
1158
1639
  };
1159
1640
  }
1160
- const pluginVars = this.getPluginVariables(activePlugin, userId);
1641
+ const pluginVars = await this.getPluginVariables(activePlugin, userId);
1161
1642
  const { apiMode, endpoint: effectiveEndpoint } = resolvePluginApiConfig(activePlugin, pluginVars);
1162
1643
  const processedEndpoint = applyModelEndpointTemplate(effectiveEndpoint, model);
1163
1644
  assertSafePluginEndpoint(processedEndpoint, 'endpoint URL constructed');
1164
- const apiKey = this.getApiKey(activePlugin, userId);
1645
+ const apiKey = await this.getApiKey(activePlugin, userId);
1165
1646
  if (pluginRequiresApiKey(activePlugin) && !apiKey) {
1166
1647
  throw new Error(`API key not found for plugin ${activePlugin.id} (save a provider credential in Settings)`);
1167
1648
  }
@@ -1177,6 +1658,7 @@ export class PluginService {
1177
1658
  headers,
1178
1659
  timeout: 60000, // 60 second timeout
1179
1660
  maxRedirects: 0,
1661
+ signal,
1180
1662
  });
1181
1663
  const normalized = convertProviderResponse(activePlugin, response.data, model, apiMode, providerStateScope);
1182
1664
  pluginUsageService.record({
@@ -1198,16 +1680,22 @@ export class PluginService {
1198
1680
  return normalized;
1199
1681
  }
1200
1682
  catch (error) {
1683
+ const cancelled = isChatGenerationCancelled(error, signal);
1201
1684
  pluginUsageService.record({
1202
1685
  userId,
1203
1686
  pluginId: activePlugin.id,
1204
1687
  pluginName: activePlugin.name,
1205
1688
  capability: 'chat',
1206
1689
  model,
1207
- status: 'error',
1690
+ status: cancelled ? 'cancelled' : 'error',
1208
1691
  durationMs: Date.now() - startedAt,
1209
1692
  });
1210
- logger.error(`Plugin request failed for ${activePlugin.id}:`, error);
1693
+ if (!cancelled) {
1694
+ logger.error(`Plugin request failed for ${activePlugin.id}:`, error);
1695
+ }
1696
+ if (cancelled) {
1697
+ throw error;
1698
+ }
1211
1699
  if (error && typeof error === 'object' && 'response' in error) {
1212
1700
  const axiosError = error;
1213
1701
  throw new Error(`Plugin API error: ${axiosError.response.status} - ${axiosError.response.data?.error?.message || axiosError.response.statusText}`);
@@ -1226,9 +1714,10 @@ export class PluginService {
1226
1714
  * Returns an async generator that yields SSE delta content strings.
1227
1715
  * Also collects tool_calls from the stream.
1228
1716
  */
1229
- async *executePluginStreamRequest(model, messages, options = {}, userId, pluginId) {
1717
+ async *executePluginStreamRequest(model, messages, options = {}, userId, pluginId, signal) {
1718
+ throwIfChatGenerationCancelled(signal);
1230
1719
  validatePluginModel(model);
1231
- const activePlugin = this.getActivePluginForModel(model, userId, pluginId);
1720
+ const activePlugin = await this.getActivePluginForModel(model, userId, pluginId);
1232
1721
  if (!activePlugin) {
1233
1722
  throw new Error(`No active plugin found for model: ${model}`);
1234
1723
  }
@@ -1236,13 +1725,13 @@ export class PluginService {
1236
1725
  throw new Error(`Model ${model} is not supported by plugin ${activePlugin.id}`);
1237
1726
  }
1238
1727
  if (activePlugin.id === CODEX_OAUTH_PLUGIN_ID) {
1239
- await codexOAuthService.ensureFreshToken();
1728
+ await codexOAuthService.ensureFreshToken(signal);
1240
1729
  }
1241
- const pluginVars = this.getPluginVariables(activePlugin, userId);
1730
+ const pluginVars = await this.getPluginVariables(activePlugin, userId);
1242
1731
  const { apiMode, endpoint: effectiveEndpoint } = resolvePluginApiConfig(activePlugin, pluginVars);
1243
1732
  const processedEndpoint = applyModelEndpointTemplate(effectiveEndpoint, model);
1244
1733
  assertSafePluginEndpoint(processedEndpoint);
1245
- const apiKey = this.getApiKey(activePlugin, userId);
1734
+ const apiKey = await this.getApiKey(activePlugin, userId);
1246
1735
  if (pluginRequiresApiKey(activePlugin) && !apiKey) {
1247
1736
  throw new Error(`API key not found for plugin ${activePlugin.id} (save a provider credential in Settings)`);
1248
1737
  }
@@ -1301,6 +1790,7 @@ export class PluginService {
1301
1790
  headers,
1302
1791
  body: JSON.stringify(payload),
1303
1792
  redirect: 'error',
1793
+ signal,
1304
1794
  });
1305
1795
  if (activePlugin.id === 'anthropic') {
1306
1796
  yield* forward(streamAnthropicResponse(response));
@@ -1377,7 +1867,7 @@ export class PluginService {
1377
1867
  status = 'success';
1378
1868
  }
1379
1869
  catch (error) {
1380
- status = 'error';
1870
+ status = isChatGenerationCancelled(error, signal) ? 'cancelled' : 'error';
1381
1871
  throw error;
1382
1872
  }
1383
1873
  finally {
@@ -1436,23 +1926,29 @@ export class PluginService {
1436
1926
  pluginRecord.model_map.length > 0);
1437
1927
  }
1438
1928
  // Export plugin to JSON
1439
- exportPlugin(id, userId) {
1929
+ async exportPlugin(id, userId) {
1440
1930
  return this.getPlugin(id, userId);
1441
1931
  }
1442
1932
  // Import plugin from JSON data
1443
- importPlugin(pluginData, approvedByUserId) {
1933
+ async importPlugin(pluginData, approvedByUserId) {
1444
1934
  // Validate and clean the plugin data
1445
1935
  if (!this.validatePlugin(pluginData)) {
1446
1936
  throw new Error('Invalid plugin data');
1447
1937
  }
1938
+ if (this.sharedPluginDefinitions) {
1939
+ const existing = await this.repositories().pluginDefinitions.find(pluginData.id);
1940
+ if (existing && this.parseSharedPluginDefinition(existing)) {
1941
+ throw new Error(`Plugin with ID ${pluginData.id} already exists`);
1942
+ }
1943
+ }
1448
1944
  // Check if plugin already exists
1449
1945
  const existingPluginPath = this.resolveEffectivePluginFilePath(pluginData.id);
1450
1946
  if (existingPluginPath) {
1451
1947
  try {
1452
- const existingPlugin = JSON.parse(fs.readFileSync(existingPluginPath, 'utf8'));
1948
+ const existingPlugin = JSON.parse(readRegularPluginDefinition(existingPluginPath));
1453
1949
  if (this.validatePlugin(existingPlugin) &&
1454
1950
  existingPlugin.id === pluginData.id &&
1455
- this.isPluginDefinitionApproved(existingPlugin, existingPluginPath)) {
1951
+ (await this.isPluginDefinitionApproved(existingPlugin, existingPluginPath))) {
1456
1952
  throw new Error(`Plugin with ID ${pluginData.id} already exists`);
1457
1953
  }
1458
1954
  }
@@ -1470,59 +1966,88 @@ export class PluginService {
1470
1966
  // ============================================
1471
1967
  // Capability Methods
1472
1968
  // ============================================
1473
- getPluginForTTS(model, pluginId, userId) {
1969
+ async getPluginForTTS(model, pluginId, userId) {
1474
1970
  return this.ttsService.getPluginForTTS(model, pluginId, userId);
1475
1971
  }
1476
- getPluginForEmbedding(model, pluginId, userId) {
1972
+ async getPluginForEmbedding(model, pluginId, userId) {
1477
1973
  return this.embeddingService.getPluginForEmbedding(model, pluginId, userId);
1478
1974
  }
1479
- getAvailableEmbeddingModels(userId) {
1975
+ async getAvailableEmbeddingModels(userId) {
1480
1976
  return this.embeddingService.getAvailableEmbeddingModels(userId);
1481
1977
  }
1482
- async executeEmbeddingRequest(model, input, pluginId, userId) {
1483
- return this.embeddingService.executeEmbeddingRequest(model, input, pluginId, userId);
1978
+ async executeEmbeddingRequest(model, input, pluginId, userId, signal) {
1979
+ return this.embeddingService.executeEmbeddingRequest(model, input, pluginId, userId, signal);
1484
1980
  }
1485
- getAvailableTTSModels(userId) {
1981
+ async getAvailableTTSModels(userId) {
1486
1982
  return this.ttsService.getAvailableTTSModels(userId);
1487
1983
  }
1984
+ async getAvailableSTTModels(userId) {
1985
+ return this.sttService.getAvailableModels(userId);
1986
+ }
1987
+ executeSTTRequest(model, audio, options) {
1988
+ return this.sttService.transcribe(model, audio, options);
1989
+ }
1488
1990
  async executeTTSRequest(model, input, options = {}) {
1489
1991
  return this.ttsService.executeTTSRequest(model, input, options);
1490
1992
  }
1491
- getTTSConfig(pluginId, userId) {
1993
+ async executeVoiceCloneRequest(model, input, referenceAudio, options = {}) {
1994
+ return this.ttsService.executeVoiceCloneRequest(model, input, referenceAudio, options);
1995
+ }
1996
+ async getTTSConfig(pluginId, userId) {
1492
1997
  return this.ttsService.getTTSConfig(pluginId, userId);
1493
1998
  }
1494
- getPluginForImageGen(model, pluginId, userId) {
1999
+ async getPluginForImageGen(model, pluginId, userId) {
1495
2000
  return this.imageGenerationService.getPluginForImageGen(model, pluginId, userId);
1496
2001
  }
1497
- getAvailableImageGenModels(userId) {
2002
+ async getAvailableImageGenModels(userId) {
1498
2003
  return this.imageGenerationService.getAvailableImageGenModels(userId);
1499
2004
  }
1500
2005
  async executeImageGenRequest(model, prompt, options) {
1501
2006
  return this.imageGenerationService.executeImageGenRequest(model, prompt, options);
1502
2007
  }
1503
- getImageGenConfig(pluginId, userId) {
2008
+ async getImageGenConfig(pluginId, userId) {
1504
2009
  return this.imageGenerationService.getImageGenConfig(pluginId, userId);
1505
2010
  }
1506
- getPluginsByCapability(capabilityType, userId) {
2011
+ async getPluginsByCapability(capabilityType, userId) {
1507
2012
  return this.capabilityRegistryService.getPluginsByCapability(capabilityType, userId);
1508
2013
  }
1509
- getAvailableAudioGenModels(userId) {
2014
+ async getAvailableAudioGenModels(userId) {
1510
2015
  return this.audioGenerationService.getAvailableModels(userId);
1511
2016
  }
1512
2017
  executeAudioGenRequest(model, prompt, options) {
1513
2018
  return this.audioGenerationService.generate(model, prompt, options);
1514
2019
  }
1515
- getAvailableVideoGenModels(userId) {
2020
+ async getAvailableVideoGenModels(userId) {
1516
2021
  return this.videoGenerationService.getAvailableModels(userId);
1517
2022
  }
1518
2023
  submitVideoGenRequest(model, prompt, options) {
1519
2024
  return this.videoGenerationService.submit(model, prompt, options);
1520
2025
  }
1521
- pollVideoGenRequest(model, providerJobId, pluginId, userId) {
1522
- return this.videoGenerationService.poll(model, providerJobId, pluginId, userId);
1523
- }
1524
- downloadVideoGenResult(model, providerJobId, pluginId, userId) {
1525
- return this.videoGenerationService.download(model, providerJobId, pluginId, userId);
2026
+ pollVideoGenRequest(model, providerJobId, pluginId, userId, signal) {
2027
+ return this.videoGenerationService.poll(model, providerJobId, pluginId, userId, signal);
2028
+ }
2029
+ downloadVideoGenResult(model, providerJobId, pluginId, userId, signal) {
2030
+ return this.videoGenerationService.download(model, providerJobId, pluginId, userId, signal);
2031
+ }
2032
+ async canCancelVideoGenRequest(model, pluginId, userId) {
2033
+ return this.videoGenerationService.supportsCancellation(model, pluginId, userId);
2034
+ }
2035
+ cancelVideoGenRequest(model, providerJobId, pluginId, userId, signal) {
2036
+ return this.videoGenerationService.cancel(model, providerJobId, pluginId, userId, signal);
2037
+ }
2038
+ async closeCacheInvalidation() {
2039
+ this.removeCacheInvalidationListener?.();
2040
+ this.removeCacheInvalidationListener = undefined;
2041
+ this.discoveredModelsCache.clear();
2042
+ this.discoveredModelsUpdatedAt.clear();
2043
+ this.discoveryAttemptedAt.clear();
2044
+ this.inflightDiscovery.clear();
2045
+ this.discoveredCapabilityModelsCache.clear();
2046
+ this.discoveredCapabilityModelsUpdatedAt.clear();
2047
+ this.capabilityDiscoveryAttemptedAt.clear();
2048
+ this.inflightCapabilityDiscovery.clear();
2049
+ this.discoveryCacheRevisions.clear();
2050
+ this.capabilityDiscoveryCacheRevisions.clear();
1526
2051
  }
1527
2052
  }
1528
2053
  export default new PluginService();