@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,583 @@
1
+ /* eslint-disable */
2
+ // Extracted graph/mermaid logic from admin.html
3
+ (function(){
4
+ // State
5
+ window.graphOriginalSource = '';
6
+ let graphEditing = false;
7
+
8
+ let __graphReloadInFlight = false;
9
+ let __graphReloadAttempt = 0;
10
+ let __graphReloadWatchdog = null;
11
+ function setGraphMetaProgress(stage, extra){
12
+ try {
13
+ const meta = document.getElementById('graph-meta2') || document.getElementById('graph-meta');
14
+ if(meta){
15
+ const ts = Date.now()%100000;
16
+ const base = meta.textContent || '';
17
+ const marker = `[stage:${stage}${extra?';'+extra:''};t=${ts}]`;
18
+ if(!/\[stage:/.test(base)) meta.textContent = base + ' ' + marker; else meta.textContent = base.replace(/\[stage:[^\]]+\]/, marker);
19
+ }
20
+ } catch{}
21
+ }
22
+
23
+ async function reloadGraphMermaid(){
24
+ if(__graphReloadInFlight){ setGraphMetaProgress('skip-concurrent'); return; }
25
+ __graphReloadInFlight = true; __graphReloadAttempt++;
26
+ const attemptId = __graphReloadAttempt;
27
+ clearTimeout(__graphReloadWatchdog);
28
+ __graphReloadWatchdog = setTimeout(()=>{
29
+ setGraphMetaProgress('watchdog-expired','a='+attemptId);
30
+ __graphReloadInFlight = false;
31
+ }, 15000);
32
+ setGraphMetaProgress('start','a='+attemptId);
33
+ const enrichEl = document.getElementById('graph-enrich');
34
+ const categoriesEl = document.getElementById('graph-categories');
35
+ const usageEl = document.getElementById('graph-usage');
36
+ const edgeTypesEl = document.getElementById('graph-edgeTypes');
37
+ const layoutSel = document.getElementById('graph-layout');
38
+ // Default enrich & categories to true if element not yet bound so initial meta shows enriched schema
39
+ const enrich = enrichEl && 'checked' in enrichEl ? enrichEl.checked : true;
40
+ const categories = categoriesEl && 'checked' in categoriesEl ? categoriesEl.checked : true;
41
+ const usage = usageEl && 'checked' in usageEl ? usageEl.checked : false;
42
+ const edgeTypesRaw = edgeTypesEl && 'value' in edgeTypesEl ? (edgeTypesEl.value || '').trim() : '';
43
+ let layout = (layoutSel && 'value' in layoutSel) ? layoutSel.value : 'elk';
44
+ const theme = 'base'; // fixed project-standard theme
45
+ const params = new URLSearchParams();
46
+ const selCatsEl = document.getElementById('drill-categories');
47
+ const selInstEl = document.getElementById('drill-instructions');
48
+ const selectedCategories = selCatsEl ? Array.from(selCatsEl.selectedOptions).map(o=>o.value).filter(Boolean) : [];
49
+ const selectedIds = selInstEl ? Array.from(selInstEl.selectedOptions).map(o=>o.value).filter(Boolean) : [];
50
+ const scopeFiltered = selectedCategories.length > 0 || selectedIds.length > 0;
51
+ // Always include toggle flags irrespective of scope filtering so meta (schema version, categories)
52
+ // remains accurate and tests expecting enrichment signals succeed.
53
+ if(enrich) params.set('enrich','1');
54
+ if(categories) params.set('categories','1');
55
+ if(usage) params.set('usage','1');
56
+ if(edgeTypesRaw) params.set('edgeTypes', edgeTypesRaw);
57
+ if(selectedCategories.length) params.set('selectedCategories', selectedCategories.join(','));
58
+ if(selectedIds.length) params.set('selectedIds', selectedIds.join(','));
59
+ const target = document.getElementById('graph-mermaid');
60
+ const metaEl = document.getElementById('graph-meta');
61
+ const metaEl2 = document.getElementById('graph-meta2');
62
+ if(target) target.textContent = '(loading graph...)';
63
+ const skeleton = document.querySelector('.graph-loading-skeleton');
64
+ if(skeleton) skeleton.style.display = '';
65
+ const manualOverride = window.__GRAPH_MANUAL_OVERRIDE === true;
66
+ const persistedOverride = !manualOverride ? null : (function(){
67
+ try { return localStorage.getItem('mcp.graph.manualOverrideSource') || null; } catch { return null; }
68
+ })();
69
+ setGraphMetaProgress('params', 'en='+(enrich?1:0)+';cat='+(categories?1:0)+';use='+(usage?1:0)+';selCats='+selectedCategories.length+';selIds='+selectedIds.length);
70
+ let fetchOk = false; let data = null; let lastErr = null;
71
+ try {
72
+ setGraphMetaProgress('fetch','a='+attemptId);
73
+ const res = await fetch('/api/graph/mermaid?'+params.toString());
74
+ if(!res.ok) throw new Error('http '+res.status);
75
+ data = await res.json();
76
+ fetchOk = !!(data && data.success && data.mermaid);
77
+ setGraphMetaProgress(fetchOk? 'fetch-ok':'fetch-empty','a='+attemptId);
78
+ } catch(e){ lastErr = e; setGraphMetaProgress('fetch-error','a='+attemptId); }
79
+ if(!fetchOk && attemptId === 1){
80
+ // Retry once with ultra-minimal params
81
+ try {
82
+ setGraphMetaProgress('retry1');
83
+ const res2 = await fetch('/api/graph/mermaid?enrich=1');
84
+ if(res2.ok){ const d2 = await res2.json(); if(d2?.success && d2.mermaid){ data = d2; fetchOk = true; setGraphMetaProgress('retry-ok'); }}
85
+ } catch{ setGraphMetaProgress('retry-fail'); }
86
+ }
87
+ if(fetchOk){
88
+ try {
89
+ let mermaidSource = data.mermaid;
90
+ setGraphMetaProgress('fetched-bytes','len='+ (mermaidSource? mermaidSource.length:0));
91
+ const effectiveLayout = layout === 'elk' ? 'elk' : 'default';
92
+ if(effectiveLayout === 'elk') await ensureMermaidElk();
93
+ // Merge or create frontmatter ensuring single config.theme + config.layout entries
94
+ function mergeFrontmatter(src){
95
+ if(!src) return src;
96
+ const wantThemeLine = theme ? ` theme: ${theme}` : null;
97
+ const wantLayoutLine = (effectiveLayout === 'elk') ? ' layout: elk' : null;
98
+ const wantThemeVariables = ` themeVariables:\n primaryColor: '#3b82f6'\n primaryTextColor: '#d0d4d8'\n primaryBorderColor: '#2c3038'\n lineColor: '#363b44'\n secondaryColor: '#1f2228'\n tertiaryColor: '#181b1f'\n background: '#111217'\n mainBkg: '#181b1f'\n secondBkg: '#1f2228'`;
99
+ const hasFrontmatter = src.startsWith('---\n');
100
+ // If frontmatter missing OR malformed ensure we create a fresh one
101
+ const m = hasFrontmatter ? /^---\n([\s\S]*?)\n---\n([\s\S]*)$/m.exec(src) : null;
102
+ if(!m){
103
+ const lines = ['config:'];
104
+ if(wantThemeLine) lines.push(wantThemeLine);
105
+ if(wantLayoutLine) lines.push(wantLayoutLine);
106
+ lines.push(wantThemeVariables);
107
+ // If there was an orphan leading '---' without closing, strip it first
108
+ const cleaned = hasFrontmatter ? src.replace(/^---\n?/, '') : src;
109
+ return `---\n${lines.join('\n')}\n---\n${cleaned}`;
110
+ }
111
+ // Split existing frontmatter header & body (valid pattern)
112
+ let header = m[1];
113
+ const body = m[2];
114
+ // Ensure config: section exists
115
+ if(!/^config:/m.test(header)){
116
+ header = 'config:\n'+header;
117
+ }
118
+ // Remove existing simple theme/layout lines; keep a single themeVariables block (first occurrence)
119
+ const lines = header.split(/\r?\n/);
120
+ let seenThemeVars = false;
121
+ const filtered = [];
122
+ for(let i=0;i<lines.length;i++){
123
+ const l = lines[i];
124
+ if(/(^\s*theme:\s)/.test(l) || /(^\s*layout:\s)/.test(l)) continue;
125
+ if(/^\s*themeVariables:/.test(l)){
126
+ if(seenThemeVars){ continue; }
127
+ seenThemeVars = true;
128
+ filtered.push(l);
129
+ // retain following indented lines belonging to existing themeVariables block
130
+ for(let j=i+1;j<lines.length;j++){
131
+ const nl = lines[j];
132
+ if(/^\s{2,}\S/.test(nl)) { filtered.push(nl); i=j; continue; }
133
+ break;
134
+ }
135
+ continue;
136
+ }
137
+ filtered.push(l);
138
+ }
139
+ // Rebuild and inject desired lines after config:
140
+ const rebuilt = filtered;
141
+ let cfgIdx = rebuilt.findIndex(l=>/^config:/.test(l));
142
+ if(cfgIdx === -1){ rebuilt.unshift('config:'); cfgIdx = 0; }
143
+ const inject = [];
144
+ if(wantThemeLine) inject.push(wantThemeLine);
145
+ if(wantLayoutLine) inject.push(wantLayoutLine);
146
+ if(!seenThemeVars) inject.push(wantThemeVariables);
147
+ rebuilt.splice(cfgIdx+1,0,...inject);
148
+ return `---\n${rebuilt.join('\n')}\n---\n${body}`;
149
+ }
150
+ mermaidSource = mergeFrontmatter(mermaidSource);
151
+ // Sanitize duplicated YAML mapping keys in frontmatter (e.g., accidental repeated darkMode)
152
+ function sanitizeFrontmatter(src){
153
+ if(!src || src.indexOf('---') !== 0) return src;
154
+ try {
155
+ const segMatch = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/m.exec(src);
156
+ if(!segMatch) return src; // not standard frontmatter pattern
157
+ const header = segMatch[1];
158
+ const body = segMatch[2];
159
+ const lines = header.split(/\r?\n/);
160
+ const seenAtIndent = {}; // key -> indent level signature
161
+ const out = [];
162
+ for(const line of lines){
163
+ // Match YAML simple key: value OR key: (end) respecting indentation
164
+ const m = /^(\s*)([A-Za-z0-9_-]+):/.exec(line);
165
+ if(m){
166
+ const indent = m[1].length;
167
+ const key = m[2];
168
+ const sig = indent+':'+key;
169
+ if(seenAtIndent[sig]){
170
+ // Skip duplicate at same nesting level
171
+ continue;
172
+ }
173
+ seenAtIndent[sig] = true;
174
+ }
175
+ out.push(line);
176
+ }
177
+ return `---\n${out.join('\n')}\n---\n${body}`;
178
+ } catch{ return src; }
179
+ }
180
+ let ensured = ensureMermaidDirective(mermaidSource);
181
+ ensured = sanitizeFrontmatter(ensured);
182
+ // If manual override is active, sanitize it too so duplicate keys (e.g. darkMode) don't break parse
183
+ let sanitizedOverride = null;
184
+ if(manualOverride && persistedOverride){
185
+ sanitizedOverride = sanitizeFrontmatter(persistedOverride);
186
+ setGraphMetaProgress('manual-override');
187
+ window.graphOriginalSource = sanitizedOverride;
188
+ if(target) target.textContent = sanitizedOverride;
189
+ } else {
190
+ window.graphOriginalSource = ensured;
191
+ if(target) target.textContent = ensured;
192
+ }
193
+ // Include scope filtering indicator so user sees when selection scoping applied
194
+ if(metaEl){
195
+ const scopeNote = scopeFiltered ? ' (scoped)' : '';
196
+ metaEl.textContent = `schema=v${data.meta?.graphSchemaVersion} nodes=${data.meta?.nodeCount} edges=${data.meta?.edgeCount}${scopeNote}`;
197
+ }
198
+ setGraphMetaProgress('render-prep','a='+attemptId);
199
+ try { await ensureMermaid(); } catch{}
200
+ try { if(effectiveLayout === 'elk' && !window.mermaid?.mcpElkRegistered) await ensureMermaidElk(); } catch{}
201
+ if(window.mermaid){
202
+ setGraphMetaProgress('render-run','a='+attemptId);
203
+ try {
204
+ const renderSource = (manualOverride && sanitizedOverride) ? sanitizedOverride : ensured;
205
+ // Lightweight syntax validation before attempting full render (helps surface parse errors explicitly)
206
+ try {
207
+ if(window.mermaid.parse){
208
+ await window.mermaid.parse(renderSource);
209
+ }
210
+ } catch(parseErr){
211
+ setGraphMetaProgress('parse-fail','a='+attemptId);
212
+ const hostParse = document.getElementById('graph-mermaid-svg');
213
+ if(hostParse){
214
+ hostParse.innerHTML = `<div style="color:#f2495c; font-family:monospace; white-space:pre;">Mermaid parse error:: ${(parseErr && parseErr.message) || parseErr}</div>`;
215
+ }
216
+ // Abort further render attempt
217
+ throw parseErr;
218
+ }
219
+ let svg; ({ svg } = await window.mermaid.render('graphMermaidSvg', renderSource));
220
+ const host = document.getElementById('graph-mermaid-svg'); if(host) host.innerHTML = svg;
221
+ const skel = document.querySelector('.graph-loading-skeleton'); if(skel) skel.style.display = 'none';
222
+ setGraphMetaProgress('render-ok','a='+attemptId);
223
+ } catch(rendErr){
224
+ setGraphMetaProgress('render-fail','a='+attemptId);
225
+ const skelFail = document.querySelector('.graph-loading-skeleton'); if(skelFail) skelFail.style.display = 'none';
226
+ const hostErr = document.getElementById('graph-mermaid-svg');
227
+ if(hostErr && !/Mermaid parse error/.test(hostErr.textContent||'')){
228
+ hostErr.innerHTML = `<div style="color:#f2495c; font-family:monospace; white-space:pre;">Mermaid render failed:: ${(rendErr && rendErr.message) || rendErr}</div>`;
229
+ }
230
+ try { console.warn('[mermaid render failed]', rendErr); } catch{}
231
+ }
232
+ }
233
+ } catch(procErr){ setGraphMetaProgress('process-error','a='+attemptId); }
234
+ } else {
235
+ if(target) target.textContent = `(graph unavailable${lastErr?': '+(lastErr.message||lastErr):''})`;
236
+ setGraphMetaProgress('unavailable','err='+(lastErr && (lastErr.message||String(lastErr))||'none'));
237
+ }
238
+ clearTimeout(__graphReloadWatchdog);
239
+ __graphReloadInFlight = false;
240
+ }
241
+
242
+ function ensureMermaidDirective(src){
243
+ if(!src) return 'flowchart TB';
244
+ const hasDirective = /^(---[\s\S]*?---\s*)?(%%.*\n)*\s*(flowchart|graph)\b/m.test(src);
245
+ if(hasDirective) return src;
246
+ if(/^---/.test(src)){
247
+ const parts = src.split(/---\s*\n/);
248
+ if(parts.length>=3){ const rest = parts.slice(2).join('---\n'); return `---\n${parts[1]}---\nflowchart TB\n${rest}`; }
249
+ }
250
+ return 'flowchart TB\n'+src;
251
+ }
252
+
253
+ // Mermaid loader state (copied behavior)
254
+ let mermaidLoading = null;
255
+ let mermaidElkLoading = null;
256
+ const MERMAID_VERSION_TARGET = '11.11.0';
257
+ function mermaidNeedsReload(force){ if(force) return true; if(!window.mermaid) return true; const ver = window.mermaid.version || window.mermaid.mermaidAPI?.getConfig?.()?.version || ''; if(ver.startsWith('10.')) return true; return false; }
258
+ async function ensureMermaid(force){
259
+ if(mermaidNeedsReload(force)){
260
+ if(window.mermaid && (force || !window.mermaid.registerLayoutLoaders)){
261
+ try{ [...document.querySelectorAll('script[src*="mermaid"]')].forEach(s=>s.remove()); } catch{}
262
+ try{ delete window.mermaid; } catch{}
263
+ mermaidLoading = null;
264
+ }
265
+ }
266
+ if(window.mermaid && !force) return;
267
+ if(mermaidLoading) return mermaidLoading;
268
+ mermaidLoading = new Promise((resolve,reject)=>{
269
+ const s = document.createElement('script');
270
+ s.src = '/js/mermaid.min.js';
271
+ s.onload = ()=>{ try { const large = !!window.__MERMAID_LARGE_GRAPH_FLAG; let configuredMaxEdges; if(typeof window.__MERMAID_MAX_EDGES === 'number' && window.__MERMAID_MAX_EDGES>0){ configuredMaxEdges = window.__MERMAID_MAX_EDGES; } else { configuredMaxEdges = large ? 20000 : 3000; } const maxTextSize = large ? 10000000 : 1000000; // Standardize base theme (frontmatter may still override per-graph)
272
+ window.mermaid.initialize({ startOnLoad:false, theme:'base', maxEdges: configuredMaxEdges, maxTextSize }); window.__MERMAID_ACTIVE_MAX_EDGES = configuredMaxEdges; window.__MERMAID_ACTIVE_MAX_TEXT_SIZE = maxTextSize; resolve(null);} catch(e){ reject(e);} };
273
+ s.onerror = (e)=>reject(e instanceof Error? e : new Error('mermaid load failed'));
274
+ document.head.appendChild(s);
275
+ });
276
+ return mermaidLoading;
277
+ }
278
+
279
+ async function ensureMermaidElk(){
280
+ await ensureMermaid();
281
+ if(window.mermaid && !window.mermaid.registerLayoutLoaders && !window.mermaid.__reloadedOnce){ window.mermaid.__reloadedOnce = true; await ensureMermaid(true); }
282
+ if(window.mermaid?.mcpElkRegistered) return;
283
+ if(mermaidElkLoading) return mermaidElkLoading;
284
+ mermaidElkLoading = new Promise((resolve)=>{
285
+ const localElk = './mermaid-layout-elk.esm.min.mjs';
286
+ const urls = [ localElk ];
287
+ let idx = 0;
288
+ function tryNext(){ if(window.mermaid?.mcpElkRegistered) return resolve(null); if(idx >= urls.length) return resolve(null); const url = urls[idx++]; (async ()=>{ try{ const mod = await import(url); let descriptorArray = (mod && mod.default && Array.isArray(mod.default)) ? mod.default : (Array.isArray(mod) ? mod : null); if(!descriptorArray && typeof mod === 'object'){ const arr = Array.isArray(mod.default)? mod.default : null; descriptorArray = arr || null; } if(descriptorArray && window.mermaid?.registerLayoutLoaders){ try{ window.mermaid.registerLayoutLoaders(descriptorArray); window.mermaid.mcpElkRegistered = true; resolve(null); return; } catch(e){ /* try next */ } } } catch(e){ /* try next */ } tryNext(); })(); }
289
+ tryNext();
290
+ });
291
+ return mermaidElkLoading;
292
+ }
293
+
294
+ function initGraphScopeDefaults(){
295
+ const catSel = document.getElementById('drill-categories');
296
+ const instSel = document.getElementById('drill-instructions');
297
+ if(catSel && !catSel.options.length) refreshDrillCategories().catch(()=>{});
298
+ if(instSel && !instSel.options.length) loadDrillInstructions().catch(()=>{});
299
+ const mer = document.getElementById('graph-mermaid'); if(mer) mer.textContent='(no selection - choose categories and/or instructions then Refresh)';
300
+ }
301
+
302
+ function copyMermaidSource(){ const el = document.getElementById('graph-mermaid'); if(!el) return; const txt = el.textContent || ''; navigator.clipboard.writeText(txt).catch(()=>{}); }
303
+
304
+ function toggleGraphEdit(){
305
+ if(graphEditing){
306
+ cancelGraphEdit();
307
+ return;
308
+ }
309
+ const target = document.getElementById('graph-mermaid');
310
+ if(!target) return;
311
+ // Capture current content as restore baseline when entering edit mode
312
+ window.graphOriginalSource = target.textContent || '';
313
+ graphEditing = true;
314
+ target.setAttribute('contenteditable','true');
315
+ target.style.outline = '1px solid #3b82f6';
316
+ window.__GRAPH_MANUAL_OVERRIDE = true; // enable manual override mode
317
+ setGraphMetaProgress('edit-start');
318
+ try { document.getElementById('graph-edit-btn').style.display='none'; } catch{}
319
+ try { document.getElementById('graph-apply-btn').style.display='inline-block'; } catch{}
320
+ try { document.getElementById('graph-cancel-btn').style.display='inline-block'; } catch{}
321
+ }
322
+
323
+ function applyGraphEdit(){
324
+ const target = document.getElementById('graph-mermaid');
325
+ if(!target) return;
326
+ const code = target.textContent || '';
327
+ // Promote edited content to new baseline so subsequent cancel doesn't revert it
328
+ window.graphOriginalSource = code;
329
+ persistGraphSource(code);
330
+ try { localStorage.setItem('mcp.graph.manualOverrideSource', code); } catch{}
331
+ setGraphMetaProgress('apply');
332
+ (async ()=>{
333
+ try {
334
+ await ensureMermaid();
335
+ const { svg } = await window.mermaid.render('graphMermaidSvg', code);
336
+ const legacyHost = document.getElementById('graph-mermaid-svg'); if(legacyHost) legacyHost.innerHTML = svg;
337
+ setGraphMetaProgress('apply-ok');
338
+ } catch(e){
339
+ setGraphMetaProgress('apply-fail');
340
+ try { alert('Render failed: '+ (e && e.message || e)); } catch{}
341
+ }
342
+ })();
343
+ cancelGraphEdit(true); // keep edited content visible
344
+ }
345
+
346
+ function cancelGraphEdit(keep){
347
+ if(!graphEditing) return;
348
+ const target = document.getElementById('graph-mermaid');
349
+ if(target){
350
+ target.removeAttribute('contenteditable');
351
+ target.style.outline='none';
352
+ if(!keep){
353
+ // Restore baseline content
354
+ target.textContent = window.graphOriginalSource;
355
+ }
356
+ }
357
+ graphEditing=false;
358
+ setGraphMetaProgress('edit-end');
359
+ try { document.getElementById('graph-edit-btn').style.display='inline-block'; } catch{}
360
+ try { document.getElementById('graph-apply-btn').style.display='none'; } catch{}
361
+ try { document.getElementById('graph-cancel-btn').style.display='none'; } catch{}
362
+ }
363
+
364
+ // Drilldown helpers (absorbed from admin.drilldown.js)
365
+ async function refreshDrillCategories(){
366
+ const el = document.getElementById('drill-categories');
367
+ if(!el) return;
368
+ try{
369
+ const res = await fetch('/api/graph/categories');
370
+ const data = await res.json();
371
+ el.innerHTML = '';
372
+ if(Array.isArray(data?.categories)){
373
+ data.categories.forEach(c=>{ const o = document.createElement('option'); o.value=c.id||c.name; o.textContent = c.name||c.id; el.appendChild(o); });
374
+ let auto = 0; for(const opt of Array.from(el.options)){ if(auto<3){ opt.selected = true; auto++; } }
375
+ }
376
+ if(typeof window.reloadGraphMermaid === 'function') { try { window.reloadGraphMermaid(); } catch(_){} }
377
+ }catch(e){ console.warn('failed refreshDrillCategories',e); }
378
+ }
379
+
380
+ async function loadDrillInstructions(){
381
+ const el = document.getElementById('drill-instructions');
382
+ if(!el) return;
383
+ try{
384
+ const res = await fetch('/api/graph/instructions');
385
+ const data = await res.json();
386
+ el.innerHTML = '';
387
+ if(Array.isArray(data?.instructions)){
388
+ data.instructions.forEach(i=>{ const o = document.createElement('option'); o.value=i.id; o.textContent = `${i.title||i.id}`; el.appendChild(o); });
389
+ }
390
+ }catch(e){ console.warn('failed loadDrillInstructions',e); }
391
+ }
392
+
393
+ function clearSelections(){
394
+ const catSel = document.getElementById('drill-categories');
395
+ const instSel = document.getElementById('drill-instructions');
396
+ if(catSel) { for(const opt of Array.from(catSel.options)) opt.selected = false; }
397
+ if(instSel) { for(const opt of Array.from(instSel.options)) opt.selected = false; }
398
+ }
399
+
400
+ // Expose
401
+ window.reloadGraphMermaid = reloadGraphMermaid;
402
+ window.reloadGraphMermaidForce = function(){
403
+ try { clearTimeout(__graphReloadWatchdog); } catch{}
404
+ __graphReloadInFlight = false; // clear guard
405
+ reloadGraphMermaid();
406
+ };
407
+ window.ensureMermaid = ensureMermaid;
408
+ window.ensureMermaidElk = ensureMermaidElk;
409
+ window.initGraphScopeDefaults = initGraphScopeDefaults;
410
+ window.ensureMermaidDirective = ensureMermaidDirective;
411
+ window.copyMermaidSource = copyMermaidSource;
412
+ window.toggleGraphEdit = toggleGraphEdit;
413
+ window.applyGraphEdit = applyGraphEdit;
414
+ window.cancelGraphEdit = cancelGraphEdit;
415
+ window.refreshDrillCategories = refreshDrillCategories;
416
+ window.loadDrillInstructions = loadDrillInstructions;
417
+ window.clearSelections = clearSelections;
418
+
419
+ // Local persistence helpers
420
+ const LS_KEY = 'mcp.graph.lastSource';
421
+ function persistGraphSource(src){ try { if(src && src.trim().length) localStorage.setItem(LS_KEY, src); } catch{} }
422
+ function loadPersistedGraphSource(){ try { return localStorage.getItem(LS_KEY) || ''; } catch { return ''; } }
423
+ window.__persistGraphSource = persistGraphSource;
424
+
425
+ // Auto render on content edits when checkbox enabled
426
+ function bindAutoRender(){
427
+ const pre = document.getElementById('graph-mermaid');
428
+ if(!pre) return;
429
+ pre.addEventListener('input', ()=>{
430
+ const auto = (document.getElementById('graph-auto-render')||{}).checked;
431
+ if(auto && graphEditing){
432
+ const code = pre.textContent || '';
433
+ persistGraphSource(code);
434
+ // Debounced lightweight render (cancel previous if still pending)
435
+ clearTimeout(window.__graphAutoRenderTimer);
436
+ window.__graphAutoRenderTimer = setTimeout(()=>{
437
+ (async ()=>{ try { await ensureMermaid(); const { svg } = await window.mermaid.render('graphMermaidSvg', code); const legacyHost = document.getElementById('graph-mermaid-svg'); if(legacyHost) legacyHost.innerHTML = svg; } catch{} })();
438
+ }, 400);
439
+ }
440
+ });
441
+ }
442
+
443
+ // Theme insertion removed (fixed theme configuration)
444
+
445
+ document.addEventListener('DOMContentLoaded', ()=>{
446
+ bindAutoRender();
447
+ // If we have a persisted manual edit, restore it (but allow fresh reload to overwrite when refreshed)
448
+ const persisted = loadPersistedGraphSource();
449
+ if(persisted){
450
+ const target = document.getElementById('graph-mermaid');
451
+ if(target && target.textContent && !/\(loading graph/.test(target.textContent)){
452
+ // Only restore if existing content is a real graph
453
+ target.textContent = persisted;
454
+ }
455
+ }
456
+ // Restore manual override source if present
457
+ try {
458
+ const mo = localStorage.getItem('mcp.graph.manualOverrideSource');
459
+ if(mo){ window.__GRAPH_MANUAL_OVERRIDE = true; const t = document.getElementById('graph-mermaid'); if(t) t.textContent = mo; }
460
+ } catch{}
461
+ });
462
+
463
+ let __graphInitialAutoReload = false;
464
+ async function graphEnsureReadyAndReload(){
465
+ // Avoid multiple concurrent auto reloads
466
+ if(__graphInitialAutoReload) return; __graphInitialAutoReload = true;
467
+ try {
468
+ // Ensure categories then instructions then mermaid libs before reload
469
+ try { await refreshDrillCategories(); } catch {}
470
+ try { await loadDrillInstructions(); } catch {}
471
+ // Ensure mermaid (and elk) prior to first fetch so meta elements ready quickly
472
+ try { await ensureMermaid(); } catch {}
473
+ try { await ensureMermaidElk(); } catch {}
474
+ await reloadGraphMermaid();
475
+ } catch(e){
476
+ try { console.warn('[graphEnsureReadyAndReload] failed', e); } catch{}
477
+ }
478
+ }
479
+ window.graphEnsureReadyAndReload = graphEnsureReadyAndReload;
480
+
481
+ // Attach refresh button listener (id added in admin.html)
482
+ document.addEventListener('DOMContentLoaded', ()=>{
483
+ const btn = document.getElementById('graph-refresh-btn');
484
+ if(btn){ btn.addEventListener('click', ()=> window.reloadGraphMermaidForce()); }
485
+ });
486
+
487
+ // Inject selection change listeners to trigger reload and clear manual override mode
488
+ function bindScopeSelectionListeners(){
489
+ try {
490
+ const catSel = document.getElementById('drill-categories');
491
+ const instSel = document.getElementById('drill-instructions');
492
+ const handler = ()=>{
493
+ // Clear manual override so new scope fetch isn't masked
494
+ if(window.__GRAPH_MANUAL_OVERRIDE){
495
+ try { delete window.__GRAPH_MANUAL_OVERRIDE; } catch{}
496
+ try { localStorage.removeItem('mcp.graph.manualOverrideSource'); } catch{}
497
+ setGraphMetaProgress('scope-clear-override');
498
+ }
499
+ // If user is not editing custom graph text, trigger debounced reload
500
+ if(!graphEditing){
501
+ clearTimeout(window.__graphScopeReloadTimer);
502
+ setGraphMetaProgress('scope-change');
503
+ window.__graphScopeReloadTimer = setTimeout(()=>{ window.reloadGraphMermaid && window.reloadGraphMermaid(); }, 200);
504
+ }
505
+ };
506
+ if(catSel && !catSel.__mcpScopeBound){ catSel.addEventListener('change', handler); catSel.addEventListener('input', handler); catSel.__mcpScopeBound = true; }
507
+ if(instSel && !instSel.__mcpScopeBound){ instSel.addEventListener('change', handler); instSel.addEventListener('input', handler); instSel.__mcpScopeBound = true; }
508
+ } catch{}
509
+ }
510
+ window.bindScopeSelectionListeners = bindScopeSelectionListeners;
511
+
512
+ // Helper to explicitly clear manual override and force reload
513
+ window.clearGraphManualOverride = function(force){
514
+ try { delete window.__GRAPH_MANUAL_OVERRIDE; } catch{}
515
+ try { localStorage.removeItem('mcp.graph.manualOverrideSource'); } catch{}
516
+ if(force) window.reloadGraphMermaid && window.reloadGraphMermaid();
517
+ };
518
+
519
+ document.addEventListener('DOMContentLoaded', ()=>{
520
+ try { bindScopeSelectionListeners(); } catch{}
521
+ });
522
+
523
+ // Auto-load graph when section becomes visible (tab switch via MutationObserver)
524
+ document.addEventListener('DOMContentLoaded', () => {
525
+ const graphSection = document.getElementById('graph-section');
526
+ if (graphSection) {
527
+ const observer = new MutationObserver((mutations) => {
528
+ for (const mutation of mutations) {
529
+ if (mutation.attributeName === 'class' && !graphSection.classList.contains('hidden')) {
530
+ graphEnsureReadyAndReload();
531
+ break;
532
+ }
533
+ }
534
+ });
535
+ observer.observe(graphSection, { attributes: true, attributeFilter: ['class'] });
536
+ }
537
+ });
538
+
539
+ // ── Phase 4.3 — Zoom controls and fullscreen ──────────────────────────
540
+ let zoomLevel = 1;
541
+ const ZOOM_STEP = 0.15;
542
+ const ZOOM_MIN = 0.2;
543
+ const ZOOM_MAX = 5;
544
+
545
+ function applyZoom(){
546
+ const svg = document.getElementById('graph-mermaid-svg');
547
+ if(svg) svg.style.transform = 'scale(' + zoomLevel + ')';
548
+ if(svg) svg.style.transformOrigin = 'top left';
549
+ }
550
+
551
+ document.addEventListener('DOMContentLoaded', () => {
552
+ const zoomIn = document.getElementById('graph-zoom-in');
553
+ const zoomOut = document.getElementById('graph-zoom-out');
554
+ const zoomReset = document.getElementById('graph-zoom-reset');
555
+ const fullscreenBtn = document.getElementById('graph-fullscreen-btn');
556
+ const renderCard = document.getElementById('graph-render-card');
557
+
558
+ if(zoomIn) zoomIn.addEventListener('click', () => { zoomLevel = Math.min(ZOOM_MAX, zoomLevel + ZOOM_STEP); applyZoom(); });
559
+ if(zoomOut) zoomOut.addEventListener('click', () => { zoomLevel = Math.max(ZOOM_MIN, zoomLevel - ZOOM_STEP); applyZoom(); });
560
+ if(zoomReset) zoomReset.addEventListener('click', () => { zoomLevel = 1; applyZoom(); });
561
+
562
+ if(fullscreenBtn && renderCard){
563
+ fullscreenBtn.addEventListener('click', () => {
564
+ renderCard.classList.toggle('graph-fullscreen');
565
+ fullscreenBtn.textContent = renderCard.classList.contains('graph-fullscreen') ? '✕' : '⛶';
566
+ });
567
+ }
568
+
569
+ // Mousewheel zoom on the rendered diagram
570
+ const rendered = document.getElementById('graph-mermaid-rendered');
571
+ if(rendered){
572
+ rendered.addEventListener('wheel', (e) => {
573
+ if(e.ctrlKey || e.metaKey){
574
+ e.preventDefault();
575
+ zoomLevel = e.deltaY < 0
576
+ ? Math.min(ZOOM_MAX, zoomLevel + ZOOM_STEP)
577
+ : Math.max(ZOOM_MIN, zoomLevel - ZOOM_STEP);
578
+ applyZoom();
579
+ }
580
+ }, { passive: false });
581
+ }
582
+ });
583
+ })();