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