@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,822 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.shutdownGuard = void 0;
8
+ exports.main = main;
9
+ exports._parseArgs = parseArgs;
10
+ exports._findPackageVersion = findPackageVersion;
11
+ exports._startDashboard = startDashboard;
12
+ exports.startDashboard = startDashboard;
13
+ /**
14
+ * Index Server - Dual Transport Architecture
15
+ *
16
+ * PRIMARY TRANSPORT - MCP Protocol (stdin/stdout):
17
+ * - JSON-RPC 2.0 over stdio for all MCP client communication
18
+ * - VS Code, Claude, and other MCP clients connect via stdin/stdout only
19
+ * - Process-isolated, no network exposure
20
+ *
21
+ * SECONDARY TRANSPORT - Admin Dashboard (optional HTTP):
22
+ * - HTTP server on localhost for administrator monitoring
23
+ * - Read-only interface for status, tools, and metrics
24
+ * - Not for MCP client communication - admin use only
25
+ */
26
+ // Early stdin buffering (handshake hardening):
27
+ // Some fast clients send the initialize frame immediately after spawn. If the
28
+ // SDK server's stdin listener isn't attached yet, those bytes can sit without
29
+ // a consumer until the listener is registered. In practice we observed cases
30
+ // where initialize never produced a response in ~30s test windows. To harden
31
+ // the handshake we capture ALL stdin data prior to startSdkServer() completing
32
+ // and then re-emit the buffered chunks once the SDK has attached its handlers.
33
+ // This ensures spec compliance: an initialize request always yields either a
34
+ // success or a version negotiation error – never silent drop.
35
+ // Install global stderr log prefix (timestamps, pid, ppid, seq, tid) before any diagnostic output.
36
+ require("../services/logPrefix");
37
+ // Ensure logger initializes early (file logging environment may auto-resolve)
38
+ require("../services/logger");
39
+ const runtimeConfig_1 = require("../config/runtimeConfig");
40
+ const __earlyInitChunks = [];
41
+ let __earlyInitFirstLogged = false;
42
+ let __sdkReady = false;
43
+ // Allow opt-out (e.g., diagnostic comparison) via INDEX_SERVER_DISABLE_EARLY_STDIN_BUFFER=1
44
+ const __bufferEnabled = !(0, runtimeConfig_1.getRuntimeConfig)().server.disableEarlyStdinBuffer;
45
+ // We attach the temporary listener immediately so even synchronous module load
46
+ // time is covered.
47
+ function __earlyCapture(chunk) {
48
+ if (!__sdkReady && __bufferEnabled) {
49
+ __earlyInitChunks.push(Buffer.from(chunk));
50
+ // Light diagnostic: log only on first capture & optionally every 10th if deep buffering occurs.
51
+ if ((0, envUtils_1.getBooleanEnv)('INDEX_SERVER_LOG_DIAG')) {
52
+ if (!__earlyInitFirstLogged) {
53
+ __earlyInitFirstLogged = true;
54
+ const preview = chunk.toString('utf8').replace(/\r/g, '\\r').replace(/\n/g, '\\n').slice(0, 120);
55
+ const hasContentLength = chunk.toString('utf8').includes('Content-Length');
56
+ try {
57
+ process.stderr.write(`[handshake-buffer] first early chunk captured size=${chunk.length} hasContentLength=${hasContentLength} preview="${preview}"\n`);
58
+ }
59
+ catch { /* ignore */ }
60
+ }
61
+ else if (__earlyInitChunks.length % 10 === 0) {
62
+ try {
63
+ process.stderr.write(`[handshake-buffer] bufferedChunks=${__earlyInitChunks.length}\n`);
64
+ }
65
+ catch { /* ignore */ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ try {
71
+ if (__bufferEnabled)
72
+ process.stdin.on('data', __earlyCapture);
73
+ }
74
+ catch { /* ignore */ }
75
+ const registry_1 = require("./registry");
76
+ const sdkServer_1 = require("./sdkServer");
77
+ require("../services/handlers.instructions");
78
+ require("../services/handlers.search");
79
+ // Register unified dispatcher (was missing causing index_dispatch tests to timeout)
80
+ require("../services/instructions.dispatcher");
81
+ require("../services/handlers.integrity");
82
+ require("../services/handlers.usage");
83
+ require("../services/handlers.prompt");
84
+ require("../services/handlers.metrics");
85
+ require("../services/handlers.gates");
86
+ require("../services/handlers.testPrimitive");
87
+ require("../services/handlers.diagnostics");
88
+ require("../services/handlers.feedback");
89
+ require("../services/handlers.help");
90
+ require("../services/handlers.instructionSchema");
91
+ require("../services/handlers.bootstrap");
92
+ require("../services/handlers.manifest");
93
+ require("../services/handlers.instructionsDiagnostics");
94
+ require("../services/handlers.graph");
95
+ require("../services/handlers.activation"); // VSCode activation guide for tool enablement
96
+ require("../services/handlers.promote"); // promote_from_repo: scan repo & upsert into index
97
+ const indexContext_1 = require("../services/indexContext");
98
+ const seedBootstrap_1 = require("../services/seedBootstrap");
99
+ const DashboardServer_js_1 = require("../dashboard/server/DashboardServer.js");
100
+ const MetricsCollector_js_1 = require("../dashboard/server/MetricsCollector.js");
101
+ const InstanceManager_js_1 = require("../dashboard/server/InstanceManager.js");
102
+ const LeaderElection_js_1 = require("../dashboard/server/LeaderElection.js");
103
+ const HttpTransport_js_1 = require("../dashboard/server/HttpTransport.js");
104
+ const ThinClient_js_1 = require("../dashboard/server/ThinClient.js");
105
+ const memoryMonitor_1 = require("../utils/memoryMonitor");
106
+ const autoBackup_1 = require("../services/autoBackup");
107
+ const envUtils_1 = require("../utils/envUtils");
108
+ const fs_1 = __importDefault(require("fs"));
109
+ const path_1 = __importDefault(require("path"));
110
+ const logger_1 = require("../services/logger");
111
+ const bootstrapGating_1 = require("../services/bootstrapGating");
112
+ const preflight_1 = require("../services/preflight");
113
+ const shutdownGuard_1 = require("./shutdownGuard");
114
+ // Singleton shutdown guard — all exit paths funnel through this (Issue #36 fix)
115
+ exports.shutdownGuard = (0, shutdownGuard_1.createShutdownGuard)();
116
+ // Store in global symbol so services (indexContext) can register cleanup without circular imports
117
+ globalThis[Symbol.for('mcp-shutdown-guard')] = exports.shutdownGuard;
118
+ // ---------------------------------------------------------------------------
119
+ // Unified global diagnostics guard (installs once) for uncaught errors, promise
120
+ // rejections, runtime warnings, and termination signals. Emits NDJSON to stderr
121
+ // for compatibility with typescript-schema-viewer log analysis.
122
+ // Uses direct process.stderr.write (not the logger) for safety in crash paths.
123
+ // ---------------------------------------------------------------------------
124
+ if (!process.listeners('uncaughtException').some(l => l.name === 'mcpGlobalGuard')) {
125
+ const ndjson = (level, msg, detail) => {
126
+ try {
127
+ const rec = { ts: new Date().toISOString(), level, msg, pid: process.pid };
128
+ if (detail)
129
+ rec.detail = detail;
130
+ process.stderr.write(JSON.stringify(rec) + '\n');
131
+ }
132
+ catch { /* truly last resort */ }
133
+ };
134
+ const errDetail = (e) => {
135
+ if (e instanceof Error)
136
+ return e.stack ?? `${e.name || 'Error'}: ${e.message}`;
137
+ return typeof e === 'object' ? JSON.stringify(e) : String(e);
138
+ };
139
+ const getFatalExitDelayMs = () => Math.max(0, (0, runtimeConfig_1.getRuntimeConfig)().server.fatalExitDelayMs);
140
+ // Register port file cleanup with the shutdown guard
141
+ exports.shutdownGuard.registerCleanup('removePortFile', () => {
142
+ try {
143
+ (0, InstanceManager_js_1.removePortFile)();
144
+ }
145
+ catch { /* ignore */ }
146
+ });
147
+ const uncaughtHandler = function mcpGlobalGuard(err) {
148
+ ndjson('ERROR', '[indexServer] Uncaught exception', errDetail(err));
149
+ const code = exports.shutdownGuard.initiateShutdown('uncaughtException');
150
+ setTimeout(() => process.exit(code), getFatalExitDelayMs());
151
+ };
152
+ const rejectionHandler = function mcpGlobalGuard(reason) {
153
+ ndjson('ERROR', '[indexServer] Unhandled rejection', errDetail(reason));
154
+ };
155
+ process.on('uncaughtException', uncaughtHandler);
156
+ process.on('unhandledRejection', rejectionHandler);
157
+ // Surface Node.js process warnings (deprecations, experimental flags, etc.)
158
+ process.on('warning', (w) => {
159
+ ndjson('WARN', '[indexServer] Process warning', errDetail(w));
160
+ });
161
+ // Graceful shutdown on common termination signals: log intent then exit
162
+ const sigHandler = (sig) => {
163
+ ndjson('INFO', `[indexServer] Signal received: ${sig}`);
164
+ const code = exports.shutdownGuard.initiateShutdown(sig);
165
+ setTimeout(() => process.exit(code), 5);
166
+ };
167
+ ['SIGINT', 'SIGTERM'].forEach(s => { try {
168
+ process.once(s, sigHandler);
169
+ }
170
+ catch { /* ignore */ } });
171
+ // Detect parent disconnect (stdin EOF). On Windows, SIGTERM is not reliably
172
+ // delivered when the parent (VS Code) kills the child process. The stdin
173
+ // stream closing is the most reliable signal that the parent is gone. Without
174
+ // this, the Express dashboard HTTP server keeps the event loop alive and the
175
+ // process becomes an orphan that never exits (Issue: stale instances).
176
+ try {
177
+ if (process.stdin && !process.stdin.destroyed) {
178
+ const stdinCloseHandler = () => {
179
+ ndjson('INFO', '[indexServer] Parent disconnected (stdin closed) — initiating shutdown');
180
+ const code = exports.shutdownGuard.initiateShutdown('stdin-closed');
181
+ setTimeout(() => process.exit(code), 50);
182
+ };
183
+ process.stdin.once('end', stdinCloseHandler);
184
+ process.stdin.once('close', stdinCloseHandler);
185
+ }
186
+ }
187
+ catch { /* ignore */ }
188
+ // Belt-and-suspenders: PPID watchdog. On Windows, stdin EOF detection can be
189
+ // unreliable in edge cases (parent crash, pipe handle inheritance). Periodically
190
+ // check if the parent process (PPID) is still alive. If the parent is gone, we
191
+ // are orphaned and should exit. The check uses process.kill(pid, 0) which on
192
+ // Windows calls OpenProcess() -- it throws ESRCH if the process doesn't exist.
193
+ // Skip when ppid is 0 or 1 (init / no parent) or when running interactively.
194
+ try {
195
+ const ppid = process.ppid;
196
+ if (ppid && ppid > 1) {
197
+ const PPID_CHECK_INTERVAL_MS = 30_000; // 30 seconds
198
+ const ppidTimer = setInterval(() => {
199
+ try {
200
+ process.kill(ppid, 0); // signal 0 = existence check, no actual signal sent
201
+ }
202
+ catch {
203
+ // Parent is gone -- we are orphaned
204
+ ndjson('WARN', `[indexServer] Parent pid=${ppid} no longer exists — initiating shutdown`);
205
+ clearInterval(ppidTimer);
206
+ const code = exports.shutdownGuard.initiateShutdown('ppid-orphan');
207
+ setTimeout(() => process.exit(code), 50);
208
+ }
209
+ }, PPID_CHECK_INTERVAL_MS);
210
+ ppidTimer.unref(); // don't keep the event loop alive just for the watchdog
211
+ }
212
+ }
213
+ catch { /* ignore */ }
214
+ }
215
+ // Low-level ingress tracing: echo raw stdin frames when verbose enabled (diagnostic only)
216
+ try {
217
+ if ((0, envUtils_1.getBooleanEnv)('INDEX_SERVER_VERBOSE_LOGGING') && !process.stdin.listenerCount('data')) {
218
+ process.stdin.on('data', chunk => {
219
+ try {
220
+ process.stderr.write(`[in] ${chunk.toString().replace(/\n/g, '\\n')}\n`);
221
+ }
222
+ catch { /* ignore */ }
223
+ });
224
+ }
225
+ }
226
+ catch { /* ignore */ }
227
+ function parseArgs(argv) {
228
+ const runtimeCfg = (0, runtimeConfig_1.reloadRuntimeConfig)();
229
+ const http = runtimeCfg.dashboard.http;
230
+ const config = {
231
+ dashboard: http.enable,
232
+ dashboardPort: http.port,
233
+ dashboardHost: http.host,
234
+ maxPortTries: http.maxPortTries,
235
+ legacy: false,
236
+ dashboardTls: http.tls.enabled,
237
+ dashboardTlsCert: http.tls.certPath,
238
+ dashboardTlsKey: http.tls.keyPath,
239
+ dashboardTlsCa: http.tls.caPath,
240
+ };
241
+ const args = argv.slice(2);
242
+ for (let i = 0; i < args.length; i++) {
243
+ const raw = args[i];
244
+ if (raw === '--dashboard')
245
+ config.dashboard = true;
246
+ else if (raw === '--no-dashboard')
247
+ config.dashboard = false;
248
+ else if (raw.startsWith('--dashboard-port='))
249
+ config.dashboardPort = parseInt(raw.split('=')[1], 10) || config.dashboardPort;
250
+ else if (raw === '--dashboard-port') {
251
+ const v = args[++i];
252
+ if (v)
253
+ config.dashboardPort = parseInt(v, 10) || config.dashboardPort;
254
+ }
255
+ else if (raw.startsWith('--dashboard-host='))
256
+ config.dashboardHost = raw.split('=')[1] || config.dashboardHost;
257
+ else if (raw === '--dashboard-host') {
258
+ const v = args[++i];
259
+ if (v)
260
+ config.dashboardHost = v;
261
+ }
262
+ else if (raw.startsWith('--dashboard-tries='))
263
+ config.maxPortTries = Math.max(1, parseInt(raw.split('=')[1], 10) || config.maxPortTries);
264
+ else if (raw === '--dashboard-tries') {
265
+ const v = args[++i];
266
+ if (v)
267
+ config.maxPortTries = Math.max(1, parseInt(v, 10) || config.maxPortTries);
268
+ }
269
+ else if (raw === '--dashboard-tls')
270
+ config.dashboardTls = true;
271
+ else if (raw.startsWith('--dashboard-tls-cert='))
272
+ config.dashboardTlsCert = raw.split('=')[1];
273
+ else if (raw === '--dashboard-tls-cert') {
274
+ const v = args[++i];
275
+ if (v)
276
+ config.dashboardTlsCert = v;
277
+ }
278
+ else if (raw.startsWith('--dashboard-tls-key='))
279
+ config.dashboardTlsKey = raw.split('=')[1];
280
+ else if (raw === '--dashboard-tls-key') {
281
+ const v = args[++i];
282
+ if (v)
283
+ config.dashboardTlsKey = v;
284
+ }
285
+ else if (raw.startsWith('--dashboard-tls-ca='))
286
+ config.dashboardTlsCa = raw.split('=')[1];
287
+ else if (raw === '--dashboard-tls-ca') {
288
+ const v = args[++i];
289
+ if (v)
290
+ config.dashboardTlsCa = v;
291
+ }
292
+ else if (raw === '--legacy' || raw === '--legacy-transport')
293
+ config.legacy = true; // no-op
294
+ else if (raw === '--help' || raw === '-h') {
295
+ printHelpAndExit();
296
+ }
297
+ }
298
+ return config;
299
+ }
300
+ function printHelpAndExit() {
301
+ const help = `index-server - Model Context Protocol Server
302
+
303
+ MCP TRANSPORT (Client Communication):
304
+ Primary transport: JSON-RPC 2.0 over stdio (stdin/stdout)
305
+ Purpose: VS Code, Claude, and other MCP clients
306
+ Security: Process-isolated, no network exposure
307
+
308
+ ADMIN DASHBOARD (Optional):
309
+ --dashboard Enable read-only admin dashboard (default off)
310
+ --dashboard-port=PORT Dashboard port (default 8787)
311
+ --dashboard-host=HOST Dashboard host (default 127.0.0.1)
312
+ --dashboard-tries=N Port retry attempts (default 10)
313
+ --no-dashboard Disable dashboard
314
+ --dashboard-tls Enable HTTPS/WSS for dashboard
315
+ --dashboard-tls-cert=PATH TLS certificate file (PEM)
316
+ --dashboard-tls-key=PATH TLS private key file (PEM)
317
+ --dashboard-tls-ca=PATH Optional CA certificate file (PEM)
318
+ Purpose: Local administrator monitoring only
319
+
320
+ ENVIRONMENT VARIABLES:
321
+ INDEX_SERVER_DASHBOARD=1 Enable dashboard (0=disable, 1=enable)
322
+ INDEX_SERVER_DASHBOARD_PORT=PORT Dashboard port (default 8787)
323
+ INDEX_SERVER_DASHBOARD_HOST=HOST Dashboard host (default 127.0.0.1)
324
+ INDEX_SERVER_DASHBOARD_TRIES=N Port retry attempts (default 10)
325
+ INDEX_SERVER_DASHBOARD_TLS=1 Enable HTTPS/WSS for dashboard
326
+ INDEX_SERVER_DASHBOARD_TLS_CERT TLS certificate file path (PEM)
327
+ INDEX_SERVER_DASHBOARD_TLS_KEY TLS private key file path (PEM)
328
+ INDEX_SERVER_DASHBOARD_TLS_CA Optional CA certificate file path (PEM)
329
+
330
+ Other environment variables:
331
+ INDEX_SERVER_VERBOSE_LOGGING=1 Verbose RPC/transport logging
332
+ INDEX_SERVER_LOG_DIAG=1 Diagnostic logging
333
+ INDEX_SERVER_MUTATION=1 Enable write operations
334
+ INDEX_SERVER_IDLE_KEEPALIVE_MS Keepalive interval (default 30000ms)
335
+
336
+ GENERAL:
337
+ -h, --help Show this help and exit
338
+ (legacy transport removed; SDK only)
339
+
340
+ IMPORTANT:
341
+ - MCP clients connect via stdio only, not HTTP dashboard
342
+ - Dashboard is for admin monitoring, not client communication
343
+ - All MCP protocol frames output to stdout; logs to stderr
344
+ - Command line arguments override environment variables`;
345
+ // write to stderr to avoid contaminating stdout protocol
346
+ process.stderr.write(help + '\n');
347
+ process.exit(0);
348
+ }
349
+ function findPackageVersion() {
350
+ const candidates = [
351
+ path_1.default.join(process.cwd(), 'package.json'),
352
+ path_1.default.join(__dirname, '..', '..', 'package.json')
353
+ ];
354
+ for (const p of candidates) {
355
+ try {
356
+ if (fs_1.default.existsSync(p)) {
357
+ const raw = JSON.parse(fs_1.default.readFileSync(p, 'utf8'));
358
+ if (raw?.version)
359
+ return raw.version;
360
+ }
361
+ }
362
+ catch { /* ignore */ }
363
+ }
364
+ return '0.0.0';
365
+ }
366
+ // Added close handle in return object for test coverage harness so unit tests can start and stop the dashboard
367
+ // without leaving open event loop handles. Production code ignores the extra property.
368
+ async function startDashboard(cfg) {
369
+ if (!cfg.dashboard)
370
+ return null;
371
+ // Build TLS options if enabled — read cert/key from disk
372
+ let tlsOpt;
373
+ if (cfg.dashboardTls) {
374
+ if (!cfg.dashboardTlsCert || !cfg.dashboardTlsKey) {
375
+ process.stderr.write(`[startup] Dashboard TLS enabled but cert/key paths missing. Set INDEX_SERVER_DASHBOARD_TLS_CERT and INDEX_SERVER_DASHBOARD_TLS_KEY.\n`);
376
+ return null;
377
+ }
378
+ try {
379
+ const cert = fs_1.default.readFileSync(cfg.dashboardTlsCert, 'utf8');
380
+ const key = fs_1.default.readFileSync(cfg.dashboardTlsKey, 'utf8');
381
+ const ca = cfg.dashboardTlsCa ? fs_1.default.readFileSync(cfg.dashboardTlsCa, 'utf8') : undefined;
382
+ tlsOpt = { cert, key, ca };
383
+ }
384
+ catch (err) {
385
+ process.stderr.write(`[startup] Failed to read TLS cert/key files: ${err}\n`);
386
+ return null;
387
+ }
388
+ }
389
+ try {
390
+ process.stderr.write(`[startup] Starting dashboard server on ${cfg.dashboardHost}:${cfg.dashboardPort}${tlsOpt ? ' (HTTPS)' : ''}\n`);
391
+ const dashboardServer = (0, DashboardServer_js_1.createDashboardServer)({
392
+ port: cfg.dashboardPort,
393
+ host: cfg.dashboardHost,
394
+ maxPortTries: cfg.maxPortTries,
395
+ enableWebSockets: true,
396
+ enableCors: false,
397
+ tls: tlsOpt,
398
+ graphEnabled: (0, runtimeConfig_1.getRuntimeConfig)().dashboard.graphEnabled,
399
+ });
400
+ const result = await dashboardServer.start();
401
+ // Record dashboard startup in metrics
402
+ (0, MetricsCollector_js_1.getMetricsCollector)().recordConnection('dashboard_server');
403
+ return {
404
+ url: result.url,
405
+ close: result.close
406
+ };
407
+ }
408
+ catch (error) {
409
+ process.stderr.write(`[startup] Dashboard startup failed: ${error}\n`);
410
+ return null;
411
+ }
412
+ }
413
+ async function main() {
414
+ // Run startup preflight (module/data presence). Non-fatal unless INDEX_SERVER_PREFLIGHT_STRICT=1
415
+ try {
416
+ (0, preflight_1.emitPreflightAndMaybeExit)();
417
+ }
418
+ catch { /* ignore preflight wrapper errors */ }
419
+ // -------------------------------------------------------------
420
+ // Automatic bootstrap seeding (executes before any index load)
421
+ // -------------------------------------------------------------
422
+ try {
423
+ (0, seedBootstrap_1.autoSeedBootstrap)();
424
+ }
425
+ catch { /* ignore seeding errors (non-fatal) */ }
426
+ // -------------------------------------------------------------
427
+ // Idle keepalive support (multi-client shared server test aid)
428
+ // -------------------------------------------------------------
429
+ // Some test scenarios spawn the index server with stdin set to 'ignore'
430
+ // (child_process stdio option) and then create separate test clients
431
+ // that each spawn *their own* server processes pointing at the same
432
+ // instructions directory. In that arrangement the originally spawned
433
+ // shared server would exit immediately because no stdin activity occurs
434
+ // (no MCP initialize frame arrives). That premature exit caused RED in
435
+ // multi-client shared server tests before any CRUD
436
+ // assertions executed.
437
+ //
438
+ // To accommodate this interim RED/ GREEN progression—while future work
439
+ // may add true multi-attach capabilities—we keep the process alive for
440
+ // a bounded idle window when (a) stdin is not readable OR (b) no stdin
441
+ // activity is observed shortly after startup. Environment variable
442
+ // INDEX_SERVER_IDLE_KEEPALIVE_MS (default 30000) bounds the maximum keepalive.
443
+ // This has negligible overhead and only applies when no initialize
444
+ // handshake occurs promptly.
445
+ let __stdinActivity = false;
446
+ try {
447
+ if (process.stdin && !process.stdin.destroyed) {
448
+ process.stdin.on('data', () => { __stdinActivity = true; });
449
+ }
450
+ }
451
+ catch { /* ignore */ }
452
+ function startIdleKeepalive() {
453
+ const serverConfig = (0, runtimeConfig_1.getRuntimeConfig)().server;
454
+ const maxMs = Math.max(1000, serverConfig.idleKeepaliveMs);
455
+ const started = Date.now();
456
+ // Only create ONE interval.
457
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
458
+ if (global.__mcpIdleKeepalive)
459
+ return;
460
+ // Emit a synthetic readiness marker for test environments that spawn the
461
+ // server with stdin=ignore and rely on a '[ready]' sentinel before
462
+ // proceeding (multi-client shared server tests). This does NOT
463
+ // emit a formal JSON-RPC server/ready (which would follow initialize in
464
+ // normal operation); it's a plain log line to stdout and is gated to the
465
+ // idle keepalive path only so production interactive flows are unaffected.
466
+ // Synthetic readiness sentinel (only when explicitly enabled) so tests that rely on a
467
+ // shared server with stdin ignored can proceed. Stricter gating to avoid contaminating
468
+ // other protocol tests: requires INDEX_SERVER_SHARED_SERVER_SENTINEL=1 AND delays emission slightly
469
+ // to allow an initialize frame to arrive first if stdin is active. Legacy env
470
+ // INDEX_SERVER_IDLE_READY_SENTINEL is ignored unless accompanied by INDEX_SERVER_SHARED_SERVER_SENTINEL.
471
+ try {
472
+ if (serverConfig.sharedSentinel === 'multi-client-shared' && !__stdinActivity) {
473
+ setTimeout(() => { if (!__stdinActivity) {
474
+ try {
475
+ process.stdout.write('[ready] idle-keepalive (no stdin activity)\n');
476
+ }
477
+ catch { /* ignore */ }
478
+ } }, 60);
479
+ }
480
+ }
481
+ catch { /* ignore */ }
482
+ const iv = setInterval(() => {
483
+ // Clear early if stdin becomes active (late attach) so we don't keep zombie processes.
484
+ if (__stdinActivity || Date.now() - started > maxMs) {
485
+ clearInterval(iv);
486
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
487
+ global.__mcpIdleKeepalive = undefined;
488
+ }
489
+ else if ((0, runtimeConfig_1.getRuntimeConfig)().server.multicoreTrace) {
490
+ try {
491
+ // Reflective access to private diagnostic API (Node internal) guarded defensively
492
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
493
+ const anyProc = process;
494
+ const handlesLen = typeof anyProc._getActiveHandles === 'function' ? (anyProc._getActiveHandles() || []).length : 'n/a';
495
+ process.stderr.write(`[keepalive] t=${Date.now() - started}ms handles=${handlesLen} stdinActivity=${__stdinActivity}\n`);
496
+ }
497
+ catch { /* ignore */ }
498
+ }
499
+ }, 500);
500
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
501
+ global.__mcpIdleKeepalive = iv;
502
+ }
503
+ // Always start keepalive immediately (unconditional) so a lack of stdin activity
504
+ // cannot allow the event loop to drain and exit before the shared-server test
505
+ // observes the synthetic readiness sentinel. The interval self-clears on first
506
+ // stdin activity or after the bounded max window.
507
+ startIdleKeepalive();
508
+ // Short-circuit handshake mode removed (INDEX_SERVER_SHORTCIRCUIT) now that full
509
+ // protocol framing is stable and locked by tests. (2025-08-31)
510
+ const cfg = parseArgs(process.argv);
511
+ const runtime = (0, runtimeConfig_1.getRuntimeConfig)();
512
+ const dash = await startDashboard(cfg);
513
+ if (dash) {
514
+ process.stderr.write(`[startup] Dashboard server started successfully\n`);
515
+ process.stderr.write(`[startup] Dashboard URL: ${dash.url}\n`);
516
+ process.stderr.write(`[startup] Dashboard host: ${cfg.dashboardHost}\n`);
517
+ process.stderr.write(`[startup] Dashboard port: ${dash.url.split(':').pop()?.replace('/', '') || 'unknown'}\n`);
518
+ process.stderr.write(`[startup] Dashboard WebSockets: enabled\n`);
519
+ process.stderr.write(`[startup] Dashboard access: Local admin interface (not for MCP clients)\n`);
520
+ // Instance discovery: clean stale port files, register this instance
521
+ try {
522
+ (0, InstanceManager_js_1.cleanStalePortFiles)();
523
+ const dashPort = parseInt(dash.url.split(':').pop()?.replace('/', '') || '0', 10);
524
+ if (dashPort > 0) {
525
+ (0, InstanceManager_js_1.writePortFile)(dashPort, cfg.dashboardHost);
526
+ process.stderr.write(`[startup] Instance port file written (pid=${process.pid} port=${dashPort})\n`);
527
+ }
528
+ // Background instance health sweep: periodically HTTP-ping other instances
529
+ // and remove port files for ones that no longer respond. Defense-in-depth
530
+ // against orphaned processes where stdin-close detection didn't fire.
531
+ const validateIntervalMs = 30_000;
532
+ const validateTimer = setInterval(() => {
533
+ (0, InstanceManager_js_1.validateInstances)().catch(() => { });
534
+ }, validateIntervalMs);
535
+ validateTimer.unref(); // Don't keep process alive just for validation
536
+ }
537
+ catch (e) {
538
+ process.stderr.write(`[startup] Instance registration failed: ${e}\n`);
539
+ }
540
+ }
541
+ else if (cfg.dashboard) {
542
+ process.stderr.write(`[startup] Dashboard enabled but failed to start (check port ${cfg.dashboardPort})\n`);
543
+ }
544
+ else {
545
+ process.stderr.write(`[startup] Dashboard disabled (set INDEX_SERVER_DASHBOARD=1 to enable)\n`);
546
+ }
547
+ // ---------------------------------------------------------------
548
+ // Multi-instance: Leader election + HTTP MCP transport [EXPERIMENTAL]
549
+ // ---------------------------------------------------------------
550
+ const instanceMode = runtime.server.instanceMode;
551
+ if (instanceMode === 'leader' || instanceMode === 'auto') {
552
+ try {
553
+ const stateDir = runtime.dashboard.admin.stateDir;
554
+ const leaderPort = runtime.server.leaderPort;
555
+ const leaderHost = cfg.dashboardHost || '127.0.0.1';
556
+ const election = new LeaderElection_js_1.LeaderElection({
557
+ stateDir,
558
+ port: leaderPort,
559
+ host: leaderHost,
560
+ heartbeatIntervalMs: runtime.server.heartbeatIntervalMs,
561
+ staleThresholdMs: runtime.server.staleThresholdMs,
562
+ });
563
+ const role = election.start();
564
+ process.stderr.write(`[startup] Instance mode=${instanceMode} elected=${role} pid=${process.pid}\n`);
565
+ if (role === 'leader') {
566
+ // Mount MCP HTTP transport for thin clients
567
+ const express = (await import('express')).default;
568
+ const mcpApp = express();
569
+ mcpApp.use('/mcp', (0, HttpTransport_js_1.createMcpTransportRoutes)());
570
+ const mcpServer = mcpApp.listen(leaderPort, leaderHost, () => {
571
+ process.stderr.write(`[startup] MCP HTTP transport listening on http://${leaderHost}:${leaderPort}/mcp\n`);
572
+ process.stderr.write(`[startup] Thin clients can connect via INDEX_SERVER_STATE_DIR=${stateDir}\n`);
573
+ });
574
+ mcpServer.on('error', (err) => {
575
+ process.stderr.write(`[startup] MCP HTTP transport failed: ${err.message}\n`);
576
+ if (err.code === 'EADDRINUSE') {
577
+ process.stderr.write(`[startup] Port ${leaderPort} is already in use. Check INDEX_SERVER_LEADER_PORT or other services on this port.\n`);
578
+ process.stderr.write(`[startup] Releasing leader lock and continuing as standalone.\n`);
579
+ // Release lock and set role to standalone so no other instance
580
+ // sees a live leader on a port that isn't actually serving.
581
+ election.stop();
582
+ }
583
+ else {
584
+ election.stop();
585
+ }
586
+ });
587
+ // Clean up on shutdown
588
+ process.on('exit', () => {
589
+ election.stop();
590
+ try {
591
+ mcpServer.close();
592
+ }
593
+ catch { /* ignore */ }
594
+ });
595
+ }
596
+ else {
597
+ // Follower: proxy all tool calls to the leader via ThinClient
598
+ process.stderr.write(`[startup] Running as follower -- leader at pid=${election.leaderInfo?.pid} port=${election.leaderInfo?.port}\n`);
599
+ const thinClient = new ThinClient_js_1.ThinClient({ stateDir });
600
+ const leaderUrl = thinClient.discoverLeader();
601
+ process.stderr.write(`[startup] Follower proxy target: ${leaderUrl ?? 'pending discovery'}\n`);
602
+ // Install proxy: all handler calls forward to leader via HTTP JSON-RPC
603
+ (0, registry_1.installHandlerProxy)(async (tool, params) => {
604
+ const response = await thinClient.sendRpc(tool, params);
605
+ if (response.error) {
606
+ throw new Error(`Leader error [${response.error.code}]: ${response.error.message}`);
607
+ }
608
+ return response.result;
609
+ });
610
+ process.stderr.write(`[startup] Handler proxy installed -- all tool calls forwarded to leader\n`);
611
+ // Watch for leader failover: if leader dies, attempt promotion
612
+ election.on('leader-lost', () => {
613
+ process.stderr.write(`[startup] Leader lost -- attempting promotion\n`);
614
+ });
615
+ election.on('promoted', () => {
616
+ process.stderr.write(`[startup] Promoted to leader -- starting HTTP transport before removing proxy\n`);
617
+ // Keep proxy active until HTTP transport is ready to avoid a
618
+ // gap where neither proxy nor local handlers serve requests.
619
+ (async () => {
620
+ try {
621
+ const express = (await import('express')).default;
622
+ const mcpApp = express();
623
+ mcpApp.use('/mcp', (0, HttpTransport_js_1.createMcpTransportRoutes)());
624
+ const mcpServer = mcpApp.listen(leaderPort, leaderHost, () => {
625
+ // HTTP transport is listening -- NOW safe to remove proxy
626
+ (0, registry_1.installHandlerProxy)(null);
627
+ process.stderr.write(`[startup] MCP HTTP transport listening on http://${leaderHost}:${leaderPort}/mcp\n`);
628
+ process.stderr.write(`[startup] Handler proxy removed -- serving requests locally\n`);
629
+ });
630
+ mcpServer.on('error', (err) => {
631
+ process.stderr.write(`[startup] Post-promotion HTTP transport failed: ${err.message}\n`);
632
+ if (err.code === 'EADDRINUSE') {
633
+ process.stderr.write(`[startup] Port ${leaderPort} in use after promotion -- retrying in 2s\n`);
634
+ setTimeout(() => {
635
+ try {
636
+ mcpServer.close();
637
+ mcpApp.listen(leaderPort, leaderHost, () => {
638
+ (0, registry_1.installHandlerProxy)(null);
639
+ process.stderr.write(`[startup] MCP HTTP transport listening on retry\n`);
640
+ });
641
+ }
642
+ catch (retryErr) {
643
+ process.stderr.write(`[startup] Port retry failed: ${retryErr}\n`);
644
+ election.stop();
645
+ }
646
+ }, 2000);
647
+ }
648
+ else {
649
+ election.stop();
650
+ }
651
+ });
652
+ process.on('exit', () => {
653
+ try {
654
+ mcpServer.close();
655
+ }
656
+ catch { /* ignore */ }
657
+ });
658
+ }
659
+ catch (e) {
660
+ process.stderr.write(`[startup] Post-promotion HTTP setup failed: ${e}\n`);
661
+ }
662
+ })();
663
+ });
664
+ process.on('exit', () => {
665
+ election.stop();
666
+ thinClient.stop();
667
+ });
668
+ }
669
+ }
670
+ catch (e) {
671
+ process.stderr.write(`[startup] Leader election failed: ${e}\n`);
672
+ }
673
+ }
674
+ else if (instanceMode !== 'standalone') {
675
+ process.stderr.write(`[startup] Instance mode=${instanceMode} (follower mode requires thin-client entry point)\n`);
676
+ }
677
+ // Initialize memory monitoring if debug mode is enabled
678
+ if ((0, envUtils_1.getBooleanEnv)('INDEX_SERVER_DEBUG') || (0, envUtils_1.getBooleanEnv)('INDEX_SERVER_MEMORY_MONITOR')) {
679
+ try {
680
+ const memMonitor = (0, memoryMonitor_1.getMemoryMonitor)();
681
+ memMonitor.startMonitoring(10000); // Monitor every 10 seconds
682
+ process.stderr.write(`[startup] Memory monitoring enabled (interval: 10s)\n`);
683
+ process.stderr.write(`[startup] Memory monitor commands: memStatus(), startMemWatch(), stopMemWatch(), memReport(), forceGC(), checkListeners()\n`);
684
+ }
685
+ catch (error) {
686
+ process.stderr.write(`[startup] Memory monitoring failed: ${error}\n`);
687
+ }
688
+ }
689
+ // Extended startup diagnostics (does not emit on stdout)
690
+ if (runtime.logging.verbose || runtime.logging.diagnostics) {
691
+ try {
692
+ const methods = (0, registry_1.listRegisteredMethods)();
693
+ // Force index load to report initial count/hash
694
+ const idx = (0, indexContext_1.getIndexState)();
695
+ const mutation = runtime.mutationEnabled;
696
+ const dirDiag = (0, indexContext_1.diagnoseInstructionsDir)();
697
+ process.stderr.write(`[startup] toolsRegistered=${methods.length} mutationEnabled=${mutation} indexCount=${idx.list.length} indexHash=${idx.hash} instructionsDir="${dirDiag.dir}" exists=${dirDiag.exists} writable=${dirDiag.writable}${dirDiag.error ? ` dirError=${dirDiag.error.replace(/\s+/g, ' ')}` : ''}\n`);
698
+ try {
699
+ const { summarizeTraceEnv } = await import('../services/tracing.js');
700
+ const sum = summarizeTraceEnv();
701
+ process.stderr.write(`[startup] trace level=${sum.level} session=${sum.session} file=${sum.file || 'none'} categories=${sum.categories ? sum.categories.join(',') : '*'} maxFileSize=${sum.maxFileSize || 0} rotationIndex=${sum.rotationIndex}\n`);
702
+ }
703
+ catch { /* ignore */ }
704
+ }
705
+ catch (e) {
706
+ process.stderr.write(`[startup] diagnostics_error ${(e instanceof Error) ? e.message : String(e)}\n`);
707
+ }
708
+ }
709
+ if (__bufferEnabled && runtime.logging.diagnostics) {
710
+ try {
711
+ const totalBytes = __earlyInitChunks.reduce((sum, c) => sum + c.length, 0);
712
+ const hasContentLength = __earlyInitChunks.some(c => c.toString('utf8').includes('Content-Length'));
713
+ process.stderr.write(`[handshake-buffer] pre-start buffered=${__earlyInitChunks.length} totalBytes=${totalBytes} hasContentLength=${hasContentLength}\n`);
714
+ }
715
+ catch { /* ignore */ }
716
+ }
717
+ await (0, sdkServer_1.startSdkServer)();
718
+ // Auto-confirm bootstrap (test harness opt-in). Executed after SDK start so index state
719
+ // exists; harmless if already confirmed or non-bootstrap instructions present.
720
+ try {
721
+ if (runtime.server.bootstrap.autoconfirm) {
722
+ const ok = (0, bootstrapGating_1.forceBootstrapConfirmForTests)('auto-confirm env');
723
+ if (ok && runtime.logging.diagnostics) {
724
+ try {
725
+ process.stderr.write('[bootstrap] auto-confirm applied (test env)\n');
726
+ }
727
+ catch { /* ignore */ }
728
+ }
729
+ }
730
+ }
731
+ catch { /* ignore */ }
732
+ // Start cross-instance index version poller unless disabled.
733
+ try {
734
+ // Poller now opt-in to avoid introducing timing variance into deterministic
735
+ // visibility & manifest repair tests. Enable with INDEX_SERVER_ENABLE_INDEX_SERVER_POLLER=1.
736
+ if (runtime.server.indexPolling.enabled) {
737
+ (0, indexContext_1.startIndexVersionPoller)({
738
+ proactive: runtime.server.indexPolling.proactive,
739
+ intervalMs: runtime.server.indexPolling.intervalMs,
740
+ });
741
+ if (runtime.logging.diagnostics) {
742
+ try {
743
+ process.stderr.write(`[startup] index version poller started proactive=${runtime.server.indexPolling.proactive}\n`);
744
+ }
745
+ catch { /* ignore */ }
746
+ }
747
+ }
748
+ else if (runtime.logging.diagnostics) {
749
+ try {
750
+ process.stderr.write('[startup] index version poller not enabled (set INDEX_SERVER_ENABLE_INDEX_SERVER_POLLER=1)\n');
751
+ }
752
+ catch { /* ignore */ }
753
+ }
754
+ }
755
+ catch { /* ignore */ }
756
+ // Start automatic periodic backup of instruction index (deferred to avoid delaying startup).
757
+ try {
758
+ setImmediate(() => { try {
759
+ (0, autoBackup_1.startAutoBackup)();
760
+ }
761
+ catch { /* ignore */ } });
762
+ }
763
+ catch { /* ignore */ }
764
+ // Mark SDK ready & replay any buffered stdin chunks exactly once.
765
+ __sdkReady = true;
766
+ if (__bufferEnabled) {
767
+ try {
768
+ process.stdin.off('data', __earlyCapture);
769
+ }
770
+ catch { /* ignore */ }
771
+ if (__earlyInitChunks.length) {
772
+ const totalBytes = __earlyInitChunks.reduce((sum, c) => sum + c.length, 0);
773
+ const hasContentLength = __earlyInitChunks.some(c => c.toString('utf8').includes('Content-Length'));
774
+ const hasInitialize = __earlyInitChunks.some(c => c.toString('utf8').includes('"method"') && c.toString('utf8').includes('initialize'));
775
+ if (runtime.logging.diagnostics) {
776
+ try {
777
+ process.stderr.write(`[handshake-buffer] replay starting chunks=${__earlyInitChunks.length} totalBytes=${totalBytes} hasContentLength=${hasContentLength} hasInitialize=${hasInitialize}\n`);
778
+ }
779
+ catch { /* ignore */ }
780
+ }
781
+ try {
782
+ for (let i = 0; i < __earlyInitChunks.length; i++) {
783
+ const c = __earlyInitChunks[i];
784
+ process.stdin.emit('data', c);
785
+ if (runtime.logging.diagnostics && i === 0) {
786
+ const preview = c.toString('utf8').replace(/\r/g, '\\r').replace(/\n/g, '\\n').slice(0, 200);
787
+ try {
788
+ process.stderr.write(`[handshake-buffer] replayed chunk[0] size=${c.length} preview="${preview}"\n`);
789
+ }
790
+ catch { /* ignore */ }
791
+ }
792
+ }
793
+ }
794
+ catch (e) {
795
+ if (runtime.logging.diagnostics) {
796
+ try {
797
+ process.stderr.write(`[handshake-buffer] replay error: ${(e instanceof Error) ? e.message : String(e)}\n`);
798
+ }
799
+ catch { /* ignore */ }
800
+ }
801
+ }
802
+ // eslint-disable-next-line no-console
803
+ if (runtime.logging.diagnostics)
804
+ console.error(`[handshake-buffer] replayed ${__earlyInitChunks.length} early chunk(s)`);
805
+ __earlyInitChunks.length = 0;
806
+ }
807
+ else if (runtime.logging.diagnostics) {
808
+ try {
809
+ process.stderr.write(`[handshake-buffer] replay skipped (no buffered chunks)\n`);
810
+ }
811
+ catch { /* ignore */ }
812
+ }
813
+ }
814
+ process.stderr.write('[startup] SDK server started (stdio only)\n');
815
+ try {
816
+ (0, logger_1.logInfo)('[indexServer] Server started', { pid: process.pid, logFile: runtime.logging.file });
817
+ }
818
+ catch { /* ignore */ }
819
+ }
820
+ if (require.main === module) {
821
+ main();
822
+ }