@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,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
|
+
}
|