@jagilber-org/index-server 1.19.1

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 (360) hide show
  1. package/CHANGELOG.md +1218 -0
  2. package/CODE_OF_CONDUCT.md +49 -0
  3. package/CONTRIBUTING.md +75 -0
  4. package/LICENSE +21 -0
  5. package/README.md +523 -0
  6. package/SECURITY.md +50 -0
  7. package/dist/config/configUtils.d.ts +11 -0
  8. package/dist/config/configUtils.js +87 -0
  9. package/dist/config/dashboardConfig.d.ts +45 -0
  10. package/dist/config/dashboardConfig.js +63 -0
  11. package/dist/config/defaultValues.d.ts +61 -0
  12. package/dist/config/defaultValues.js +70 -0
  13. package/dist/config/dirConstants.d.ts +17 -0
  14. package/dist/config/dirConstants.js +28 -0
  15. package/dist/config/featureConfig.d.ts +61 -0
  16. package/dist/config/featureConfig.js +121 -0
  17. package/dist/config/runtimeConfig.d.ts +145 -0
  18. package/dist/config/runtimeConfig.js +334 -0
  19. package/dist/config/serverConfig.d.ts +90 -0
  20. package/dist/config/serverConfig.js +164 -0
  21. package/dist/dashboard/analytics/AnalyticsEngine.d.ts +142 -0
  22. package/dist/dashboard/analytics/AnalyticsEngine.js +373 -0
  23. package/dist/dashboard/analytics/BusinessIntelligence.d.ts +187 -0
  24. package/dist/dashboard/analytics/BusinessIntelligence.js +594 -0
  25. package/dist/dashboard/client/admin.html +2150 -0
  26. package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/chunk-SP2CHFBE.mjs +1 -0
  27. package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/render-T6MDALS3.mjs +27 -0
  28. package/dist/dashboard/client/css/admin.css +1466 -0
  29. package/dist/dashboard/client/js/admin.boot.js +359 -0
  30. package/dist/dashboard/client/js/admin.config.js +196 -0
  31. package/dist/dashboard/client/js/admin.embeddings.js +425 -0
  32. package/dist/dashboard/client/js/admin.graph.js +583 -0
  33. package/dist/dashboard/client/js/admin.instances.js +120 -0
  34. package/dist/dashboard/client/js/admin.instructions.js +552 -0
  35. package/dist/dashboard/client/js/admin.logs.js +113 -0
  36. package/dist/dashboard/client/js/admin.maintenance.js +354 -0
  37. package/dist/dashboard/client/js/admin.messaging.js +635 -0
  38. package/dist/dashboard/client/js/admin.monitor.js +181 -0
  39. package/dist/dashboard/client/js/admin.overview.js +221 -0
  40. package/dist/dashboard/client/js/admin.performance.js +61 -0
  41. package/dist/dashboard/client/js/admin.sessions.js +293 -0
  42. package/dist/dashboard/client/js/admin.sqlite.js +366 -0
  43. package/dist/dashboard/client/js/admin.utils.js +49 -0
  44. package/dist/dashboard/client/js/chart.umd.js +14 -0
  45. package/dist/dashboard/client/js/elk.bundled.js +6696 -0
  46. package/dist/dashboard/client/js/marked.umd.js +74 -0
  47. package/dist/dashboard/client/js/mermaid.min.js +3022 -0
  48. package/dist/dashboard/client/mermaid-layout-elk.esm.min.mjs +1 -0
  49. package/dist/dashboard/export/DataExporter.d.ts +169 -0
  50. package/dist/dashboard/export/DataExporter.js +737 -0
  51. package/dist/dashboard/export/exporters/csvExporter.d.ts +11 -0
  52. package/dist/dashboard/export/exporters/csvExporter.js +46 -0
  53. package/dist/dashboard/export/exporters/exportTypes.d.ts +89 -0
  54. package/dist/dashboard/export/exporters/exportTypes.js +5 -0
  55. package/dist/dashboard/export/exporters/jsonExporter.d.ts +7 -0
  56. package/dist/dashboard/export/exporters/jsonExporter.js +22 -0
  57. package/dist/dashboard/export/exporters/xmlExporter.d.ts +17 -0
  58. package/dist/dashboard/export/exporters/xmlExporter.js +175 -0
  59. package/dist/dashboard/integration/APIIntegration.d.ts +41 -0
  60. package/dist/dashboard/integration/APIIntegration.js +95 -0
  61. package/dist/dashboard/security/SecurityMonitor.d.ts +167 -0
  62. package/dist/dashboard/security/SecurityMonitor.js +559 -0
  63. package/dist/dashboard/server/AdminPanel.d.ts +183 -0
  64. package/dist/dashboard/server/AdminPanel.js +792 -0
  65. package/dist/dashboard/server/AdminPanelConfig.d.ts +42 -0
  66. package/dist/dashboard/server/AdminPanelConfig.js +80 -0
  67. package/dist/dashboard/server/AdminPanelState.d.ts +47 -0
  68. package/dist/dashboard/server/AdminPanelState.js +214 -0
  69. package/dist/dashboard/server/ApiRoutes.d.ts +17 -0
  70. package/dist/dashboard/server/ApiRoutes.js +149 -0
  71. package/dist/dashboard/server/DashboardServer.d.ts +49 -0
  72. package/dist/dashboard/server/DashboardServer.js +159 -0
  73. package/dist/dashboard/server/FileMetricsStorage.d.ts +49 -0
  74. package/dist/dashboard/server/FileMetricsStorage.js +195 -0
  75. package/dist/dashboard/server/HttpTransport.d.ts +23 -0
  76. package/dist/dashboard/server/HttpTransport.js +116 -0
  77. package/dist/dashboard/server/InstanceManager.d.ts +53 -0
  78. package/dist/dashboard/server/InstanceManager.js +284 -0
  79. package/dist/dashboard/server/KnowledgeStore.d.ts +35 -0
  80. package/dist/dashboard/server/KnowledgeStore.js +105 -0
  81. package/dist/dashboard/server/LeaderElection.d.ts +81 -0
  82. package/dist/dashboard/server/LeaderElection.js +268 -0
  83. package/dist/dashboard/server/MetricsCollector.d.ts +200 -0
  84. package/dist/dashboard/server/MetricsCollector.js +803 -0
  85. package/dist/dashboard/server/SessionPersistenceManager.d.ts +88 -0
  86. package/dist/dashboard/server/SessionPersistenceManager.js +457 -0
  87. package/dist/dashboard/server/ThinClient.d.ts +64 -0
  88. package/dist/dashboard/server/ThinClient.js +237 -0
  89. package/dist/dashboard/server/WebSocketManager.d.ts +161 -0
  90. package/dist/dashboard/server/WebSocketManager.js +463 -0
  91. package/dist/dashboard/server/httpLifecycle.d.ts +17 -0
  92. package/dist/dashboard/server/httpLifecycle.js +35 -0
  93. package/dist/dashboard/server/legacyDashboardHtml.d.ts +9 -0
  94. package/dist/dashboard/server/legacyDashboardHtml.js +618 -0
  95. package/dist/dashboard/server/legacyDashboardStyles.d.ts +5 -0
  96. package/dist/dashboard/server/legacyDashboardStyles.js +490 -0
  97. package/dist/dashboard/server/metricsAggregation.d.ts +252 -0
  98. package/dist/dashboard/server/metricsAggregation.js +206 -0
  99. package/dist/dashboard/server/metricsSerializer.d.ts +25 -0
  100. package/dist/dashboard/server/metricsSerializer.js +195 -0
  101. package/dist/dashboard/server/routes/admin.routes.d.ts +16 -0
  102. package/dist/dashboard/server/routes/admin.routes.js +596 -0
  103. package/dist/dashboard/server/routes/alerts.routes.d.ts +7 -0
  104. package/dist/dashboard/server/routes/alerts.routes.js +93 -0
  105. package/dist/dashboard/server/routes/api.feedback.routes.d.ts +73 -0
  106. package/dist/dashboard/server/routes/api.feedback.routes.js +171 -0
  107. package/dist/dashboard/server/routes/api.instructions.routes.d.ts +101 -0
  108. package/dist/dashboard/server/routes/api.instructions.routes.js +213 -0
  109. package/dist/dashboard/server/routes/api.usage.routes.d.ts +57 -0
  110. package/dist/dashboard/server/routes/api.usage.routes.js +374 -0
  111. package/dist/dashboard/server/routes/embeddings.routes.d.ts +6 -0
  112. package/dist/dashboard/server/routes/embeddings.routes.js +246 -0
  113. package/dist/dashboard/server/routes/graph.routes.d.ts +6 -0
  114. package/dist/dashboard/server/routes/graph.routes.js +280 -0
  115. package/dist/dashboard/server/routes/index.d.ts +38 -0
  116. package/dist/dashboard/server/routes/index.js +194 -0
  117. package/dist/dashboard/server/routes/instances.routes.d.ts +6 -0
  118. package/dist/dashboard/server/routes/instances.routes.js +35 -0
  119. package/dist/dashboard/server/routes/instructions.routes.d.ts +8 -0
  120. package/dist/dashboard/server/routes/instructions.routes.js +336 -0
  121. package/dist/dashboard/server/routes/knowledge.routes.d.ts +6 -0
  122. package/dist/dashboard/server/routes/knowledge.routes.js +82 -0
  123. package/dist/dashboard/server/routes/logs.routes.d.ts +6 -0
  124. package/dist/dashboard/server/routes/logs.routes.js +164 -0
  125. package/dist/dashboard/server/routes/messaging.routes.d.ts +16 -0
  126. package/dist/dashboard/server/routes/messaging.routes.js +293 -0
  127. package/dist/dashboard/server/routes/metrics.routes.d.ts +10 -0
  128. package/dist/dashboard/server/routes/metrics.routes.js +346 -0
  129. package/dist/dashboard/server/routes/scripts.routes.d.ts +9 -0
  130. package/dist/dashboard/server/routes/scripts.routes.js +84 -0
  131. package/dist/dashboard/server/routes/sqlite.routes.d.ts +9 -0
  132. package/dist/dashboard/server/routes/sqlite.routes.js +569 -0
  133. package/dist/dashboard/server/routes/status.routes.d.ts +7 -0
  134. package/dist/dashboard/server/routes/status.routes.js +183 -0
  135. package/dist/dashboard/server/routes/synthetic.routes.d.ts +7 -0
  136. package/dist/dashboard/server/routes/synthetic.routes.js +195 -0
  137. package/dist/dashboard/server/routes/tools.routes.d.ts +6 -0
  138. package/dist/dashboard/server/routes/tools.routes.js +46 -0
  139. package/dist/dashboard/server/routes/usage.routes.d.ts +6 -0
  140. package/dist/dashboard/server/routes/usage.routes.js +25 -0
  141. package/dist/dashboard/server/wsInit.d.ts +16 -0
  142. package/dist/dashboard/server/wsInit.js +35 -0
  143. package/dist/externalClientLib.d.ts +1 -0
  144. package/dist/externalClientLib.js +2 -0
  145. package/dist/minimal/index.d.ts +1 -0
  146. package/dist/minimal/index.js +140 -0
  147. package/dist/models/SessionPersistence.d.ts +115 -0
  148. package/dist/models/SessionPersistence.js +66 -0
  149. package/dist/models/instruction.d.ts +45 -0
  150. package/dist/models/instruction.js +2 -0
  151. package/dist/perf/benchmark.d.ts +1 -0
  152. package/dist/perf/benchmark.js +50 -0
  153. package/dist/portableClientWrapper.d.ts +1 -0
  154. package/dist/portableClientWrapper.js +2 -0
  155. package/dist/schemas/index.d.ts +128 -0
  156. package/dist/schemas/index.js +371 -0
  157. package/dist/scripts/runPerformanceBaseline.d.ts +1 -0
  158. package/dist/scripts/runPerformanceBaseline.js +17 -0
  159. package/dist/server/handshakeManager.d.ts +25 -0
  160. package/dist/server/handshakeManager.js +472 -0
  161. package/dist/server/index-server.d.ts +56 -0
  162. package/dist/server/index-server.js +822 -0
  163. package/dist/server/registry.d.ts +44 -0
  164. package/dist/server/registry.js +236 -0
  165. package/dist/server/sdkServer.d.ts +8 -0
  166. package/dist/server/sdkServer.js +299 -0
  167. package/dist/server/shutdownGuard.d.ts +41 -0
  168. package/dist/server/shutdownGuard.js +52 -0
  169. package/dist/server/thin-client.d.ts +22 -0
  170. package/dist/server/thin-client.js +111 -0
  171. package/dist/server/transport.d.ts +41 -0
  172. package/dist/server/transport.js +312 -0
  173. package/dist/server/transportFactory.d.ts +21 -0
  174. package/dist/server/transportFactory.js +429 -0
  175. package/dist/services/atomicFs.d.ts +22 -0
  176. package/dist/services/atomicFs.js +103 -0
  177. package/dist/services/auditLog.d.ts +38 -0
  178. package/dist/services/auditLog.js +142 -0
  179. package/dist/services/autoBackup.d.ts +14 -0
  180. package/dist/services/autoBackup.js +171 -0
  181. package/dist/services/autoSplit.d.ts +32 -0
  182. package/dist/services/autoSplit.js +113 -0
  183. package/dist/services/backupZip.d.ts +25 -0
  184. package/dist/services/backupZip.js +110 -0
  185. package/dist/services/bootstrapGating.d.ts +123 -0
  186. package/dist/services/bootstrapGating.js +221 -0
  187. package/dist/services/canonical.d.ts +23 -0
  188. package/dist/services/canonical.js +65 -0
  189. package/dist/services/categoryRules.d.ts +7 -0
  190. package/dist/services/categoryRules.js +37 -0
  191. package/dist/services/classificationService.d.ts +42 -0
  192. package/dist/services/classificationService.js +168 -0
  193. package/dist/services/embeddingService.d.ts +62 -0
  194. package/dist/services/embeddingService.js +259 -0
  195. package/dist/services/errors.d.ts +22 -0
  196. package/dist/services/errors.js +31 -0
  197. package/dist/services/featureFlags.d.ts +25 -0
  198. package/dist/services/featureFlags.js +89 -0
  199. package/dist/services/features.d.ts +13 -0
  200. package/dist/services/features.js +35 -0
  201. package/dist/services/handlers/instructions.add.d.ts +1 -0
  202. package/dist/services/handlers/instructions.add.js +496 -0
  203. package/dist/services/handlers/instructions.groom.d.ts +1 -0
  204. package/dist/services/handlers/instructions.groom.js +523 -0
  205. package/dist/services/handlers/instructions.import.d.ts +1 -0
  206. package/dist/services/handlers/instructions.import.js +173 -0
  207. package/dist/services/handlers/instructions.patch.d.ts +1 -0
  208. package/dist/services/handlers/instructions.patch.js +167 -0
  209. package/dist/services/handlers/instructions.query.d.ts +163 -0
  210. package/dist/services/handlers/instructions.query.js +522 -0
  211. package/dist/services/handlers/instructions.reload.d.ts +1 -0
  212. package/dist/services/handlers/instructions.reload.js +13 -0
  213. package/dist/services/handlers/instructions.remove.d.ts +1 -0
  214. package/dist/services/handlers/instructions.remove.js +118 -0
  215. package/dist/services/handlers/instructions.shared.d.ts +31 -0
  216. package/dist/services/handlers/instructions.shared.js +124 -0
  217. package/dist/services/handlers.activation.d.ts +1 -0
  218. package/dist/services/handlers.activation.js +203 -0
  219. package/dist/services/handlers.bootstrap.d.ts +1 -0
  220. package/dist/services/handlers.bootstrap.js +38 -0
  221. package/dist/services/handlers.dashboardConfig.d.ts +34 -0
  222. package/dist/services/handlers.dashboardConfig.js +108 -0
  223. package/dist/services/handlers.diagnostics.d.ts +1 -0
  224. package/dist/services/handlers.diagnostics.js +64 -0
  225. package/dist/services/handlers.feedback.d.ts +15 -0
  226. package/dist/services/handlers.feedback.js +378 -0
  227. package/dist/services/handlers.gates.d.ts +1 -0
  228. package/dist/services/handlers.gates.js +46 -0
  229. package/dist/services/handlers.graph.d.ts +53 -0
  230. package/dist/services/handlers.graph.js +231 -0
  231. package/dist/services/handlers.help.d.ts +1 -0
  232. package/dist/services/handlers.help.js +119 -0
  233. package/dist/services/handlers.instructionSchema.d.ts +1 -0
  234. package/dist/services/handlers.instructionSchema.js +227 -0
  235. package/dist/services/handlers.instructions.d.ts +8 -0
  236. package/dist/services/handlers.instructions.js +14 -0
  237. package/dist/services/handlers.instructionsDiagnostics.d.ts +1 -0
  238. package/dist/services/handlers.instructionsDiagnostics.js +14 -0
  239. package/dist/services/handlers.integrity.d.ts +1 -0
  240. package/dist/services/handlers.integrity.js +35 -0
  241. package/dist/services/handlers.manifest.d.ts +1 -0
  242. package/dist/services/handlers.manifest.js +24 -0
  243. package/dist/services/handlers.messaging.d.ts +12 -0
  244. package/dist/services/handlers.messaging.js +203 -0
  245. package/dist/services/handlers.metrics.d.ts +1 -0
  246. package/dist/services/handlers.metrics.js +43 -0
  247. package/dist/services/handlers.promote.d.ts +1 -0
  248. package/dist/services/handlers.promote.js +306 -0
  249. package/dist/services/handlers.prompt.d.ts +1 -0
  250. package/dist/services/handlers.prompt.js +7 -0
  251. package/dist/services/handlers.search.d.ts +69 -0
  252. package/dist/services/handlers.search.js +645 -0
  253. package/dist/services/handlers.testPrimitive.d.ts +1 -0
  254. package/dist/services/handlers.testPrimitive.js +5 -0
  255. package/dist/services/handlers.trace.d.ts +1 -0
  256. package/dist/services/handlers.trace.js +31 -0
  257. package/dist/services/handlers.usage.d.ts +1 -0
  258. package/dist/services/handlers.usage.js +11 -0
  259. package/dist/services/hotScore.d.ts +137 -0
  260. package/dist/services/hotScore.js +244 -0
  261. package/dist/services/indexContext.d.ts +117 -0
  262. package/dist/services/indexContext.js +968 -0
  263. package/dist/services/indexLoader.d.ts +44 -0
  264. package/dist/services/indexLoader.js +921 -0
  265. package/dist/services/indexRepository.d.ts +32 -0
  266. package/dist/services/indexRepository.js +71 -0
  267. package/dist/services/indexingService.d.ts +1 -0
  268. package/dist/services/indexingService.js +2 -0
  269. package/dist/services/instructions.dispatcher.d.ts +1 -0
  270. package/dist/services/instructions.dispatcher.js +231 -0
  271. package/dist/services/logPrefix.d.ts +1 -0
  272. package/dist/services/logPrefix.js +30 -0
  273. package/dist/services/logger.d.ts +52 -0
  274. package/dist/services/logger.js +268 -0
  275. package/dist/services/manifestManager.d.ts +82 -0
  276. package/dist/services/manifestManager.js +200 -0
  277. package/dist/services/messaging/agentMailbox.d.ts +60 -0
  278. package/dist/services/messaging/agentMailbox.js +353 -0
  279. package/dist/services/messaging/messagingPersistence.d.ts +20 -0
  280. package/dist/services/messaging/messagingPersistence.js +111 -0
  281. package/dist/services/messaging/messagingTypes.d.ts +150 -0
  282. package/dist/services/messaging/messagingTypes.js +66 -0
  283. package/dist/services/ownershipService.d.ts +1 -0
  284. package/dist/services/ownershipService.js +38 -0
  285. package/dist/services/performanceBaseline.d.ts +19 -0
  286. package/dist/services/performanceBaseline.js +210 -0
  287. package/dist/services/preflight.d.ts +12 -0
  288. package/dist/services/preflight.js +79 -0
  289. package/dist/services/promptReviewService.d.ts +44 -0
  290. package/dist/services/promptReviewService.js +101 -0
  291. package/dist/services/responseEnvelope.d.ts +6 -0
  292. package/dist/services/responseEnvelope.js +25 -0
  293. package/dist/services/seedBootstrap.d.ts +34 -0
  294. package/dist/services/seedBootstrap.js +427 -0
  295. package/dist/services/storage/factory.d.ts +17 -0
  296. package/dist/services/storage/factory.js +35 -0
  297. package/dist/services/storage/hashUtils.d.ts +11 -0
  298. package/dist/services/storage/hashUtils.js +35 -0
  299. package/dist/services/storage/index.d.ts +12 -0
  300. package/dist/services/storage/index.js +18 -0
  301. package/dist/services/storage/jsonFileStore.d.ts +32 -0
  302. package/dist/services/storage/jsonFileStore.js +241 -0
  303. package/dist/services/storage/migrationEngine.d.ts +35 -0
  304. package/dist/services/storage/migrationEngine.js +93 -0
  305. package/dist/services/storage/sqliteMessageStore.d.ts +53 -0
  306. package/dist/services/storage/sqliteMessageStore.js +146 -0
  307. package/dist/services/storage/sqliteSchema.d.ts +12 -0
  308. package/dist/services/storage/sqliteSchema.js +122 -0
  309. package/dist/services/storage/sqliteStore.d.ts +41 -0
  310. package/dist/services/storage/sqliteStore.js +339 -0
  311. package/dist/services/storage/sqliteUsageStore.d.ts +35 -0
  312. package/dist/services/storage/sqliteUsageStore.js +94 -0
  313. package/dist/services/storage/types.d.ts +171 -0
  314. package/dist/services/storage/types.js +12 -0
  315. package/dist/services/toolHandlers.d.ts +23 -0
  316. package/dist/services/toolHandlers.js +50 -0
  317. package/dist/services/toolRegistry.d.ts +20 -0
  318. package/dist/services/toolRegistry.js +490 -0
  319. package/dist/services/toolRegistry.zod.d.ts +10 -0
  320. package/dist/services/toolRegistry.zod.js +323 -0
  321. package/dist/services/tracing.d.ts +26 -0
  322. package/dist/services/tracing.js +260 -0
  323. package/dist/services/usageBuckets.d.ts +161 -0
  324. package/dist/services/usageBuckets.js +364 -0
  325. package/dist/services/validationService.d.ts +38 -0
  326. package/dist/services/validationService.js +125 -0
  327. package/dist/utils/BufferRing.d.ts +203 -0
  328. package/dist/utils/BufferRing.js +551 -0
  329. package/dist/utils/BufferRingExamples.d.ts +55 -0
  330. package/dist/utils/BufferRingExamples.js +188 -0
  331. package/dist/utils/envUtils.d.ts +42 -0
  332. package/dist/utils/envUtils.js +80 -0
  333. package/dist/utils/memoryMonitor.d.ts +83 -0
  334. package/dist/utils/memoryMonitor.js +275 -0
  335. package/dist/versioning/schemaVersion.d.ts +6 -0
  336. package/dist/versioning/schemaVersion.js +93 -0
  337. package/package.json +134 -0
  338. package/schemas/README.md +13 -0
  339. package/schemas/feedback-entry.schema.json +27 -0
  340. package/schemas/graph-export-v2.schema.json +60 -0
  341. package/schemas/index-server.code-schema.json +38477 -0
  342. package/schemas/instruction.schema.json +262 -0
  343. package/schemas/json-schema/SessionPersistence-persisted-admin-session.schema.json +54 -0
  344. package/schemas/json-schema/SessionPersistence-persisted-session-history-entry.schema.json +51 -0
  345. package/schemas/json-schema/SessionPersistence-persisted-web-socket-connection.schema.json +54 -0
  346. package/schemas/json-schema/SessionPersistence-session-persistence-config.schema.json +110 -0
  347. package/schemas/json-schema/SessionPersistence-session-persistence-data.schema.json +229 -0
  348. package/schemas/json-schema/SessionPersistence-session-persistence-manifest.schema.json +109 -0
  349. package/schemas/json-schema/SessionPersistence-session-persistence-metadata.schema.json +55 -0
  350. package/schemas/json-schema/instruction-audience-scope.schema.json +14 -0
  351. package/schemas/json-schema/instruction-content-type.schema.json +17 -0
  352. package/schemas/json-schema/instruction-instruction-entry.schema.json +206 -0
  353. package/schemas/json-schema/instruction-requirement-level.schema.json +16 -0
  354. package/schemas/manifest.json +78 -0
  355. package/schemas/manifest.schema.json +33 -0
  356. package/schemas/usage-batch.schema.json +16 -0
  357. package/schemas/usage-buckets.schema.json +30 -0
  358. package/schemas/usage-event.schema.json +17 -0
  359. package/scripts/copy-dashboard-assets.mjs +170 -0
  360. package/scripts/setup-hooks.cjs +28 -0
@@ -0,0 +1,792 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AdminPanel = void 0;
7
+ exports.getAdminPanel = getAdminPanel;
8
+ /**
9
+ * Index Server Admin - Enterprise Administration Interface
10
+ *
11
+ * Thin coordinator that delegates to:
12
+ * - AdminPanelConfig — server configuration rendering/serialization
13
+ * - AdminPanelState — admin session state management
14
+ *
15
+ * Retains direct responsibility for maintenance operations, backup/restore,
16
+ * system health monitoring, and admin statistics.
17
+ */
18
+ const fs_1 = __importDefault(require("fs"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const v8_1 = __importDefault(require("v8"));
21
+ const runtimeConfig_1 = require("../../config/runtimeConfig");
22
+ const MetricsCollector_1 = require("./MetricsCollector");
23
+ const indexContext_1 = require("../../services/indexContext");
24
+ const AdminPanelConfig_1 = require("./AdminPanelConfig");
25
+ const AdminPanelState_1 = require("./AdminPanelState");
26
+ const backupZip_1 = require("../../services/backupZip");
27
+ const adm_zip_1 = __importDefault(require("adm-zip"));
28
+ class AdminPanel {
29
+ panelConfig;
30
+ panelState;
31
+ maintenanceInfo;
32
+ indexStatsCache = null;
33
+ lastUptimeSeconds = 0;
34
+ get backupRoot() {
35
+ return (0, runtimeConfig_1.getRuntimeConfig)().dashboard.admin.backupsDir || path_1.default.join(process.cwd(), 'backups');
36
+ }
37
+ get instructionsRoot() {
38
+ return (0, runtimeConfig_1.getRuntimeConfig)().index.baseDir || path_1.default.join(process.cwd(), 'instructions');
39
+ }
40
+ // CPU tracking for leak detection
41
+ cpuHistory = [];
42
+ lastCpuUsage = null;
43
+ maxCpuHistoryEntries = 100;
44
+ // Memory tracking for leak detection
45
+ memoryHistory = [];
46
+ maxMemoryHistoryEntries = 100;
47
+ constructor() {
48
+ this.panelConfig = new AdminPanelConfig_1.AdminPanelConfig();
49
+ this.panelState = new AdminPanelState_1.AdminPanelState();
50
+ this.maintenanceInfo = {
51
+ lastBackup: null,
52
+ nextScheduledMaintenance: null,
53
+ maintenanceMode: false,
54
+ systemHealth: { status: 'healthy', issues: [], recommendations: [] }
55
+ };
56
+ }
57
+ // ── Config delegation ──────────────────────────────────────────────────────────────
58
+ getAdminConfig() {
59
+ return this.panelConfig.getAdminConfig();
60
+ }
61
+ updateAdminConfig(updates) {
62
+ return this.panelConfig.updateAdminConfig(updates);
63
+ }
64
+ // ── Session state delegation ────────────────────────────────────────────────────────
65
+ getActiveSessions() {
66
+ return this.panelState.getActiveSessions(this.panelConfig.sessionTimeout);
67
+ }
68
+ createAdminSession(userId, ipAddress, userAgent) {
69
+ return this.panelState.createAdminSession(userId, ipAddress, userAgent);
70
+ }
71
+ terminateSession(sessionId) {
72
+ return this.panelState.terminateSession(sessionId);
73
+ }
74
+ /**
75
+ * Get system maintenance information
76
+ */
77
+ getMaintenanceInfo() {
78
+ // Update system health
79
+ this.updateSystemHealth();
80
+ return JSON.parse(JSON.stringify(this.maintenanceInfo));
81
+ }
82
+ /**
83
+ * Set maintenance mode
84
+ */
85
+ setMaintenanceMode(enabled, message) {
86
+ try {
87
+ this.maintenanceInfo.maintenanceMode = enabled;
88
+ if (enabled) {
89
+ process.stderr.write(`[admin] Maintenance mode ENABLED${message ? `: ${message}` : ''}\n`);
90
+ }
91
+ else {
92
+ process.stderr.write(`[admin] Maintenance mode DISABLED\n`);
93
+ }
94
+ return {
95
+ success: true,
96
+ message: `Maintenance mode ${enabled ? 'enabled' : 'disabled'}`
97
+ };
98
+ }
99
+ catch (error) {
100
+ return {
101
+ success: false,
102
+ message: `Failed to set maintenance mode: ${error instanceof Error ? error.message : String(error)}`
103
+ };
104
+ }
105
+ }
106
+ /**
107
+ * Perform system backup
108
+ */
109
+ async performBackup() {
110
+ try {
111
+ const backupRoot = this.backupRoot;
112
+ if (!fs_1.default.existsSync(backupRoot))
113
+ fs_1.default.mkdirSync(backupRoot, { recursive: true });
114
+ const now = new Date();
115
+ const iso = now.toISOString();
116
+ const baseTs = iso.replace(/[-:]/g, '').replace(/\..+/, '');
117
+ const ms = String(now.getMilliseconds()).padStart(3, '0');
118
+ const backupId = `backup_${baseTs}_${ms}`;
119
+ const zipPath = path_1.default.join(backupRoot, `${backupId}.zip`);
120
+ const instructionsDir = this.instructionsRoot;
121
+ let fileCount = 0;
122
+ if (fs_1.default.existsSync(instructionsDir)) {
123
+ fileCount = fs_1.default.readdirSync(instructionsDir).filter(f => f.toLowerCase().endsWith('.json')).length;
124
+ }
125
+ const manifest = {
126
+ backupId,
127
+ createdAt: now.toISOString(),
128
+ instructionCount: fileCount,
129
+ schemaVersion: this.indexStatsCache?.schemaVersion || 'unknown',
130
+ };
131
+ (0, backupZip_1.createZipBackupWithManifest)(instructionsDir, zipPath, manifest);
132
+ this.maintenanceInfo.lastBackup = new Date();
133
+ process.stderr.write(`[admin] System backup completed: ${backupId}.zip (${fileCount} files)\n`);
134
+ return { success: true, message: 'System backup completed successfully', backupId, files: fileCount };
135
+ }
136
+ catch (error) {
137
+ return {
138
+ success: false,
139
+ message: `Backup failed: ${error instanceof Error ? error.message : String(error)}`
140
+ };
141
+ }
142
+ }
143
+ listBackups() {
144
+ const backupRoot = this.backupRoot;
145
+ if (!fs_1.default.existsSync(backupRoot))
146
+ return [];
147
+ const results = [];
148
+ for (const entry of fs_1.default.readdirSync(backupRoot)) {
149
+ const full = path_1.default.join(backupRoot, entry);
150
+ try {
151
+ const stat = fs_1.default.statSync(full);
152
+ if ((0, backupZip_1.isZipBackup)(entry) && stat.isFile()) {
153
+ // Zip backup
154
+ const id = entry.replace(/\.zip$/i, '');
155
+ let createdAt = new Date(stat.mtime).toISOString();
156
+ let instructionCount = 0;
157
+ let schemaVersion;
158
+ const manifest = (0, backupZip_1.readZipManifest)(full);
159
+ if (manifest) {
160
+ createdAt = manifest.createdAt || createdAt;
161
+ instructionCount = manifest.instructionCount || 0;
162
+ schemaVersion = manifest.schemaVersion;
163
+ }
164
+ else {
165
+ instructionCount = (0, backupZip_1.listZipInstructionFiles)(full).length;
166
+ }
167
+ results.push({ id, createdAt, instructionCount, schemaVersion, sizeBytes: stat.size });
168
+ }
169
+ else if (stat.isDirectory()) {
170
+ // Legacy directory backup
171
+ const manifestPath = path_1.default.join(full, 'manifest.json');
172
+ let createdAt = new Date(stat.mtime).toISOString();
173
+ let instructionCount = 0;
174
+ let schemaVersion;
175
+ if (fs_1.default.existsSync(manifestPath)) {
176
+ try {
177
+ const mf = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf-8'));
178
+ createdAt = mf.createdAt || createdAt;
179
+ instructionCount = mf.instructionCount || 0;
180
+ schemaVersion = mf.schemaVersion;
181
+ }
182
+ catch { /* ignore */ }
183
+ }
184
+ else {
185
+ instructionCount = fs_1.default.readdirSync(full).filter(f => f.toLowerCase().endsWith('.json')).length;
186
+ }
187
+ const sizeBytes = fs_1.default.readdirSync(full).reduce((sum, f) => {
188
+ try {
189
+ return sum + fs_1.default.statSync(path_1.default.join(full, f)).size;
190
+ }
191
+ catch {
192
+ return sum;
193
+ }
194
+ }, 0);
195
+ results.push({ id: entry, createdAt, instructionCount, schemaVersion, sizeBytes });
196
+ }
197
+ }
198
+ catch { /* ignore individual entry errors */ }
199
+ }
200
+ results.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
201
+ return results;
202
+ }
203
+ restoreBackup(backupId) {
204
+ try {
205
+ if (!backupId)
206
+ return { success: false, message: 'backupId required' };
207
+ const backupRoot = this.backupRoot;
208
+ const zipPath = path_1.default.join(backupRoot, `${backupId}.zip`);
209
+ const backupDir = path_1.default.join(backupRoot, backupId);
210
+ const isZip = fs_1.default.existsSync(zipPath);
211
+ const isDir = fs_1.default.existsSync(backupDir) && fs_1.default.statSync(backupDir).isDirectory();
212
+ if (!isZip && !isDir)
213
+ return { success: false, message: `Backup not found: ${backupId}` };
214
+ const instructionsDir = this.instructionsRoot;
215
+ if (!fs_1.default.existsSync(instructionsDir))
216
+ fs_1.default.mkdirSync(instructionsDir, { recursive: true });
217
+ // Pre-restore safety backup (as zip)
218
+ const existing = fs_1.default.readdirSync(instructionsDir).filter(f => f.toLowerCase().endsWith('.json'));
219
+ if (existing.length) {
220
+ const safetyId = `pre_restore_${Date.now()}`;
221
+ const safetyZipPath = path_1.default.join(backupRoot, `${safetyId}.zip`);
222
+ (0, backupZip_1.createZipBackupWithManifest)(instructionsDir, safetyZipPath, {
223
+ type: 'pre-restore',
224
+ createdAt: new Date().toISOString(),
225
+ source: backupId,
226
+ originalCount: existing.length,
227
+ });
228
+ process.stderr.write(`[admin] Pre-restore safety backup created: ${safetyId}.zip\n`);
229
+ }
230
+ let restored = 0;
231
+ if (isZip) {
232
+ restored = (0, backupZip_1.extractZipBackup)(zipPath, instructionsDir);
233
+ // Don't count manifest.json as a restored instruction
234
+ }
235
+ else {
236
+ // Legacy directory restore
237
+ for (const f of fs_1.default.readdirSync(backupDir)) {
238
+ if (f.toLowerCase().endsWith('.json') && f !== 'manifest.json') {
239
+ fs_1.default.copyFileSync(path_1.default.join(backupDir, f), path_1.default.join(instructionsDir, f));
240
+ restored++;
241
+ }
242
+ }
243
+ }
244
+ this.indexStatsCache = null;
245
+ process.stderr.write(`[admin] Restored backup ${backupId} (${restored} instruction files)\n`);
246
+ return { success: true, message: `Backup ${backupId} restored`, restored };
247
+ }
248
+ catch (error) {
249
+ return { success: false, message: `Restore failed: ${error instanceof Error ? error.message : String(error)}` };
250
+ }
251
+ }
252
+ /** Delete a backup zip or directory (safety checks on name) */
253
+ deleteBackup(backupId) {
254
+ try {
255
+ if (!backupId)
256
+ return { success: false, message: 'backupId required' };
257
+ const backupRoot = this.backupRoot;
258
+ // Check for zip first, then legacy directory
259
+ const zipPath = path_1.default.join(backupRoot, `${backupId}.zip`);
260
+ const dirPath = path_1.default.join(backupRoot, backupId);
261
+ const hasZip = fs_1.default.existsSync(zipPath);
262
+ const hasDir = fs_1.default.existsSync(dirPath) && fs_1.default.statSync(dirPath).isDirectory();
263
+ if (!hasZip && !hasDir)
264
+ return { success: false, message: `Backup not found: ${backupId}` };
265
+ if (!/^backup_|^instructions-|^pre_restore_|^auto-backup-/.test(backupId)) {
266
+ return { success: false, message: 'Refusing to delete unexpected backup name' };
267
+ }
268
+ if (hasZip)
269
+ fs_1.default.unlinkSync(zipPath);
270
+ if (hasDir)
271
+ fs_1.default.rmSync(dirPath, { recursive: true, force: true });
272
+ process.stderr.write(`[admin] Deleted backup ${backupId}\n`);
273
+ return { success: true, message: `Backup ${backupId} deleted`, removed: true };
274
+ }
275
+ catch (error) {
276
+ return { success: false, message: `Delete failed: ${error instanceof Error ? error.message : String(error)}` };
277
+ }
278
+ }
279
+ /** Prune backups keeping newest N (by createdAt / mtime). Returns count pruned. */
280
+ pruneBackups(retain) {
281
+ try {
282
+ if (retain < 0)
283
+ return { success: false, message: 'retain must be >= 0' };
284
+ const backupRoot = this.backupRoot;
285
+ if (!fs_1.default.existsSync(backupRoot))
286
+ return { success: true, message: 'No backups to prune', pruned: 0 };
287
+ const entries = fs_1.default.readdirSync(backupRoot)
288
+ .map(name => {
289
+ const full = path_1.default.join(backupRoot, name);
290
+ // Derive the logical ID (strip .zip extension)
291
+ const id = name.endsWith('.zip') ? name.replace(/\.zip$/i, '') : name;
292
+ return { name, id, full };
293
+ })
294
+ .filter(d => {
295
+ try {
296
+ const stat = fs_1.default.statSync(d.full);
297
+ if (d.name.endsWith('.zip') && stat.isFile())
298
+ return /^backup_|^instructions-|^pre_restore_|^auto-backup-/.test(d.id);
299
+ if (stat.isDirectory())
300
+ return /^backup_|^instructions-|^pre_restore_|^auto-backup-/.test(d.id);
301
+ return false;
302
+ }
303
+ catch {
304
+ return false;
305
+ }
306
+ });
307
+ // sort newest first by mtime
308
+ entries.sort((a, b) => {
309
+ try {
310
+ return fs_1.default.statSync(b.full).mtime.getTime() - fs_1.default.statSync(a.full).mtime.getTime();
311
+ }
312
+ catch {
313
+ return 0;
314
+ }
315
+ });
316
+ if (retain === 0) {
317
+ let prunedAll = 0;
318
+ for (const d of entries) {
319
+ try {
320
+ if (d.name.endsWith('.zip'))
321
+ fs_1.default.unlinkSync(d.full);
322
+ else
323
+ fs_1.default.rmSync(d.full, { recursive: true, force: true });
324
+ prunedAll++;
325
+ }
326
+ catch { /* ignore */ }
327
+ }
328
+ process.stderr.write(`[admin] Pruned all backups (${prunedAll})\n`);
329
+ return { success: true, message: `Pruned ${prunedAll} backups`, pruned: prunedAll };
330
+ }
331
+ const toDelete = entries.slice(retain);
332
+ let pruned = 0;
333
+ for (const d of toDelete) {
334
+ try {
335
+ if (d.name.endsWith('.zip'))
336
+ fs_1.default.unlinkSync(d.full);
337
+ else
338
+ fs_1.default.rmSync(d.full, { recursive: true, force: true });
339
+ pruned++;
340
+ }
341
+ catch { /* ignore */ }
342
+ }
343
+ process.stderr.write(`[admin] Pruned ${pruned} backup(s); retained ${entries.length - pruned}\n`);
344
+ return { success: true, message: `Pruned ${pruned} backups (retained ${entries.length - pruned})`, pruned };
345
+ }
346
+ catch (error) {
347
+ return { success: false, message: `Prune failed: ${error instanceof Error ? error.message : String(error)}` };
348
+ }
349
+ }
350
+ /** Export a backup — returns the zip file path for streaming, or falls back to JSON bundle for legacy dirs */
351
+ exportBackup(backupId) {
352
+ try {
353
+ if (!backupId)
354
+ return { success: false, message: 'backupId required' };
355
+ const zipPath = path_1.default.join(this.backupRoot, `${backupId}.zip`);
356
+ if (fs_1.default.existsSync(zipPath) && fs_1.default.statSync(zipPath).isFile()) {
357
+ return { success: true, message: 'Export ready', zipPath };
358
+ }
359
+ // Legacy directory fallback
360
+ const backupDir = path_1.default.join(this.backupRoot, backupId);
361
+ if (!fs_1.default.existsSync(backupDir) || !fs_1.default.statSync(backupDir).isDirectory())
362
+ return { success: false, message: `Backup not found: ${backupId}` };
363
+ let manifest = {};
364
+ const manifestPath = path_1.default.join(backupDir, 'manifest.json');
365
+ if (fs_1.default.existsSync(manifestPath)) {
366
+ try {
367
+ manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf-8'));
368
+ }
369
+ catch { /* ignore */ }
370
+ }
371
+ const files = {};
372
+ for (const f of fs_1.default.readdirSync(backupDir)) {
373
+ if (f.toLowerCase().endsWith('.json') && f !== 'manifest.json') {
374
+ try {
375
+ files[f] = JSON.parse(fs_1.default.readFileSync(path_1.default.join(backupDir, f), 'utf-8'));
376
+ }
377
+ catch { /* skip corrupt */ }
378
+ }
379
+ }
380
+ return { success: true, message: 'Export ready', bundle: { manifest, files } };
381
+ }
382
+ catch (error) {
383
+ return { success: false, message: `Export failed: ${error instanceof Error ? error.message : String(error)}` };
384
+ }
385
+ }
386
+ /** Import a backup from a JSON bundle uploaded by the client — creates a zip */
387
+ importBackup(bundle) {
388
+ try {
389
+ if (!bundle || typeof bundle !== 'object' || !bundle.files || typeof bundle.files !== 'object') {
390
+ return { success: false, message: 'Invalid bundle: must contain a "files" object' };
391
+ }
392
+ const now = new Date();
393
+ const baseTs = now.toISOString().replace(/[-:]/g, '').replace(/\..+/, '');
394
+ const ms = String(now.getMilliseconds()).padStart(3, '0');
395
+ const backupId = `backup_${baseTs}_${ms}`;
396
+ const zipPath = path_1.default.join(this.backupRoot, `${backupId}.zip`);
397
+ if (!fs_1.default.existsSync(this.backupRoot))
398
+ fs_1.default.mkdirSync(this.backupRoot, { recursive: true });
399
+ const zip = new adm_zip_1.default();
400
+ let written = 0;
401
+ for (const [name, content] of Object.entries(bundle.files)) {
402
+ if (typeof name !== 'string' || !name.toLowerCase().endsWith('.json'))
403
+ continue;
404
+ const safeName = path_1.default.basename(name);
405
+ if (safeName !== name || safeName.includes('..'))
406
+ continue; // path traversal guard
407
+ zip.addFile(safeName, Buffer.from(JSON.stringify(content, null, 2)));
408
+ written++;
409
+ }
410
+ const manifest = {
411
+ backupId,
412
+ createdAt: now.toISOString(),
413
+ instructionCount: written,
414
+ schemaVersion: bundle.manifest?.schemaVersion || 'imported',
415
+ source: 'file-import',
416
+ };
417
+ zip.addFile('manifest.json', Buffer.from(JSON.stringify(manifest, null, 2)));
418
+ zip.writeZip(zipPath);
419
+ process.stderr.write(`[admin] Imported backup from file: ${backupId}.zip (${written} files)\n`);
420
+ return { success: true, message: `Imported ${written} files as ${backupId}`, backupId, files: written };
421
+ }
422
+ catch (error) {
423
+ return { success: false, message: `Import failed: ${error instanceof Error ? error.message : String(error)}` };
424
+ }
425
+ }
426
+ /**
427
+ * Calculate current CPU usage with historical tracking
428
+ */
429
+ calculateCpuUsage() {
430
+ const currentCpuUsage = process.cpuUsage();
431
+ let cpuPercent = 0;
432
+ let userTime = 0;
433
+ let systemTime = 0;
434
+ if (this.lastCpuUsage) {
435
+ // Calculate delta since last measurement
436
+ const userDelta = currentCpuUsage.user - this.lastCpuUsage.user;
437
+ const systemDelta = currentCpuUsage.system - this.lastCpuUsage.system;
438
+ const totalDelta = userDelta + systemDelta;
439
+ // Convert microseconds to percentage (assuming 1 second interval)
440
+ // For more accurate results, you'd want to track the actual time interval
441
+ cpuPercent = Math.min((totalDelta / 1000000) * 100, 100);
442
+ userTime = userDelta / 1000000; // Convert to seconds
443
+ systemTime = systemDelta / 1000000; // Convert to seconds
444
+ }
445
+ this.lastCpuUsage = currentCpuUsage;
446
+ // Add to history for leak detection
447
+ const historyEntry = {
448
+ timestamp: Date.now(),
449
+ user: userTime,
450
+ system: systemTime,
451
+ percent: cpuPercent
452
+ };
453
+ this.cpuHistory.push(historyEntry);
454
+ // Keep only recent entries
455
+ if (this.cpuHistory.length > this.maxCpuHistoryEntries) {
456
+ this.cpuHistory.shift();
457
+ }
458
+ return {
459
+ user: userTime,
460
+ system: systemTime,
461
+ percent: cpuPercent
462
+ };
463
+ }
464
+ /**
465
+ * Analyze CPU trends for potential leaks
466
+ */
467
+ analyzeCpuTrends() {
468
+ if (this.cpuHistory.length < 10) {
469
+ return { trend: 'stable', avgUsage: 0, peakUsage: 0 };
470
+ }
471
+ const recent = this.cpuHistory.slice(-10);
472
+ const avgUsage = recent.reduce((sum, entry) => sum + entry.percent, 0) / recent.length;
473
+ const peakUsage = Math.max(...recent.map(entry => entry.percent));
474
+ // Simple trend analysis - compare first half vs second half
475
+ const firstHalf = recent.slice(0, 5);
476
+ const secondHalf = recent.slice(5);
477
+ const firstAvg = firstHalf.reduce((sum, entry) => sum + entry.percent, 0) / firstHalf.length;
478
+ const secondAvg = secondHalf.reduce((sum, entry) => sum + entry.percent, 0) / secondHalf.length;
479
+ let trend = 'stable';
480
+ const difference = secondAvg - firstAvg;
481
+ if (Math.abs(difference) > 5) {
482
+ trend = difference > 0 ? 'increasing' : 'decreasing';
483
+ }
484
+ return { trend, avgUsage, peakUsage };
485
+ }
486
+ /**
487
+ * Analyze memory usage trends for leak detection
488
+ */
489
+ analyzeMemoryTrends() {
490
+ if (this.memoryHistory.length < 10) {
491
+ return { trend: 'stable', avgHeapUsed: 0, peakHeapUsed: 0, growthRate: 0 };
492
+ }
493
+ const recent = this.memoryHistory.slice(-10);
494
+ const avgHeapUsed = recent.reduce((sum, entry) => sum + entry.heapUsed, 0) / recent.length;
495
+ const peakHeapUsed = Math.max(...recent.map(entry => entry.heapUsed));
496
+ // Calculate growth rate (bytes per minute)
497
+ const firstEntry = recent[0];
498
+ const lastEntry = recent[recent.length - 1];
499
+ const timeDiffMinutes = (lastEntry.timestamp - firstEntry.timestamp) / (1000 * 60);
500
+ const growthRate = timeDiffMinutes > 0 ? (lastEntry.heapUsed - firstEntry.heapUsed) / timeDiffMinutes : 0;
501
+ // Simple trend analysis - compare first half vs second half
502
+ const firstHalf = recent.slice(0, 5);
503
+ const secondHalf = recent.slice(5);
504
+ const firstAvg = firstHalf.reduce((sum, entry) => sum + entry.heapUsed, 0) / firstHalf.length;
505
+ const secondAvg = secondHalf.reduce((sum, entry) => sum + entry.heapUsed, 0) / secondHalf.length;
506
+ let trend = 'stable';
507
+ const difference = secondAvg - firstAvg;
508
+ // Consider memory leak if growth is > 10MB or growth rate > 1MB/min
509
+ if (Math.abs(difference) > 10 * 1024 * 1024 || Math.abs(growthRate) > 1024 * 1024) {
510
+ trend = difference > 0 ? 'increasing' : 'decreasing';
511
+ }
512
+ return { trend, avgHeapUsed, peakHeapUsed, growthRate };
513
+ }
514
+ /**
515
+ * Get comprehensive admin statistics
516
+ */
517
+ getAdminStats() {
518
+ // Use real metrics snapshot (deterministic values)
519
+ const collector = (0, MetricsCollector_1.getMetricsCollector)();
520
+ const snapshot = collector.getCurrentSnapshot();
521
+ // Aggregate total requests from tool metrics
522
+ let totalRequests = 0;
523
+ Object.values(snapshot.tools).forEach(t => { totalRequests += t.callCount; });
524
+ // Get index validation summary for accurate accepted vs raw counts
525
+ let accepted = 0, scanned = 0, skipped = 0;
526
+ try {
527
+ const st = (0, indexContext_1.getIndexState)();
528
+ if (st.loadSummary) {
529
+ accepted = st.loadSummary.accepted;
530
+ scanned = st.loadSummary.scanned;
531
+ skipped = st.loadSummary.skipped;
532
+ }
533
+ else {
534
+ accepted = st.list.length;
535
+ scanned = st.loadDebug?.scanned ?? accepted;
536
+ skipped = Math.max(0, scanned - accepted);
537
+ }
538
+ }
539
+ catch {
540
+ /* ignore */
541
+ }
542
+ // Count physical *.json files (raw) deterministically from FS (may equal scanned; retained for transparency)
543
+ const indexDir = this.instructionsRoot;
544
+ let rawFileCount = scanned; // default to scanned
545
+ try {
546
+ if (fs_1.default.existsSync(indexDir)) {
547
+ rawFileCount = fs_1.default.readdirSync(indexDir).filter(f => f.toLowerCase().endsWith('.json')).length;
548
+ }
549
+ }
550
+ catch { /* ignore */ }
551
+ // Recompute schema version snapshot only when any of these counts change
552
+ const cacheNeedsUpdate = !this.indexStatsCache || this.indexStatsCache.acceptedInstructions !== accepted || this.indexStatsCache.rawFileCount !== rawFileCount || this.indexStatsCache.skippedInstructions !== skipped;
553
+ if (cacheNeedsUpdate) {
554
+ const schemaVersions = new Set();
555
+ try {
556
+ if (fs_1.default.existsSync(indexDir)) {
557
+ const files = fs_1.default.readdirSync(indexDir).filter(f => f.toLowerCase().endsWith('.json')).slice(0, 200); // cap scan
558
+ for (const f of files) {
559
+ try {
560
+ const raw = fs_1.default.readFileSync(path_1.default.join(indexDir, f), 'utf-8');
561
+ const json = JSON.parse(raw);
562
+ if (typeof json.schemaVersion === 'string')
563
+ schemaVersions.add(json.schemaVersion);
564
+ }
565
+ catch { /* ignore parse */ }
566
+ }
567
+ }
568
+ }
569
+ catch { /* ignore */ }
570
+ const schemaVersion = schemaVersions.size === 0 ? 'unknown' : (schemaVersions.size === 1 ? Array.from(schemaVersions)[0] : `mixed(${Array.from(schemaVersions).join(',')})`);
571
+ this.indexStatsCache = {
572
+ totalInstructions: accepted, // maintain backward compatibility; semantic now accepted
573
+ acceptedInstructions: accepted,
574
+ rawFileCount,
575
+ skippedInstructions: skipped,
576
+ lastUpdated: new Date(),
577
+ version: snapshot.server.version,
578
+ schemaVersion
579
+ };
580
+ }
581
+ const memUsage = snapshot.server.memoryUsage; // already captured in snapshot
582
+ const cpuUsage = this.calculateCpuUsage(); // Calculate current CPU usage
583
+ // Ensure cache populated (should be by logic above, but safeguard for strict types)
584
+ if (!this.indexStatsCache) {
585
+ this.indexStatsCache = {
586
+ totalInstructions: accepted,
587
+ acceptedInstructions: accepted,
588
+ rawFileCount,
589
+ skippedInstructions: skipped,
590
+ lastUpdated: new Date(),
591
+ version: snapshot.server.version,
592
+ schemaVersion: 'unknown'
593
+ };
594
+ }
595
+ return {
596
+ // Total historical websocket connections (connected + disconnected)
597
+ totalConnections: snapshot.connections.totalConnections,
598
+ // Active websocket connections (live WS clients). Previously this returned only admin sessions size,
599
+ // which caused the UI to show 0 even when multiple WS clients were connected. This now reflects
600
+ // real-time active websocket connections from metrics.
601
+ activeConnections: snapshot.connections.activeConnections,
602
+ // Preserve visibility into admin (logical) sessions separately.
603
+ adminActiveSessions: this.panelState.activeSessions.size,
604
+ totalRequests,
605
+ errorRate: snapshot.performance.errorRate,
606
+ avgResponseTime: snapshot.performance.avgResponseTime,
607
+ uptime: Math.floor(snapshot.server.uptime / 1000), // seconds
608
+ memoryUsage: {
609
+ heapUsed: memUsage.heapUsed,
610
+ heapTotal: memUsage.heapTotal,
611
+ external: memUsage?.external ?? 0,
612
+ ...(memUsage?.heapLimit ? { heapLimit: memUsage.heapLimit } : {})
613
+ },
614
+ cpuUsage,
615
+ toolMetrics: snapshot.tools,
616
+ indexStats: this.indexStatsCache
617
+ };
618
+ }
619
+ updateSystemHealth() {
620
+ const issues = [];
621
+ const recommendations = [];
622
+ // Check memory usage and track history
623
+ const memUsage = process.memoryUsage();
624
+ // Use V8 heap_size_limit for percentage -- heapTotal tracks closely
625
+ // behind heapUsed and would false-alarm at low absolute usage.
626
+ const v8Stats = v8_1.default.getHeapStatistics();
627
+ const heapLimit = v8Stats.heap_size_limit || memUsage.heapTotal;
628
+ const memPercent = (memUsage.heapUsed / heapLimit) * 100;
629
+ // Track memory history for leak detection
630
+ this.memoryHistory.push({
631
+ timestamp: Date.now(),
632
+ heapUsed: memUsage.heapUsed,
633
+ heapTotal: memUsage.heapTotal,
634
+ external: memUsage.external,
635
+ rss: memUsage.rss
636
+ });
637
+ // Maintain memory history buffer
638
+ if (this.memoryHistory.length > this.maxMemoryHistoryEntries) {
639
+ this.memoryHistory.shift();
640
+ }
641
+ if (memPercent > 80) {
642
+ issues.push('High memory usage detected');
643
+ recommendations.push('Consider restarting the server or increasing memory limits');
644
+ }
645
+ // Check memory trends for leak detection
646
+ const memoryTrends = this.analyzeMemoryTrends();
647
+ if (memoryTrends.trend === 'increasing' && memoryTrends.growthRate > 1024 * 1024) {
648
+ issues.push('Memory leak detected - heap growing consistently');
649
+ recommendations.push('Investigate memory usage patterns and potential leaks');
650
+ }
651
+ if (memoryTrends.growthRate > 5 * 1024 * 1024) { // > 5MB/min growth
652
+ issues.push('Rapid memory growth detected');
653
+ recommendations.push('Monitor memory usage closely and consider restart if growth continues');
654
+ }
655
+ // Check CPU usage and trends
656
+ const cpuTrends = this.analyzeCpuTrends();
657
+ if (cpuTrends.avgUsage > 80) {
658
+ issues.push('High CPU usage detected');
659
+ recommendations.push('Review server load and consider scaling');
660
+ }
661
+ if (cpuTrends.trend === 'increasing' && cpuTrends.avgUsage > 50) {
662
+ issues.push('CPU usage trend increasing');
663
+ recommendations.push('Monitor for potential CPU leaks or resource contention');
664
+ }
665
+ if (cpuTrends.peakUsage > 95) {
666
+ issues.push('CPU usage spikes detected');
667
+ recommendations.push('Investigate CPU-intensive operations');
668
+ }
669
+ // Check uptime (regression & long-running)
670
+ const currentUptimeSeconds = Math.floor(process.uptime());
671
+ const uptimeHours = currentUptimeSeconds / 3600;
672
+ if (this.lastUptimeSeconds > 0 && currentUptimeSeconds < this.lastUptimeSeconds) {
673
+ // Uptime decreased => restart/regression
674
+ issues.push('Uptime regression detected (server restart)');
675
+ recommendations.push('Review restart reason and ensure intentional');
676
+ }
677
+ else if (uptimeHours > 72) {
678
+ recommendations.push('Consider scheduled restart for optimal performance');
679
+ }
680
+ this.lastUptimeSeconds = currentUptimeSeconds;
681
+ // Check error rate
682
+ const errorRate = this.getErrorRate();
683
+ if (errorRate > 5) {
684
+ issues.push('Elevated error rate detected');
685
+ recommendations.push('Review error logs and investigate root causes');
686
+ }
687
+ // Determine overall health status
688
+ let status = 'healthy';
689
+ if (issues.length > 0) {
690
+ status = (memPercent > 90 || errorRate > 10 || cpuTrends.avgUsage > 90 || memoryTrends.growthRate > 10 * 1024 * 1024) ? 'critical' : 'warning';
691
+ }
692
+ this.maintenanceInfo.systemHealth = {
693
+ status,
694
+ issues,
695
+ recommendations,
696
+ cpuTrend: cpuTrends.trend,
697
+ memoryTrend: memoryTrends.trend,
698
+ memoryGrowthRate: memoryTrends.growthRate
699
+ };
700
+ }
701
+ /** Return immutable copy of session history */
702
+ getSessionHistory(limit) {
703
+ return this.panelState.getSessionHistory(limit);
704
+ }
705
+ async clearSessionHistory() {
706
+ return this.panelState.clearSessionHistory();
707
+ }
708
+ updateSessionActivity(sessionId) {
709
+ return this.panelState.updateSessionActivity(sessionId);
710
+ }
711
+ getTotalConnections() {
712
+ return (0, MetricsCollector_1.getMetricsCollector)().getCurrentSnapshot().connections.totalConnections;
713
+ }
714
+ getTotalRequests() {
715
+ const snap = (0, MetricsCollector_1.getMetricsCollector)().getCurrentSnapshot();
716
+ return Object.values(snap.tools).reduce((sum, t) => sum + t.callCount, 0);
717
+ }
718
+ getErrorRate() {
719
+ return (0, MetricsCollector_1.getMetricsCollector)().getCurrentSnapshot().performance.errorRate;
720
+ }
721
+ getAvgResponseTime() {
722
+ return (0, MetricsCollector_1.getMetricsCollector)().getCurrentSnapshot().performance.avgResponseTime;
723
+ }
724
+ getIndexInstructionCount() {
725
+ const indexDir = this.instructionsRoot;
726
+ try {
727
+ if (fs_1.default.existsSync(indexDir)) {
728
+ return fs_1.default.readdirSync(indexDir).filter(f => f.toLowerCase().endsWith('.json')).length;
729
+ }
730
+ }
731
+ catch {
732
+ // ignore
733
+ }
734
+ return 0;
735
+ }
736
+ /**
737
+ * Restart server components
738
+ */
739
+ async restartServer(component = 'all') {
740
+ try {
741
+ process.stderr.write(`[admin] Restart requested for component: ${component}\n`);
742
+ // In real implementation, this would perform actual component restarts
743
+ await new Promise(resolve => setTimeout(resolve, 2000));
744
+ return {
745
+ success: true,
746
+ message: `${component} restart completed successfully`
747
+ };
748
+ }
749
+ catch (error) {
750
+ return {
751
+ success: false,
752
+ message: `Restart failed: ${error instanceof Error ? error.message : String(error)}`
753
+ };
754
+ }
755
+ }
756
+ /**
757
+ * Clear server caches
758
+ */
759
+ clearCaches() {
760
+ try {
761
+ const cleared = [];
762
+ // Clear instruction cache
763
+ cleared.push('instruction_cache');
764
+ // Clear metrics cache
765
+ cleared.push('metrics_cache');
766
+ // Clear response cache
767
+ cleared.push('response_cache');
768
+ process.stderr.write(`[admin] Caches cleared: ${cleared.join(', ')}\n`);
769
+ return {
770
+ success: true,
771
+ message: 'All caches cleared successfully',
772
+ cleared
773
+ };
774
+ }
775
+ catch (error) {
776
+ return {
777
+ success: false,
778
+ message: `Failed to clear caches: ${error instanceof Error ? error.message : String(error)}`,
779
+ cleared: []
780
+ };
781
+ }
782
+ }
783
+ }
784
+ exports.AdminPanel = AdminPanel;
785
+ // Singleton instance
786
+ let adminPanelInstance = null;
787
+ function getAdminPanel() {
788
+ if (!adminPanelInstance) {
789
+ adminPanelInstance = new AdminPanel();
790
+ }
791
+ return adminPanelInstance;
792
+ }