@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.
- package/CHANGELOG.md +1218 -0
- package/CODE_OF_CONDUCT.md +49 -0
- package/CONTRIBUTING.md +75 -0
- package/LICENSE +21 -0
- package/README.md +523 -0
- package/SECURITY.md +50 -0
- package/dist/config/configUtils.d.ts +11 -0
- package/dist/config/configUtils.js +87 -0
- package/dist/config/dashboardConfig.d.ts +45 -0
- package/dist/config/dashboardConfig.js +63 -0
- package/dist/config/defaultValues.d.ts +61 -0
- package/dist/config/defaultValues.js +70 -0
- package/dist/config/dirConstants.d.ts +17 -0
- package/dist/config/dirConstants.js +28 -0
- package/dist/config/featureConfig.d.ts +61 -0
- package/dist/config/featureConfig.js +121 -0
- package/dist/config/runtimeConfig.d.ts +145 -0
- package/dist/config/runtimeConfig.js +334 -0
- package/dist/config/serverConfig.d.ts +90 -0
- package/dist/config/serverConfig.js +164 -0
- package/dist/dashboard/analytics/AnalyticsEngine.d.ts +142 -0
- package/dist/dashboard/analytics/AnalyticsEngine.js +373 -0
- package/dist/dashboard/analytics/BusinessIntelligence.d.ts +187 -0
- package/dist/dashboard/analytics/BusinessIntelligence.js +594 -0
- package/dist/dashboard/client/admin.html +2150 -0
- package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/chunk-SP2CHFBE.mjs +1 -0
- package/dist/dashboard/client/chunks/mermaid-layout-elk.esm.min/render-T6MDALS3.mjs +27 -0
- package/dist/dashboard/client/css/admin.css +1466 -0
- package/dist/dashboard/client/js/admin.boot.js +359 -0
- package/dist/dashboard/client/js/admin.config.js +196 -0
- package/dist/dashboard/client/js/admin.embeddings.js +425 -0
- package/dist/dashboard/client/js/admin.graph.js +583 -0
- package/dist/dashboard/client/js/admin.instances.js +120 -0
- package/dist/dashboard/client/js/admin.instructions.js +552 -0
- package/dist/dashboard/client/js/admin.logs.js +113 -0
- package/dist/dashboard/client/js/admin.maintenance.js +354 -0
- package/dist/dashboard/client/js/admin.messaging.js +635 -0
- package/dist/dashboard/client/js/admin.monitor.js +181 -0
- package/dist/dashboard/client/js/admin.overview.js +221 -0
- package/dist/dashboard/client/js/admin.performance.js +61 -0
- package/dist/dashboard/client/js/admin.sessions.js +293 -0
- package/dist/dashboard/client/js/admin.sqlite.js +366 -0
- package/dist/dashboard/client/js/admin.utils.js +49 -0
- package/dist/dashboard/client/js/chart.umd.js +14 -0
- package/dist/dashboard/client/js/elk.bundled.js +6696 -0
- package/dist/dashboard/client/js/marked.umd.js +74 -0
- package/dist/dashboard/client/js/mermaid.min.js +3022 -0
- package/dist/dashboard/client/mermaid-layout-elk.esm.min.mjs +1 -0
- package/dist/dashboard/export/DataExporter.d.ts +169 -0
- package/dist/dashboard/export/DataExporter.js +737 -0
- package/dist/dashboard/export/exporters/csvExporter.d.ts +11 -0
- package/dist/dashboard/export/exporters/csvExporter.js +46 -0
- package/dist/dashboard/export/exporters/exportTypes.d.ts +89 -0
- package/dist/dashboard/export/exporters/exportTypes.js +5 -0
- package/dist/dashboard/export/exporters/jsonExporter.d.ts +7 -0
- package/dist/dashboard/export/exporters/jsonExporter.js +22 -0
- package/dist/dashboard/export/exporters/xmlExporter.d.ts +17 -0
- package/dist/dashboard/export/exporters/xmlExporter.js +175 -0
- package/dist/dashboard/integration/APIIntegration.d.ts +41 -0
- package/dist/dashboard/integration/APIIntegration.js +95 -0
- package/dist/dashboard/security/SecurityMonitor.d.ts +167 -0
- package/dist/dashboard/security/SecurityMonitor.js +559 -0
- package/dist/dashboard/server/AdminPanel.d.ts +183 -0
- package/dist/dashboard/server/AdminPanel.js +792 -0
- package/dist/dashboard/server/AdminPanelConfig.d.ts +42 -0
- package/dist/dashboard/server/AdminPanelConfig.js +80 -0
- package/dist/dashboard/server/AdminPanelState.d.ts +47 -0
- package/dist/dashboard/server/AdminPanelState.js +214 -0
- package/dist/dashboard/server/ApiRoutes.d.ts +17 -0
- package/dist/dashboard/server/ApiRoutes.js +149 -0
- package/dist/dashboard/server/DashboardServer.d.ts +49 -0
- package/dist/dashboard/server/DashboardServer.js +159 -0
- package/dist/dashboard/server/FileMetricsStorage.d.ts +49 -0
- package/dist/dashboard/server/FileMetricsStorage.js +195 -0
- package/dist/dashboard/server/HttpTransport.d.ts +23 -0
- package/dist/dashboard/server/HttpTransport.js +116 -0
- package/dist/dashboard/server/InstanceManager.d.ts +53 -0
- package/dist/dashboard/server/InstanceManager.js +284 -0
- package/dist/dashboard/server/KnowledgeStore.d.ts +35 -0
- package/dist/dashboard/server/KnowledgeStore.js +105 -0
- package/dist/dashboard/server/LeaderElection.d.ts +81 -0
- package/dist/dashboard/server/LeaderElection.js +268 -0
- package/dist/dashboard/server/MetricsCollector.d.ts +200 -0
- package/dist/dashboard/server/MetricsCollector.js +803 -0
- package/dist/dashboard/server/SessionPersistenceManager.d.ts +88 -0
- package/dist/dashboard/server/SessionPersistenceManager.js +457 -0
- package/dist/dashboard/server/ThinClient.d.ts +64 -0
- package/dist/dashboard/server/ThinClient.js +237 -0
- package/dist/dashboard/server/WebSocketManager.d.ts +161 -0
- package/dist/dashboard/server/WebSocketManager.js +463 -0
- package/dist/dashboard/server/httpLifecycle.d.ts +17 -0
- package/dist/dashboard/server/httpLifecycle.js +35 -0
- package/dist/dashboard/server/legacyDashboardHtml.d.ts +9 -0
- package/dist/dashboard/server/legacyDashboardHtml.js +618 -0
- package/dist/dashboard/server/legacyDashboardStyles.d.ts +5 -0
- package/dist/dashboard/server/legacyDashboardStyles.js +490 -0
- package/dist/dashboard/server/metricsAggregation.d.ts +252 -0
- package/dist/dashboard/server/metricsAggregation.js +206 -0
- package/dist/dashboard/server/metricsSerializer.d.ts +25 -0
- package/dist/dashboard/server/metricsSerializer.js +195 -0
- package/dist/dashboard/server/routes/admin.routes.d.ts +16 -0
- package/dist/dashboard/server/routes/admin.routes.js +596 -0
- package/dist/dashboard/server/routes/alerts.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/alerts.routes.js +93 -0
- package/dist/dashboard/server/routes/api.feedback.routes.d.ts +73 -0
- package/dist/dashboard/server/routes/api.feedback.routes.js +171 -0
- package/dist/dashboard/server/routes/api.instructions.routes.d.ts +101 -0
- package/dist/dashboard/server/routes/api.instructions.routes.js +213 -0
- package/dist/dashboard/server/routes/api.usage.routes.d.ts +57 -0
- package/dist/dashboard/server/routes/api.usage.routes.js +374 -0
- package/dist/dashboard/server/routes/embeddings.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/embeddings.routes.js +246 -0
- package/dist/dashboard/server/routes/graph.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/graph.routes.js +280 -0
- package/dist/dashboard/server/routes/index.d.ts +38 -0
- package/dist/dashboard/server/routes/index.js +194 -0
- package/dist/dashboard/server/routes/instances.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/instances.routes.js +35 -0
- package/dist/dashboard/server/routes/instructions.routes.d.ts +8 -0
- package/dist/dashboard/server/routes/instructions.routes.js +336 -0
- package/dist/dashboard/server/routes/knowledge.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/knowledge.routes.js +82 -0
- package/dist/dashboard/server/routes/logs.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/logs.routes.js +164 -0
- package/dist/dashboard/server/routes/messaging.routes.d.ts +16 -0
- package/dist/dashboard/server/routes/messaging.routes.js +293 -0
- package/dist/dashboard/server/routes/metrics.routes.d.ts +10 -0
- package/dist/dashboard/server/routes/metrics.routes.js +346 -0
- package/dist/dashboard/server/routes/scripts.routes.d.ts +9 -0
- package/dist/dashboard/server/routes/scripts.routes.js +84 -0
- package/dist/dashboard/server/routes/sqlite.routes.d.ts +9 -0
- package/dist/dashboard/server/routes/sqlite.routes.js +569 -0
- package/dist/dashboard/server/routes/status.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/status.routes.js +183 -0
- package/dist/dashboard/server/routes/synthetic.routes.d.ts +7 -0
- package/dist/dashboard/server/routes/synthetic.routes.js +195 -0
- package/dist/dashboard/server/routes/tools.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/tools.routes.js +46 -0
- package/dist/dashboard/server/routes/usage.routes.d.ts +6 -0
- package/dist/dashboard/server/routes/usage.routes.js +25 -0
- package/dist/dashboard/server/wsInit.d.ts +16 -0
- package/dist/dashboard/server/wsInit.js +35 -0
- package/dist/externalClientLib.d.ts +1 -0
- package/dist/externalClientLib.js +2 -0
- package/dist/minimal/index.d.ts +1 -0
- package/dist/minimal/index.js +140 -0
- package/dist/models/SessionPersistence.d.ts +115 -0
- package/dist/models/SessionPersistence.js +66 -0
- package/dist/models/instruction.d.ts +45 -0
- package/dist/models/instruction.js +2 -0
- package/dist/perf/benchmark.d.ts +1 -0
- package/dist/perf/benchmark.js +50 -0
- package/dist/portableClientWrapper.d.ts +1 -0
- package/dist/portableClientWrapper.js +2 -0
- package/dist/schemas/index.d.ts +128 -0
- package/dist/schemas/index.js +371 -0
- package/dist/scripts/runPerformanceBaseline.d.ts +1 -0
- package/dist/scripts/runPerformanceBaseline.js +17 -0
- package/dist/server/handshakeManager.d.ts +25 -0
- package/dist/server/handshakeManager.js +472 -0
- package/dist/server/index-server.d.ts +56 -0
- package/dist/server/index-server.js +822 -0
- package/dist/server/registry.d.ts +44 -0
- package/dist/server/registry.js +236 -0
- package/dist/server/sdkServer.d.ts +8 -0
- package/dist/server/sdkServer.js +299 -0
- package/dist/server/shutdownGuard.d.ts +41 -0
- package/dist/server/shutdownGuard.js +52 -0
- package/dist/server/thin-client.d.ts +22 -0
- package/dist/server/thin-client.js +111 -0
- package/dist/server/transport.d.ts +41 -0
- package/dist/server/transport.js +312 -0
- package/dist/server/transportFactory.d.ts +21 -0
- package/dist/server/transportFactory.js +429 -0
- package/dist/services/atomicFs.d.ts +22 -0
- package/dist/services/atomicFs.js +103 -0
- package/dist/services/auditLog.d.ts +38 -0
- package/dist/services/auditLog.js +142 -0
- package/dist/services/autoBackup.d.ts +14 -0
- package/dist/services/autoBackup.js +171 -0
- package/dist/services/autoSplit.d.ts +32 -0
- package/dist/services/autoSplit.js +113 -0
- package/dist/services/backupZip.d.ts +25 -0
- package/dist/services/backupZip.js +110 -0
- package/dist/services/bootstrapGating.d.ts +123 -0
- package/dist/services/bootstrapGating.js +221 -0
- package/dist/services/canonical.d.ts +23 -0
- package/dist/services/canonical.js +65 -0
- package/dist/services/categoryRules.d.ts +7 -0
- package/dist/services/categoryRules.js +37 -0
- package/dist/services/classificationService.d.ts +42 -0
- package/dist/services/classificationService.js +168 -0
- package/dist/services/embeddingService.d.ts +62 -0
- package/dist/services/embeddingService.js +259 -0
- package/dist/services/errors.d.ts +22 -0
- package/dist/services/errors.js +31 -0
- package/dist/services/featureFlags.d.ts +25 -0
- package/dist/services/featureFlags.js +89 -0
- package/dist/services/features.d.ts +13 -0
- package/dist/services/features.js +35 -0
- package/dist/services/handlers/instructions.add.d.ts +1 -0
- package/dist/services/handlers/instructions.add.js +496 -0
- package/dist/services/handlers/instructions.groom.d.ts +1 -0
- package/dist/services/handlers/instructions.groom.js +523 -0
- package/dist/services/handlers/instructions.import.d.ts +1 -0
- package/dist/services/handlers/instructions.import.js +173 -0
- package/dist/services/handlers/instructions.patch.d.ts +1 -0
- package/dist/services/handlers/instructions.patch.js +167 -0
- package/dist/services/handlers/instructions.query.d.ts +163 -0
- package/dist/services/handlers/instructions.query.js +522 -0
- package/dist/services/handlers/instructions.reload.d.ts +1 -0
- package/dist/services/handlers/instructions.reload.js +13 -0
- package/dist/services/handlers/instructions.remove.d.ts +1 -0
- package/dist/services/handlers/instructions.remove.js +118 -0
- package/dist/services/handlers/instructions.shared.d.ts +31 -0
- package/dist/services/handlers/instructions.shared.js +124 -0
- package/dist/services/handlers.activation.d.ts +1 -0
- package/dist/services/handlers.activation.js +203 -0
- package/dist/services/handlers.bootstrap.d.ts +1 -0
- package/dist/services/handlers.bootstrap.js +38 -0
- package/dist/services/handlers.dashboardConfig.d.ts +34 -0
- package/dist/services/handlers.dashboardConfig.js +108 -0
- package/dist/services/handlers.diagnostics.d.ts +1 -0
- package/dist/services/handlers.diagnostics.js +64 -0
- package/dist/services/handlers.feedback.d.ts +15 -0
- package/dist/services/handlers.feedback.js +378 -0
- package/dist/services/handlers.gates.d.ts +1 -0
- package/dist/services/handlers.gates.js +46 -0
- package/dist/services/handlers.graph.d.ts +53 -0
- package/dist/services/handlers.graph.js +231 -0
- package/dist/services/handlers.help.d.ts +1 -0
- package/dist/services/handlers.help.js +119 -0
- package/dist/services/handlers.instructionSchema.d.ts +1 -0
- package/dist/services/handlers.instructionSchema.js +227 -0
- package/dist/services/handlers.instructions.d.ts +8 -0
- package/dist/services/handlers.instructions.js +14 -0
- package/dist/services/handlers.instructionsDiagnostics.d.ts +1 -0
- package/dist/services/handlers.instructionsDiagnostics.js +14 -0
- package/dist/services/handlers.integrity.d.ts +1 -0
- package/dist/services/handlers.integrity.js +35 -0
- package/dist/services/handlers.manifest.d.ts +1 -0
- package/dist/services/handlers.manifest.js +24 -0
- package/dist/services/handlers.messaging.d.ts +12 -0
- package/dist/services/handlers.messaging.js +203 -0
- package/dist/services/handlers.metrics.d.ts +1 -0
- package/dist/services/handlers.metrics.js +43 -0
- package/dist/services/handlers.promote.d.ts +1 -0
- package/dist/services/handlers.promote.js +306 -0
- package/dist/services/handlers.prompt.d.ts +1 -0
- package/dist/services/handlers.prompt.js +7 -0
- package/dist/services/handlers.search.d.ts +69 -0
- package/dist/services/handlers.search.js +645 -0
- package/dist/services/handlers.testPrimitive.d.ts +1 -0
- package/dist/services/handlers.testPrimitive.js +5 -0
- package/dist/services/handlers.trace.d.ts +1 -0
- package/dist/services/handlers.trace.js +31 -0
- package/dist/services/handlers.usage.d.ts +1 -0
- package/dist/services/handlers.usage.js +11 -0
- package/dist/services/hotScore.d.ts +137 -0
- package/dist/services/hotScore.js +244 -0
- package/dist/services/indexContext.d.ts +117 -0
- package/dist/services/indexContext.js +968 -0
- package/dist/services/indexLoader.d.ts +44 -0
- package/dist/services/indexLoader.js +921 -0
- package/dist/services/indexRepository.d.ts +32 -0
- package/dist/services/indexRepository.js +71 -0
- package/dist/services/indexingService.d.ts +1 -0
- package/dist/services/indexingService.js +2 -0
- package/dist/services/instructions.dispatcher.d.ts +1 -0
- package/dist/services/instructions.dispatcher.js +231 -0
- package/dist/services/logPrefix.d.ts +1 -0
- package/dist/services/logPrefix.js +30 -0
- package/dist/services/logger.d.ts +52 -0
- package/dist/services/logger.js +268 -0
- package/dist/services/manifestManager.d.ts +82 -0
- package/dist/services/manifestManager.js +200 -0
- package/dist/services/messaging/agentMailbox.d.ts +60 -0
- package/dist/services/messaging/agentMailbox.js +353 -0
- package/dist/services/messaging/messagingPersistence.d.ts +20 -0
- package/dist/services/messaging/messagingPersistence.js +111 -0
- package/dist/services/messaging/messagingTypes.d.ts +150 -0
- package/dist/services/messaging/messagingTypes.js +66 -0
- package/dist/services/ownershipService.d.ts +1 -0
- package/dist/services/ownershipService.js +38 -0
- package/dist/services/performanceBaseline.d.ts +19 -0
- package/dist/services/performanceBaseline.js +210 -0
- package/dist/services/preflight.d.ts +12 -0
- package/dist/services/preflight.js +79 -0
- package/dist/services/promptReviewService.d.ts +44 -0
- package/dist/services/promptReviewService.js +101 -0
- package/dist/services/responseEnvelope.d.ts +6 -0
- package/dist/services/responseEnvelope.js +25 -0
- package/dist/services/seedBootstrap.d.ts +34 -0
- package/dist/services/seedBootstrap.js +427 -0
- package/dist/services/storage/factory.d.ts +17 -0
- package/dist/services/storage/factory.js +35 -0
- package/dist/services/storage/hashUtils.d.ts +11 -0
- package/dist/services/storage/hashUtils.js +35 -0
- package/dist/services/storage/index.d.ts +12 -0
- package/dist/services/storage/index.js +18 -0
- package/dist/services/storage/jsonFileStore.d.ts +32 -0
- package/dist/services/storage/jsonFileStore.js +241 -0
- package/dist/services/storage/migrationEngine.d.ts +35 -0
- package/dist/services/storage/migrationEngine.js +93 -0
- package/dist/services/storage/sqliteMessageStore.d.ts +53 -0
- package/dist/services/storage/sqliteMessageStore.js +146 -0
- package/dist/services/storage/sqliteSchema.d.ts +12 -0
- package/dist/services/storage/sqliteSchema.js +122 -0
- package/dist/services/storage/sqliteStore.d.ts +41 -0
- package/dist/services/storage/sqliteStore.js +339 -0
- package/dist/services/storage/sqliteUsageStore.d.ts +35 -0
- package/dist/services/storage/sqliteUsageStore.js +94 -0
- package/dist/services/storage/types.d.ts +171 -0
- package/dist/services/storage/types.js +12 -0
- package/dist/services/toolHandlers.d.ts +23 -0
- package/dist/services/toolHandlers.js +50 -0
- package/dist/services/toolRegistry.d.ts +20 -0
- package/dist/services/toolRegistry.js +490 -0
- package/dist/services/toolRegistry.zod.d.ts +10 -0
- package/dist/services/toolRegistry.zod.js +323 -0
- package/dist/services/tracing.d.ts +26 -0
- package/dist/services/tracing.js +260 -0
- package/dist/services/usageBuckets.d.ts +161 -0
- package/dist/services/usageBuckets.js +364 -0
- package/dist/services/validationService.d.ts +38 -0
- package/dist/services/validationService.js +125 -0
- package/dist/utils/BufferRing.d.ts +203 -0
- package/dist/utils/BufferRing.js +551 -0
- package/dist/utils/BufferRingExamples.d.ts +55 -0
- package/dist/utils/BufferRingExamples.js +188 -0
- package/dist/utils/envUtils.d.ts +42 -0
- package/dist/utils/envUtils.js +80 -0
- package/dist/utils/memoryMonitor.d.ts +83 -0
- package/dist/utils/memoryMonitor.js +275 -0
- package/dist/versioning/schemaVersion.d.ts +6 -0
- package/dist/versioning/schemaVersion.js +93 -0
- package/package.json +134 -0
- package/schemas/README.md +13 -0
- package/schemas/feedback-entry.schema.json +27 -0
- package/schemas/graph-export-v2.schema.json +60 -0
- package/schemas/index-server.code-schema.json +38477 -0
- package/schemas/instruction.schema.json +262 -0
- package/schemas/json-schema/SessionPersistence-persisted-admin-session.schema.json +54 -0
- package/schemas/json-schema/SessionPersistence-persisted-session-history-entry.schema.json +51 -0
- package/schemas/json-schema/SessionPersistence-persisted-web-socket-connection.schema.json +54 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-config.schema.json +110 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-data.schema.json +229 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-manifest.schema.json +109 -0
- package/schemas/json-schema/SessionPersistence-session-persistence-metadata.schema.json +55 -0
- package/schemas/json-schema/instruction-audience-scope.schema.json +14 -0
- package/schemas/json-schema/instruction-content-type.schema.json +17 -0
- package/schemas/json-schema/instruction-instruction-entry.schema.json +206 -0
- package/schemas/json-schema/instruction-requirement-level.schema.json +16 -0
- package/schemas/manifest.json +78 -0
- package/schemas/manifest.schema.json +33 -0
- package/schemas/usage-batch.schema.json +16 -0
- package/schemas/usage-buckets.schema.json +30 -0
- package/schemas/usage-event.schema.json +17 -0
- package/scripts/copy-dashboard-assets.mjs +170 -0
- package/scripts/setup-hooks.cjs +28 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type Handler<TParams = unknown> = (params: TParams) => Promise<unknown> | unknown;
|
|
2
|
+
interface MetricRecord {
|
|
3
|
+
count: number;
|
|
4
|
+
totalMs: number;
|
|
5
|
+
maxMs: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Register a tool handler in the in-process registry, wrapping it with metrics,
|
|
9
|
+
* audit logging, correlation IDs, and optional proxy forwarding.
|
|
10
|
+
* @param name - Tool name used to route incoming requests
|
|
11
|
+
* @param fn - Handler function; may return a plain value or a Promise
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerHandler<TParams = unknown>(name: string, fn: Handler<TParams>): void;
|
|
14
|
+
/**
|
|
15
|
+
* Look up a registered (wrapped) handler by name.
|
|
16
|
+
* @param name - Tool name to look up
|
|
17
|
+
* @returns The wrapped handler, or `undefined` if not registered
|
|
18
|
+
*/
|
|
19
|
+
export declare function getHandler(name: string): Handler<unknown>;
|
|
20
|
+
/**
|
|
21
|
+
* Return the raw (unwrapped) handler that always executes locally,
|
|
22
|
+
* bypassing any installed proxy. Used by HttpTransport so the leader
|
|
23
|
+
* never accidentally routes its own handler calls through a proxy.
|
|
24
|
+
* @param name - Tool name to look up
|
|
25
|
+
* @returns The raw unwrapped handler, or `undefined` if not registered
|
|
26
|
+
*/
|
|
27
|
+
export declare function getLocalHandler(name: string): Handler<unknown>;
|
|
28
|
+
export declare function installHandlerProxy(fn: ((tool: string, params: unknown) => Promise<unknown>) | null): void;
|
|
29
|
+
/**
|
|
30
|
+
* Return the currently installed proxy function, or `null` if no proxy is active.
|
|
31
|
+
* @returns The proxy function, or `null`
|
|
32
|
+
*/
|
|
33
|
+
export declare function getHandlerProxy(): ((tool: string, params: unknown) => Promise<unknown>) | null;
|
|
34
|
+
/**
|
|
35
|
+
* Return a sorted list of all registered tool method names.
|
|
36
|
+
* @returns Array of method name strings in alphabetical order
|
|
37
|
+
*/
|
|
38
|
+
export declare function listRegisteredMethods(): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Return the raw per-tool metrics record map (count, totalMs, maxMs).
|
|
41
|
+
* @returns Reference to the live metrics map keyed by tool name
|
|
42
|
+
*/
|
|
43
|
+
export declare function getMetricsRaw(): Record<string, MetricRecord>;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerHandler = registerHandler;
|
|
4
|
+
exports.getHandler = getHandler;
|
|
5
|
+
exports.getLocalHandler = getLocalHandler;
|
|
6
|
+
exports.installHandlerProxy = installHandlerProxy;
|
|
7
|
+
exports.getHandlerProxy = getHandlerProxy;
|
|
8
|
+
exports.listRegisteredMethods = listRegisteredMethods;
|
|
9
|
+
exports.getMetricsRaw = getMetricsRaw;
|
|
10
|
+
// Lightweight in-process tool registry used exclusively by the SDK server path.
|
|
11
|
+
// Replaces the prior custom JSON-RPC transport layer.
|
|
12
|
+
const logger_1 = require("../services/logger");
|
|
13
|
+
const responseEnvelope_1 = require("../services/responseEnvelope");
|
|
14
|
+
const auditLog_1 = require("../services/auditLog");
|
|
15
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
16
|
+
// Dashboard metrics integration: bridge per-tool execution to global MetricsCollector
|
|
17
|
+
// so the admin panel performance & tool counters reflect live activity. Previously the
|
|
18
|
+
// dashboard showed zeros because recordToolCall was never invoked along the runtime path.
|
|
19
|
+
const MetricsCollector_js_1 = require("../dashboard/server/MetricsCollector.js");
|
|
20
|
+
const handlers = {};
|
|
21
|
+
// Raw (unwrapped) handlers that always execute locally - never go through proxy.
|
|
22
|
+
// Used by HttpTransport so the leader always runs handlers locally even when
|
|
23
|
+
// a proxy is installed in this process (e.g., same-process test scenarios).
|
|
24
|
+
const localHandlers = {};
|
|
25
|
+
const metrics = {};
|
|
26
|
+
function recordMetric(name, ms) {
|
|
27
|
+
let rec = metrics[name];
|
|
28
|
+
if (!rec) {
|
|
29
|
+
rec = { count: 0, totalMs: 0, maxMs: 0 };
|
|
30
|
+
metrics[name] = rec;
|
|
31
|
+
}
|
|
32
|
+
rec.count++;
|
|
33
|
+
rec.totalMs += ms;
|
|
34
|
+
if (ms > rec.maxMs)
|
|
35
|
+
rec.maxMs = ms;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register a tool handler in the in-process registry, wrapping it with metrics,
|
|
39
|
+
* audit logging, correlation IDs, and optional proxy forwarding.
|
|
40
|
+
* @param name - Tool name used to route incoming requests
|
|
41
|
+
* @param fn - Handler function; may return a plain value or a Promise
|
|
42
|
+
*/
|
|
43
|
+
function registerHandler(name, fn) {
|
|
44
|
+
// Always log tool lifecycle events (previously gated by INDEX_SERVER_LOG_TOOLS)
|
|
45
|
+
// Lazily resolve singleton (avoid throwing if dashboard disabled – metrics collector module
|
|
46
|
+
// still exports a singleton even when dashboard not started).
|
|
47
|
+
const collector = (() => { try {
|
|
48
|
+
return (0, MetricsCollector_js_1.getMetricsCollector)();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
} })();
|
|
53
|
+
const wrapped = async (params) => {
|
|
54
|
+
const corr = (0, logger_1.newCorrelationId)();
|
|
55
|
+
// If a proxy is installed (follower mode), forward to leader instead of running locally
|
|
56
|
+
if (proxyFn) {
|
|
57
|
+
try {
|
|
58
|
+
(0, logger_1.log)('INFO', `[registry] → ${name} (proxy)`, { tool: name, correlationId: corr });
|
|
59
|
+
}
|
|
60
|
+
catch { /* ignore */ }
|
|
61
|
+
const startNs = typeof process.hrtime === 'function' ? process.hrtime.bigint() : BigInt(Date.now()) * 1000000n;
|
|
62
|
+
try {
|
|
63
|
+
const result = await proxyFn(name, params);
|
|
64
|
+
const endNs = typeof process.hrtime === 'function' ? process.hrtime.bigint() : BigInt(Date.now()) * 1000000n;
|
|
65
|
+
const ms = Number(endNs - startNs) / 1_000_000;
|
|
66
|
+
recordMetric(name, ms);
|
|
67
|
+
try {
|
|
68
|
+
collector?.recordToolCall(name, true, ms);
|
|
69
|
+
}
|
|
70
|
+
catch { /* ignore */ }
|
|
71
|
+
try {
|
|
72
|
+
(0, logger_1.log)('INFO', `[registry] ← ${name} (proxy)`, { tool: name, correlationId: corr, ms });
|
|
73
|
+
}
|
|
74
|
+
catch { /* ignore */ }
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
const endNs = typeof process.hrtime === 'function' ? process.hrtime.bigint() : BigInt(Date.now()) * 1000000n;
|
|
79
|
+
const ms = Number(endNs - startNs) / 1_000_000;
|
|
80
|
+
recordMetric(name, ms);
|
|
81
|
+
try {
|
|
82
|
+
collector?.recordToolCall(name, false, ms, 'proxy_error');
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore */ }
|
|
85
|
+
try {
|
|
86
|
+
(0, logger_1.log)('ERROR', `[registry] Tool proxy error: ${name}`, { tool: name, correlationId: corr, detail: e instanceof Error ? e.stack : String(e) });
|
|
87
|
+
}
|
|
88
|
+
catch { /* ignore */ }
|
|
89
|
+
throw e;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const startNs = typeof process.hrtime === 'function' ? process.hrtime.bigint() : BigInt(Date.now()) * 1000000n;
|
|
93
|
+
const timingEnabled = process.env.INDEX_SERVER_ADD_TIMING === '1' || (0, runtimeConfig_1.getRuntimeConfig)().mutation.dispatcherTiming;
|
|
94
|
+
let phaseMarks;
|
|
95
|
+
if (timingEnabled) {
|
|
96
|
+
phaseMarks = [{ p: 'start', t: Date.now() }];
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
(0, logger_1.log)('INFO', `[registry] → ${name}`, { tool: name, correlationId: corr });
|
|
100
|
+
}
|
|
101
|
+
catch { /* logging should not break */ }
|
|
102
|
+
let success = false;
|
|
103
|
+
let errorType;
|
|
104
|
+
try {
|
|
105
|
+
const result = await (0, auditLog_1.runWithCorrelation)(corr, () => Promise.resolve(fn(params)));
|
|
106
|
+
if (timingEnabled && phaseMarks) {
|
|
107
|
+
phaseMarks.push({ p: 'afterFn', t: Date.now() });
|
|
108
|
+
}
|
|
109
|
+
success = true;
|
|
110
|
+
const wrappedResp = (0, responseEnvelope_1.wrapResponse)(result);
|
|
111
|
+
if (timingEnabled) {
|
|
112
|
+
try {
|
|
113
|
+
const endTs = Date.now();
|
|
114
|
+
phaseMarks.push({ p: 'endPreWrap', t: endTs });
|
|
115
|
+
const phases = phaseMarks;
|
|
116
|
+
wrappedResp.__timing = { tool: name, phases };
|
|
117
|
+
}
|
|
118
|
+
catch { /* ignore timing embed errors */ }
|
|
119
|
+
}
|
|
120
|
+
return wrappedResp;
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
try {
|
|
124
|
+
(0, logger_1.log)('ERROR', `[registry] Tool error: ${name}`, { tool: name, correlationId: corr, detail: e instanceof Error ? e.stack : String(e) });
|
|
125
|
+
}
|
|
126
|
+
catch { /* ignore */ }
|
|
127
|
+
// Best-effort classification for dashboard error breakdown
|
|
128
|
+
try {
|
|
129
|
+
const errObj = e;
|
|
130
|
+
// Narrow progressively without casting to any to satisfy eslint no-explicit-any rule.
|
|
131
|
+
if (typeof errObj === 'object' && errObj !== null) {
|
|
132
|
+
const maybeCode = errObj.code;
|
|
133
|
+
if (Number.isSafeInteger(maybeCode)) {
|
|
134
|
+
errorType = `code_${maybeCode}`;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const maybeData = errObj.data;
|
|
138
|
+
if (typeof maybeData === 'object' && maybeData !== null && typeof maybeData.reason === 'string') {
|
|
139
|
+
errorType = String(maybeData.reason);
|
|
140
|
+
}
|
|
141
|
+
else if (typeof errObj.reason === 'string') {
|
|
142
|
+
errorType = String(errObj.reason);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
errorType = 'error';
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
errorType = 'error';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch { /* ignore classification errors */ }
|
|
154
|
+
throw e;
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
const endNs = typeof process.hrtime === 'function' ? process.hrtime.bigint() : BigInt(Date.now()) * 1000000n;
|
|
158
|
+
const ms = Number(endNs - startNs) / 1_000_000;
|
|
159
|
+
recordMetric(name, ms);
|
|
160
|
+
if (timingEnabled && phaseMarks) {
|
|
161
|
+
try {
|
|
162
|
+
phaseMarks.push({ p: 'finally', t: Date.now() });
|
|
163
|
+
}
|
|
164
|
+
catch { /* ignore */ }
|
|
165
|
+
}
|
|
166
|
+
// Feed global dashboard metrics (safe no-op if collector absent). This enables:
|
|
167
|
+
// - requestsPerMinute (rolling window)
|
|
168
|
+
// - successRate / errorRate
|
|
169
|
+
// - per-tool call counts & avg response time
|
|
170
|
+
try {
|
|
171
|
+
collector?.recordToolCall(name, success, ms, success ? undefined : errorType);
|
|
172
|
+
}
|
|
173
|
+
catch { /* never block tool path */ }
|
|
174
|
+
try {
|
|
175
|
+
(0, auditLog_1.logToolAudit)(name, success, ms, corr, success ? undefined : errorType);
|
|
176
|
+
}
|
|
177
|
+
catch { /* never block tool path */ }
|
|
178
|
+
try {
|
|
179
|
+
(0, logger_1.log)('INFO', `[registry] ← ${name}`, { tool: name, correlationId: corr, ms });
|
|
180
|
+
}
|
|
181
|
+
catch { /* ignore */ }
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
handlers[name] = wrapped;
|
|
185
|
+
localHandlers[name] = fn;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Look up a registered (wrapped) handler by name.
|
|
189
|
+
* @param name - Tool name to look up
|
|
190
|
+
* @returns The wrapped handler, or `undefined` if not registered
|
|
191
|
+
*/
|
|
192
|
+
function getHandler(name) {
|
|
193
|
+
return handlers[name];
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Return the raw (unwrapped) handler that always executes locally,
|
|
197
|
+
* bypassing any installed proxy. Used by HttpTransport so the leader
|
|
198
|
+
* never accidentally routes its own handler calls through a proxy.
|
|
199
|
+
* @param name - Tool name to look up
|
|
200
|
+
* @returns The raw unwrapped handler, or `undefined` if not registered
|
|
201
|
+
*/
|
|
202
|
+
function getLocalHandler(name) {
|
|
203
|
+
return localHandlers[name];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Install a proxy function that intercepts all handler calls.
|
|
207
|
+
* Used by follower instances to forward tool calls to the leader.
|
|
208
|
+
* The proxy receives (toolName, params) and returns the result.
|
|
209
|
+
* Pass null to remove the proxy (e.g., on promotion to leader).
|
|
210
|
+
* @param fn - Proxy function to install, or `null` to remove the current proxy
|
|
211
|
+
*/
|
|
212
|
+
let proxyFn = null;
|
|
213
|
+
function installHandlerProxy(fn) {
|
|
214
|
+
proxyFn = fn;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Return the currently installed proxy function, or `null` if no proxy is active.
|
|
218
|
+
* @returns The proxy function, or `null`
|
|
219
|
+
*/
|
|
220
|
+
function getHandlerProxy() {
|
|
221
|
+
return proxyFn;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Return a sorted list of all registered tool method names.
|
|
225
|
+
* @returns Array of method name strings in alphabetical order
|
|
226
|
+
*/
|
|
227
|
+
function listRegisteredMethods() {
|
|
228
|
+
return Object.keys(handlers).sort();
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Return the raw per-tool metrics record map (count, totalMs, maxMs).
|
|
232
|
+
* @returns Reference to the live metrics map keyed by tool name
|
|
233
|
+
*/
|
|
234
|
+
function getMetricsRaw() {
|
|
235
|
+
return metrics;
|
|
236
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import '../services/toolHandlers';
|
|
2
|
+
/**
|
|
3
|
+
* Create and configure an MCP SDK server instance with the full tool registry.
|
|
4
|
+
* @param ServerClass - The MCP SDK Server constructor (loaded dynamically to avoid ESM/CJS conflicts)
|
|
5
|
+
* @returns Configured SDK server instance with all tool handlers registered
|
|
6
|
+
*/
|
|
7
|
+
export declare function createSdkServer(ServerClass: any): any;
|
|
8
|
+
export declare function startSdkServer(): Promise<void>;
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createSdkServer = createSdkServer;
|
|
7
|
+
exports.startSdkServer = startSdkServer;
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
9
|
+
/**
|
|
10
|
+
* SDK-based MCP server bootstrap (dynamic require variant to work under CommonJS build).
|
|
11
|
+
* Uses the published dist/ subpath exports without relying on TS ESM moduleResolution.
|
|
12
|
+
*
|
|
13
|
+
* Orchestrates server creation and startup, delegating handshake/protocol logic to
|
|
14
|
+
* handshakeManager.ts and transport/dispatcher setup to transportFactory.ts.
|
|
15
|
+
*/
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const toolRegistry_1 = require("../services/toolRegistry");
|
|
19
|
+
require("../services/toolHandlers");
|
|
20
|
+
const registry_1 = require("./registry");
|
|
21
|
+
const zod_1 = require("zod");
|
|
22
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
23
|
+
const handshakeManager_1 = require("./handshakeManager");
|
|
24
|
+
const transportFactory_1 = require("./transportFactory");
|
|
25
|
+
// ESM dynamic import used below for SDK modules.
|
|
26
|
+
// We'll lazy-load ESM exports via dynamic import when starting.
|
|
27
|
+
let StdioServerTransport;
|
|
28
|
+
/**
|
|
29
|
+
* Create and configure an MCP SDK server instance with the full tool registry.
|
|
30
|
+
* @param ServerClass - The MCP SDK Server constructor (loaded dynamically to avoid ESM/CJS conflicts)
|
|
31
|
+
* @returns Configured SDK server instance with all tool handlers registered
|
|
32
|
+
*/
|
|
33
|
+
function createSdkServer(ServerClass) {
|
|
34
|
+
// Derive version from package.json (no artificial suffix so clients see real semantic version)
|
|
35
|
+
let version = '0.0.0';
|
|
36
|
+
const pkgCandidates = [
|
|
37
|
+
path_1.default.join(process.cwd(), 'package.json'),
|
|
38
|
+
path_1.default.join(__dirname, '..', '..', 'package.json'), // dist/server/../.. = repo root
|
|
39
|
+
path_1.default.join(__dirname, '..', 'package.json'), // fallback
|
|
40
|
+
];
|
|
41
|
+
for (const pkgPath of pkgCandidates) {
|
|
42
|
+
try {
|
|
43
|
+
if (fs_1.default.existsSync(pkgPath)) {
|
|
44
|
+
const raw = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
|
|
45
|
+
if (raw.version) {
|
|
46
|
+
version = raw.version;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch { /* ignore */ }
|
|
52
|
+
}
|
|
53
|
+
const server = new ServerClass({ name: 'index', version }, { capabilities: { tools: { listChanged: true } } });
|
|
54
|
+
server.__declaredVersion = version;
|
|
55
|
+
// Never emit tools/list_changed before ready. Wrap sendToolListChanged to enforce ordering.
|
|
56
|
+
try {
|
|
57
|
+
const origSendToolListChanged = server.sendToolListChanged?.bind(server);
|
|
58
|
+
if (origSendToolListChanged && !server.__listPatched) {
|
|
59
|
+
server.__listPatched = true;
|
|
60
|
+
server.sendToolListChanged = (...a) => {
|
|
61
|
+
if (!server.__readyNotified) {
|
|
62
|
+
server.__pendingListChanged = true;
|
|
63
|
+
(0, handshakeManager_1.record)('buffer_list_changed_pre_ready');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
return origSendToolListChanged(...a);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch { /* ignore */ }
|
|
71
|
+
// Track ready notification + whether initialize was seen (ordering guarantee)
|
|
72
|
+
server.__readyNotified = false;
|
|
73
|
+
server.__sawInitializeRequest = false;
|
|
74
|
+
server.__initResponseSent = false;
|
|
75
|
+
// Single fallback watchdog if ready somehow suppressed.
|
|
76
|
+
if ((0, handshakeManager_1.isHandshakeFallbacksEnabled)()) {
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
try {
|
|
79
|
+
if (server.__sawInitializeRequest && !server.__readyNotified) {
|
|
80
|
+
(0, handshakeManager_1.record)('watchdog_emit_ready');
|
|
81
|
+
(0, handshakeManager_1.emitReadyGlobal)(server, 'watchdog');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore */ }
|
|
85
|
+
}, 250).unref?.();
|
|
86
|
+
}
|
|
87
|
+
const requestSchema = (methodName) => zod_1.z.object({
|
|
88
|
+
jsonrpc: zod_1.z.literal('2.0'),
|
|
89
|
+
id: zod_1.z.union([zod_1.z.string(), zod_1.z.number()]).optional(),
|
|
90
|
+
method: zod_1.z.literal(methodName),
|
|
91
|
+
params: zod_1.z.any().optional()
|
|
92
|
+
});
|
|
93
|
+
// Explicit initialize handler – guarantees deterministic initialize response
|
|
94
|
+
// followed by exactly one server/ready notification.
|
|
95
|
+
server.setRequestHandler(requestSchema('initialize'), async (req) => {
|
|
96
|
+
try {
|
|
97
|
+
server.__sawInitializeRequest = true;
|
|
98
|
+
(0, handshakeManager_1.record)('initialize_received', { requestedProtocol: req?.params?.protocolVersion });
|
|
99
|
+
const requested = req?.params?.protocolVersion;
|
|
100
|
+
const negotiated = (0, handshakeManager_1.negotiateProtocolVersion)(requested);
|
|
101
|
+
const versionDeclared = server.__declaredVersion || server.version || '0.0.0';
|
|
102
|
+
const result = {
|
|
103
|
+
protocolVersion: negotiated,
|
|
104
|
+
serverInfo: { name: 'index', version: versionDeclared },
|
|
105
|
+
capabilities: { tools: { listChanged: true } },
|
|
106
|
+
instructions: 'Use initialize -> tools/list -> tools/call { name, arguments }. Health: tools/call health_check. Metrics: tools/call metrics_snapshot. Ping: ping.'
|
|
107
|
+
};
|
|
108
|
+
(0, handshakeManager_1.initFrameLog)('handler_return', { negotiated });
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return { protocolVersion: handshakeManager_1.SUPPORTED_PROTOCOL_VERSIONS[0], serverInfo: { name: 'index', version: '0.0.0' }, capabilities: { tools: { listChanged: true } }, instructions: 'init fallback' };
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
// Legacy internal _oninitialize patch (will not trigger because we intercept initialize directly)
|
|
116
|
+
const originalInitInner = server._oninitialize?.bind(server);
|
|
117
|
+
if (originalInitInner && !server.__initPatched) {
|
|
118
|
+
server.__initPatched = true;
|
|
119
|
+
server._oninitialize = async function (request) {
|
|
120
|
+
const result = await originalInitInner(request);
|
|
121
|
+
try {
|
|
122
|
+
const negotiated = (0, handshakeManager_1.negotiateProtocolVersion)(request?.params?.protocolVersion);
|
|
123
|
+
result.protocolVersion = negotiated;
|
|
124
|
+
if (result && typeof result === 'object' && !('instructions' in result)) {
|
|
125
|
+
result.instructions = 'Use initialize -> tools/list -> tools/call { name, arguments }. Health: tools/call health_check. Metrics: tools/call metrics_snapshot. Ping: ping.';
|
|
126
|
+
}
|
|
127
|
+
this.__sawInitializeRequest = true;
|
|
128
|
+
}
|
|
129
|
+
catch { /* ignore */ }
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
server.setRequestHandler(requestSchema('tools/list'), async () => {
|
|
134
|
+
(0, handshakeManager_1.record)('tools_list_request', { afterReady: !!server.__readyNotified, sawInit: !!server.__sawInitializeRequest });
|
|
135
|
+
const registry = (0, toolRegistry_1.getToolRegistry)();
|
|
136
|
+
return { tools: registry.map(r => ({ name: r.name, description: r.description, inputSchema: r.inputSchema })) };
|
|
137
|
+
});
|
|
138
|
+
// Raw handler for tools/call (MCP style) - returns content array
|
|
139
|
+
server.setRequestHandler(requestSchema('tools/call'), async (req) => {
|
|
140
|
+
const p = req?.params ?? {};
|
|
141
|
+
const name = p.name ?? '';
|
|
142
|
+
const args = p.arguments || {};
|
|
143
|
+
if (name === 'health_check')
|
|
144
|
+
(0, handshakeManager_1.record)('tools_call_health');
|
|
145
|
+
try {
|
|
146
|
+
if ((0, runtimeConfig_1.getRuntimeConfig)().logging.verbose)
|
|
147
|
+
process.stderr.write(`[rpc] call method=tools/call tool=${name} id=${req?.id ?? 'n/a'}\n`);
|
|
148
|
+
}
|
|
149
|
+
catch { /* ignore */ }
|
|
150
|
+
const handler = (0, registry_1.getHandler)(name);
|
|
151
|
+
if (!handler) {
|
|
152
|
+
throw { code: -32601, message: `Unknown tool: ${name}`, data: { message: `Unknown tool: ${name}`, method: name } };
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const result = await Promise.resolve(handler(args));
|
|
156
|
+
try {
|
|
157
|
+
if ((0, runtimeConfig_1.getRuntimeConfig)().logging.verbose)
|
|
158
|
+
process.stderr.write(`[rpc] tool_result tool=${name} bytes=${Buffer.byteLength(JSON.stringify(result), 'utf8')}\n`);
|
|
159
|
+
}
|
|
160
|
+
catch { /* ignore */ }
|
|
161
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
const code = e?.code;
|
|
165
|
+
const sem = e?.__semantic === true;
|
|
166
|
+
if (Number.isSafeInteger(code)) {
|
|
167
|
+
try {
|
|
168
|
+
if ((0, runtimeConfig_1.getRuntimeConfig)().logging.verbose)
|
|
169
|
+
process.stderr.write(`[rpc] tool_error_passthru tool=${name} code=${code} semantic=${sem ? '1' : '0'} msg=${e?.message || ''}\n`);
|
|
170
|
+
}
|
|
171
|
+
catch { /* ignore */ }
|
|
172
|
+
throw e;
|
|
173
|
+
}
|
|
174
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
175
|
+
try {
|
|
176
|
+
if ((0, runtimeConfig_1.getRuntimeConfig)().logging.verbose)
|
|
177
|
+
process.stderr.write(`[rpc] tool_error_wrap tool=${name} msg=${msg.replace(/\s+/g, ' ')} code=${code ?? 'n/a'}\n`);
|
|
178
|
+
}
|
|
179
|
+
catch { /* ignore */ }
|
|
180
|
+
throw { code: -32603, message: 'Tool execution failed', data: { message: msg, method: name } };
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
// Lightweight ping handler (simple reachability / latency measurement)
|
|
184
|
+
server.setRequestHandler(requestSchema('ping'), async () => {
|
|
185
|
+
if (server.__sawInitializeRequest && server.__initResponseSent && !server.__readyNotified) {
|
|
186
|
+
(0, handshakeManager_1.emitReadyGlobal)(server, 'ping-trigger');
|
|
187
|
+
}
|
|
188
|
+
return { timestamp: new Date().toISOString(), uptimeMs: Math.round(process.uptime() * 1000) };
|
|
189
|
+
});
|
|
190
|
+
return server;
|
|
191
|
+
}
|
|
192
|
+
// Diagnostic accessor tool registered via dynamic side-effect (safe: tiny + read-only)
|
|
193
|
+
try {
|
|
194
|
+
global.__MCP_HANDSHAKE_TRACE_TOOL__ = true;
|
|
195
|
+
}
|
|
196
|
+
catch { /* ignore */ }
|
|
197
|
+
async function startSdkServer() {
|
|
198
|
+
// Lazy dynamic import once (first-call path)
|
|
199
|
+
if (!StdioServerTransport) {
|
|
200
|
+
let modServer, modStdio;
|
|
201
|
+
try {
|
|
202
|
+
modServer = await (0, transportFactory_1.dynamicImport)('@modelcontextprotocol/sdk/server/index.js');
|
|
203
|
+
modStdio = await (0, transportFactory_1.dynamicImport)('@modelcontextprotocol/sdk/server/stdio.js');
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
try {
|
|
207
|
+
process.stderr.write(`[startup] sdk_dynamic_import_failed ${(e instanceof Error) ? e.message : String(e)}\n`);
|
|
208
|
+
}
|
|
209
|
+
catch { /* ignore */ }
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
StdioServerTransport = modStdio?.StdioServerTransport;
|
|
213
|
+
}
|
|
214
|
+
catch { /* ignore */ }
|
|
215
|
+
let server;
|
|
216
|
+
try {
|
|
217
|
+
if (modServer?.Server)
|
|
218
|
+
server = createSdkServer(modServer.Server);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
try {
|
|
222
|
+
process.stderr.write(`[startup] sdk_server_create_failed ${(e instanceof Error) ? e.message : String(e)}\n`);
|
|
223
|
+
}
|
|
224
|
+
catch { /* ignore */ }
|
|
225
|
+
}
|
|
226
|
+
await (0, transportFactory_1.setupStdoutDiagnostics)();
|
|
227
|
+
(0, handshakeManager_1.setupStdinSniffer)(server);
|
|
228
|
+
if (!StdioServerTransport || !server) {
|
|
229
|
+
throw new Error('MCP SDK transport unavailable (removed fallback)');
|
|
230
|
+
}
|
|
231
|
+
(0, transportFactory_1.setupDispatcherOverride)(server);
|
|
232
|
+
const logDiag = (0, runtimeConfig_1.getRuntimeConfig)().logging.diagnostics;
|
|
233
|
+
if (logDiag) {
|
|
234
|
+
try {
|
|
235
|
+
process.stderr.write(`[transport-init] creating StdioServerTransport\n`);
|
|
236
|
+
}
|
|
237
|
+
catch { /* ignore */ }
|
|
238
|
+
}
|
|
239
|
+
const transport = new StdioServerTransport();
|
|
240
|
+
if (logDiag) {
|
|
241
|
+
try {
|
|
242
|
+
process.stderr.write(`[transport-init] connecting transport to server\n`);
|
|
243
|
+
}
|
|
244
|
+
catch { /* ignore */ }
|
|
245
|
+
}
|
|
246
|
+
await server.connect(transport);
|
|
247
|
+
if (logDiag) {
|
|
248
|
+
try {
|
|
249
|
+
const stdinReadable = process.stdin.readable;
|
|
250
|
+
const stdinListenerCount = process.stdin.listenerCount('data');
|
|
251
|
+
process.stderr.write(`[transport-init] transport connected stdin.readable=${stdinReadable} stdin.dataListeners=${stdinListenerCount}\n`);
|
|
252
|
+
}
|
|
253
|
+
catch { /* ignore */ }
|
|
254
|
+
}
|
|
255
|
+
(0, transportFactory_1.setupKeepalive)();
|
|
256
|
+
(0, handshakeManager_1.setupSafetyFallbacks)(server);
|
|
257
|
+
(0, transportFactory_1.wrapTransportSend)(server, transport);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
// Secondary path: StdioServerTransport already loaded
|
|
261
|
+
const modServer = await (0, transportFactory_1.dynamicImport)('@modelcontextprotocol/sdk/server/index.js');
|
|
262
|
+
const server = createSdkServer(modServer.Server);
|
|
263
|
+
const logDiag2 = (0, runtimeConfig_1.getRuntimeConfig)().logging.diagnostics;
|
|
264
|
+
if (logDiag2) {
|
|
265
|
+
try {
|
|
266
|
+
process.stderr.write(`[transport-init] (secondary) creating StdioServerTransport\n`);
|
|
267
|
+
}
|
|
268
|
+
catch { /* ignore */ }
|
|
269
|
+
}
|
|
270
|
+
const transport = new StdioServerTransport();
|
|
271
|
+
if (logDiag2) {
|
|
272
|
+
try {
|
|
273
|
+
process.stderr.write(`[transport-init] (secondary) connecting transport to server\n`);
|
|
274
|
+
}
|
|
275
|
+
catch { /* ignore */ }
|
|
276
|
+
}
|
|
277
|
+
await server.connect(transport);
|
|
278
|
+
if (logDiag2) {
|
|
279
|
+
try {
|
|
280
|
+
const stdinReadable = process.stdin.readable;
|
|
281
|
+
const stdinListenerCount = process.stdin.listenerCount('data');
|
|
282
|
+
process.stderr.write(`[transport-init] (secondary) transport connected stdin.readable=${stdinReadable} stdin.dataListeners=${stdinListenerCount}\n`);
|
|
283
|
+
}
|
|
284
|
+
catch { /* ignore */ }
|
|
285
|
+
}
|
|
286
|
+
(0, transportFactory_1.setupKeepalive)('secondary');
|
|
287
|
+
// Safety fallback timer (mirrors dynamic path) for missed ready emission
|
|
288
|
+
if ((0, handshakeManager_1.isHandshakeFallbacksEnabled)()) {
|
|
289
|
+
setTimeout(() => {
|
|
290
|
+
try {
|
|
291
|
+
if (server.__sawInitializeRequest && !server.__readyNotified) {
|
|
292
|
+
(0, handshakeManager_1.handshakeLog)('safety_timeout_emit_attempt', { label: 'safety-timeout-100ms-secondary', sawInit: true, initRespSent: !!server.__initResponseSent });
|
|
293
|
+
(0, handshakeManager_1.emitReadyGlobal)(server, 'safety-timeout-100ms-secondary');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
catch { /* ignore */ }
|
|
297
|
+
}, 100).unref?.();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shutdown Guard — Consolidates all process exit handling into a single
|
|
3
|
+
* re-entrance-guarded shutdown path.
|
|
4
|
+
*
|
|
5
|
+
* Fixes: GitHub Issue #36 — Multiple process.exit() race in shutdown paths
|
|
6
|
+
*
|
|
7
|
+
* Instead of SIGINT/SIGTERM/uncaughtException each independently calling
|
|
8
|
+
* process.exit(), all paths funnel through initiateShutdown() which:
|
|
9
|
+
* 1. Sets a guard flag to prevent re-entrance
|
|
10
|
+
* 2. Runs all registered cleanup handlers (with error isolation)
|
|
11
|
+
* 3. Returns the appropriate exit code
|
|
12
|
+
*/
|
|
13
|
+
export interface ShutdownGuard {
|
|
14
|
+
/**
|
|
15
|
+
* Register a named cleanup handler to run during shutdown.
|
|
16
|
+
* @param name - Unique identifier for this cleanup handler
|
|
17
|
+
* @param handler - Function to invoke during shutdown; errors are caught and logged
|
|
18
|
+
*/
|
|
19
|
+
registerCleanup(name: string, handler: () => void): void;
|
|
20
|
+
/**
|
|
21
|
+
* Remove a previously registered cleanup handler.
|
|
22
|
+
* @param name - Identifier of the handler to remove
|
|
23
|
+
*/
|
|
24
|
+
deregisterCleanup(name: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Initiate shutdown — only executes cleanup once (re-entrant calls return early).
|
|
27
|
+
* @param reason - Reason string; `'uncaughtException'` maps to exit code 1, all others to 0
|
|
28
|
+
* @returns The process exit code that callers should pass to `process.exit()`
|
|
29
|
+
*/
|
|
30
|
+
initiateShutdown(reason: string): number;
|
|
31
|
+
/**
|
|
32
|
+
* Check if shutdown has been initiated.
|
|
33
|
+
* @returns `true` once {@link initiateShutdown} has been called
|
|
34
|
+
*/
|
|
35
|
+
isShuttingDown(): boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a new shutdown guard that consolidates all process exit paths into a single re-entrance-safe flow.
|
|
39
|
+
* @returns A {@link ShutdownGuard} instance with `registerCleanup`, `deregisterCleanup`, `initiateShutdown`, and `isShuttingDown` methods
|
|
40
|
+
*/
|
|
41
|
+
export declare function createShutdownGuard(): ShutdownGuard;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shutdown Guard — Consolidates all process exit handling into a single
|
|
4
|
+
* re-entrance-guarded shutdown path.
|
|
5
|
+
*
|
|
6
|
+
* Fixes: GitHub Issue #36 — Multiple process.exit() race in shutdown paths
|
|
7
|
+
*
|
|
8
|
+
* Instead of SIGINT/SIGTERM/uncaughtException each independently calling
|
|
9
|
+
* process.exit(), all paths funnel through initiateShutdown() which:
|
|
10
|
+
* 1. Sets a guard flag to prevent re-entrance
|
|
11
|
+
* 2. Runs all registered cleanup handlers (with error isolation)
|
|
12
|
+
* 3. Returns the appropriate exit code
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.createShutdownGuard = createShutdownGuard;
|
|
16
|
+
/**
|
|
17
|
+
* Create a new shutdown guard that consolidates all process exit paths into a single re-entrance-safe flow.
|
|
18
|
+
* @returns A {@link ShutdownGuard} instance with `registerCleanup`, `deregisterCleanup`, `initiateShutdown`, and `isShuttingDown` methods
|
|
19
|
+
*/
|
|
20
|
+
function createShutdownGuard() {
|
|
21
|
+
let shuttingDown = false;
|
|
22
|
+
const cleanupHandlers = new Map();
|
|
23
|
+
return {
|
|
24
|
+
registerCleanup(name, handler) {
|
|
25
|
+
cleanupHandlers.set(name, handler);
|
|
26
|
+
},
|
|
27
|
+
deregisterCleanup(name) {
|
|
28
|
+
cleanupHandlers.delete(name);
|
|
29
|
+
},
|
|
30
|
+
initiateShutdown(reason) {
|
|
31
|
+
const exitCode = reason === 'uncaughtException' ? 1 : 0;
|
|
32
|
+
if (shuttingDown)
|
|
33
|
+
return exitCode;
|
|
34
|
+
shuttingDown = true;
|
|
35
|
+
for (const [name, handler] of cleanupHandlers) {
|
|
36
|
+
try {
|
|
37
|
+
handler();
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
try {
|
|
41
|
+
process.stderr.write(`[shutdown] cleanup handler "${name}" failed: ${err}\n`);
|
|
42
|
+
}
|
|
43
|
+
catch { /* ignore */ }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return exitCode;
|
|
47
|
+
},
|
|
48
|
+
isShuttingDown() {
|
|
49
|
+
return shuttingDown;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|