@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,268 @@
|
|
|
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.logError = exports.logWarn = exports.logInfo = exports.logDebug = exports.logTrace = void 0;
|
|
7
|
+
exports.newCorrelationId = newCorrelationId;
|
|
8
|
+
exports.log = log;
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
13
|
+
/** Numeric priority for log level filtering (lower = more verbose). */
|
|
14
|
+
const LEVEL_PRIORITY = {
|
|
15
|
+
TRACE: 0,
|
|
16
|
+
DEBUG: 1,
|
|
17
|
+
INFO: 2,
|
|
18
|
+
WARN: 3,
|
|
19
|
+
ERROR: 4,
|
|
20
|
+
};
|
|
21
|
+
// Simple correlation id helper (call per incoming JSON-RPC if desired)
|
|
22
|
+
/**
|
|
23
|
+
* Generate a new random correlation ID (16 hex characters).
|
|
24
|
+
* @returns Hex string suitable for tagging a single request context
|
|
25
|
+
*/
|
|
26
|
+
function newCorrelationId() { return crypto_1.default.randomBytes(8).toString('hex'); }
|
|
27
|
+
let logFileHandle = null;
|
|
28
|
+
function loggingCfg() {
|
|
29
|
+
return (0, runtimeConfig_1.getRuntimeConfig)().logging;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Capture V8 call-site stack trace, omitting the logger internals.
|
|
33
|
+
* Used on WARN/ERROR to populate the `detail` field for Error Trace Flow.
|
|
34
|
+
*/
|
|
35
|
+
function captureCallStack(omitFrames) {
|
|
36
|
+
const obj = {};
|
|
37
|
+
Error.captureStackTrace(obj, omitFrames);
|
|
38
|
+
return obj.stack;
|
|
39
|
+
}
|
|
40
|
+
/** Serialize a detail value to a string for the NDJSON detail field. */
|
|
41
|
+
function serializeDetail(detail) {
|
|
42
|
+
if (detail === undefined || detail === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
if (detail instanceof Error)
|
|
45
|
+
return detail.stack ?? detail.message;
|
|
46
|
+
if (typeof detail === 'string')
|
|
47
|
+
return detail;
|
|
48
|
+
return JSON.stringify(detail);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check whether the given log level passes the configured minimum level.
|
|
52
|
+
* Returns true if the record should be emitted, false if suppressed.
|
|
53
|
+
*/
|
|
54
|
+
function shouldEmit(level) {
|
|
55
|
+
const cfg = loggingCfg();
|
|
56
|
+
const cfgLevel = cfg.level?.toUpperCase() ?? 'INFO';
|
|
57
|
+
const threshold = LEVEL_PRIORITY[cfgLevel] ?? LEVEL_PRIORITY.INFO;
|
|
58
|
+
const recordPriority = LEVEL_PRIORITY[level] ?? LEVEL_PRIORITY.INFO;
|
|
59
|
+
return recordPriority >= threshold;
|
|
60
|
+
}
|
|
61
|
+
// Initialize file logging if INDEX_SERVER_LOG_FILE is specified
|
|
62
|
+
function initializeFileLogging() {
|
|
63
|
+
const cfg = loggingCfg();
|
|
64
|
+
const logFile = cfg.file;
|
|
65
|
+
if (!logFile || logFileHandle)
|
|
66
|
+
return; // Already initialized or not requested
|
|
67
|
+
try {
|
|
68
|
+
// Ensure log directory exists
|
|
69
|
+
const logDir = path_1.default.dirname(logFile);
|
|
70
|
+
if (!fs_1.default.existsSync(logDir)) {
|
|
71
|
+
fs_1.default.mkdirSync(logDir, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
// Create write stream with append mode
|
|
74
|
+
logFileHandle = fs_1.default.createWriteStream(logFile, {
|
|
75
|
+
flags: 'a',
|
|
76
|
+
encoding: 'utf8'
|
|
77
|
+
});
|
|
78
|
+
// NDJSON session start record
|
|
79
|
+
const sessionStart = {
|
|
80
|
+
ts: new Date().toISOString(),
|
|
81
|
+
level: 'INFO',
|
|
82
|
+
msg: '[logger] Session started',
|
|
83
|
+
pid: process.pid,
|
|
84
|
+
};
|
|
85
|
+
const startLine = JSON.stringify(sessionStart);
|
|
86
|
+
logFileHandle.write(startLine + '\n');
|
|
87
|
+
// Cleanup on process exit
|
|
88
|
+
process.on('exit', () => {
|
|
89
|
+
if (logFileHandle && !logFileHandle.destroyed) {
|
|
90
|
+
const sessionEnd = {
|
|
91
|
+
ts: new Date().toISOString(),
|
|
92
|
+
level: 'INFO',
|
|
93
|
+
msg: '[logger] Session ended',
|
|
94
|
+
pid: process.pid,
|
|
95
|
+
};
|
|
96
|
+
logFileHandle.write(JSON.stringify(sessionEnd) + '\n');
|
|
97
|
+
logFileHandle.end();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
// Emit NDJSON init diagnostic
|
|
101
|
+
try {
|
|
102
|
+
const stats = fs_1.default.existsSync(logFile) ? fs_1.default.statSync(logFile) : null;
|
|
103
|
+
const diag = {
|
|
104
|
+
ts: new Date().toISOString(),
|
|
105
|
+
level: 'INFO',
|
|
106
|
+
msg: '[logger] File logging enabled',
|
|
107
|
+
pid: process.pid,
|
|
108
|
+
detail: JSON.stringify({
|
|
109
|
+
file: logFile,
|
|
110
|
+
size: stats?.size ?? 0,
|
|
111
|
+
sentinel: cfg.sentinelRequested,
|
|
112
|
+
cwd: process.cwd(),
|
|
113
|
+
}),
|
|
114
|
+
};
|
|
115
|
+
const line = JSON.stringify(diag);
|
|
116
|
+
console.error(line);
|
|
117
|
+
if (logFileHandle && !logFileHandle.destroyed) {
|
|
118
|
+
try {
|
|
119
|
+
logFileHandle.write(line + '\n');
|
|
120
|
+
}
|
|
121
|
+
catch { /* ignore */ }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch { /* ignore diagnostics error */ }
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
// Fallback to NDJSON on stderr if file logging fails
|
|
128
|
+
console.error(JSON.stringify({
|
|
129
|
+
ts: new Date().toISOString(),
|
|
130
|
+
level: 'ERROR',
|
|
131
|
+
msg: '[logger] Failed to initialize file logging',
|
|
132
|
+
detail: String(error),
|
|
133
|
+
pid: process.pid,
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Eager initialization: if user supplied a sentinel value ('1', 'true', etc.)
|
|
138
|
+
// we create the log file immediately so external components (dashboard log
|
|
139
|
+
// viewer polling /api/logs) see the file even before the first structured
|
|
140
|
+
// log line is emitted. Without this, very early polling could race the first
|
|
141
|
+
// emit() call and incorrectly report "no log file". Normal explicit paths
|
|
142
|
+
// remain lazy to avoid unnecessary fd usage when logger never used.
|
|
143
|
+
try {
|
|
144
|
+
const cfg = loggingCfg();
|
|
145
|
+
if (cfg.file && cfg.sentinelRequested) {
|
|
146
|
+
initializeFileLogging();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch { /* ignore eager init errors */ }
|
|
150
|
+
function emit(rec) {
|
|
151
|
+
// Level filtering — suppress records below configured threshold
|
|
152
|
+
if (!shouldEmit(rec.level))
|
|
153
|
+
return;
|
|
154
|
+
// Initialize file logging on first emit (lazy initialization)
|
|
155
|
+
const cfg = loggingCfg();
|
|
156
|
+
if (!logFileHandle && cfg.file) {
|
|
157
|
+
initializeFileLogging();
|
|
158
|
+
}
|
|
159
|
+
// Always include pid for multi-process identification
|
|
160
|
+
if (rec.pid === undefined)
|
|
161
|
+
rec.pid = process.pid;
|
|
162
|
+
// Always NDJSON — no plain-text path
|
|
163
|
+
const out = {
|
|
164
|
+
ts: rec.ts,
|
|
165
|
+
level: rec.level,
|
|
166
|
+
msg: rec.msg,
|
|
167
|
+
};
|
|
168
|
+
if (rec.detail)
|
|
169
|
+
out.detail = rec.detail;
|
|
170
|
+
if (rec.tool)
|
|
171
|
+
out.tool = rec.tool;
|
|
172
|
+
if (rec.ms !== undefined)
|
|
173
|
+
out.ms = rec.ms;
|
|
174
|
+
out.pid = rec.pid;
|
|
175
|
+
if (rec.port)
|
|
176
|
+
out.port = rec.port;
|
|
177
|
+
if (rec.correlationId)
|
|
178
|
+
out.correlationId = rec.correlationId;
|
|
179
|
+
const logLine = JSON.stringify(out);
|
|
180
|
+
// Always log to stderr for VS Code output panel
|
|
181
|
+
console.error(logLine);
|
|
182
|
+
// Also log to file if configured and available
|
|
183
|
+
if (logFileHandle && !logFileHandle.destroyed) {
|
|
184
|
+
try {
|
|
185
|
+
logFileHandle.write(logLine + '\n');
|
|
186
|
+
// Optional deterministic flushing for tests / critical observability. Enabled with INDEX_SERVER_LOG_SYNC=1
|
|
187
|
+
if (cfg.sync) {
|
|
188
|
+
try {
|
|
189
|
+
fs_1.default.fsyncSync(logFileHandle.fd);
|
|
190
|
+
}
|
|
191
|
+
catch { /* ignore fsync errors */ }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch { /* ignore file write failures */ }
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Emit a structured NDJSON log record at the specified level.
|
|
199
|
+
* @param level - TRACE | DEBUG | INFO | WARN | ERROR
|
|
200
|
+
* @param msg - Message with [module] prefix for heatmap matching
|
|
201
|
+
* @param fields - Additional fields (detail, tool, ms, correlationId, etc.)
|
|
202
|
+
*/
|
|
203
|
+
function log(level, msg, fields = {}) {
|
|
204
|
+
emit({ ts: new Date().toISOString(), level, msg, ...fields });
|
|
205
|
+
}
|
|
206
|
+
/** TRACE — function entry/exit tracing and low-level diagnostics.
|
|
207
|
+
* Use `→ Class.method` / `← Class.method` prefixes for call graph support.
|
|
208
|
+
* @param msg - Message (use → / ← prefixes for function tracing)
|
|
209
|
+
* @param detail - Optional data serialized into the detail field
|
|
210
|
+
*/
|
|
211
|
+
const logTrace = (msg, detail) => {
|
|
212
|
+
log('TRACE', msg, { detail: serializeDetail(detail) });
|
|
213
|
+
};
|
|
214
|
+
exports.logTrace = logTrace;
|
|
215
|
+
/** DEBUG — diagnostic information for development.
|
|
216
|
+
* @param msg - Message with [module] prefix
|
|
217
|
+
* @param detail - Optional data serialized into the detail field
|
|
218
|
+
*/
|
|
219
|
+
const logDebug = (msg, detail) => {
|
|
220
|
+
log('DEBUG', msg, { detail: serializeDetail(detail) });
|
|
221
|
+
};
|
|
222
|
+
exports.logDebug = logDebug;
|
|
223
|
+
/** INFO — normal operational events.
|
|
224
|
+
* @param msg - Message with [module] prefix
|
|
225
|
+
* @param detail - Optional data serialized into the detail field
|
|
226
|
+
*/
|
|
227
|
+
const logInfo = (msg, detail) => {
|
|
228
|
+
log('INFO', msg, { detail: serializeDetail(detail) });
|
|
229
|
+
};
|
|
230
|
+
exports.logInfo = logInfo;
|
|
231
|
+
/** WARN — potential issues. Captures V8 call-site stack into detail for Error Trace Flow.
|
|
232
|
+
* Error instances use their own stack; non-Error detail is serialized with call-site stack appended.
|
|
233
|
+
* @param msg - Message with [module] prefix
|
|
234
|
+
* @param detail - Optional Error, string, or data; Error.stack or V8 call-site stack used
|
|
235
|
+
*/
|
|
236
|
+
const logWarn = (msg, detail) => {
|
|
237
|
+
let d;
|
|
238
|
+
if (detail instanceof Error) {
|
|
239
|
+
d = detail.stack;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const stack = captureCallStack(exports.logWarn);
|
|
243
|
+
d = detail !== undefined
|
|
244
|
+
? serializeDetail(detail) + (stack ? '\n' + stack : '')
|
|
245
|
+
: stack;
|
|
246
|
+
}
|
|
247
|
+
log('WARN', msg, { detail: d });
|
|
248
|
+
};
|
|
249
|
+
exports.logWarn = logWarn;
|
|
250
|
+
/** ERROR — failures. Captures V8 call-site stack into detail for Error Trace Flow.
|
|
251
|
+
* Error instances use their own stack; non-Error detail is serialized with call-site stack appended.
|
|
252
|
+
* @param msg - Message with [module] prefix
|
|
253
|
+
* @param detail - Optional Error, string, or data; Error.stack or V8 call-site stack used
|
|
254
|
+
*/
|
|
255
|
+
const logError = (msg, detail) => {
|
|
256
|
+
let d;
|
|
257
|
+
if (detail instanceof Error) {
|
|
258
|
+
d = detail.stack;
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
const stack = captureCallStack(exports.logError);
|
|
262
|
+
d = detail !== undefined
|
|
263
|
+
? serializeDetail(detail) + (stack ? '\n' + stack : '')
|
|
264
|
+
: stack;
|
|
265
|
+
}
|
|
266
|
+
log('ERROR', msg, { detail: d });
|
|
267
|
+
};
|
|
268
|
+
exports.logError = logError;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime manifest management.
|
|
3
|
+
* Format (version 1):
|
|
4
|
+
* {
|
|
5
|
+
* version: 1,
|
|
6
|
+
* generatedAt: ISO string,
|
|
7
|
+
* count: number,
|
|
8
|
+
* entries: [ { id, sourceHash, bodyHash } ]
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* Design notes:
|
|
12
|
+
* - We intentionally keep entries minimal (id + hashes) to reduce churn risk.
|
|
13
|
+
* - Recomputing the manifest from the in‑memory index after a mutation is O(N) and
|
|
14
|
+
* acceptable for current index sizes (< few hundred). This favors simplicity & correctness
|
|
15
|
+
* over incremental append complexity (which can be added later if needed).
|
|
16
|
+
* - Atomicity: write to tmp then rename to avoid partial file visibility.
|
|
17
|
+
*
|
|
18
|
+
* Phase F (simplification):
|
|
19
|
+
* - Removed debounce / max-delay scheduling. Writes are now synchronous & deterministic.
|
|
20
|
+
* - Added no-op short circuit: if projected manifest JSON unchanged, skip write.
|
|
21
|
+
* - attemptManifestUpdate() is now a thin alias of scheduleManifestUpdate() which performs
|
|
22
|
+
* immediate write (naming preserved for backward compatibility with existing call sites).
|
|
23
|
+
*/
|
|
24
|
+
export interface ManifestEntry {
|
|
25
|
+
id: string;
|
|
26
|
+
sourceHash?: string;
|
|
27
|
+
bodyHash?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface IndexManifest {
|
|
30
|
+
$schema?: string;
|
|
31
|
+
version: 1;
|
|
32
|
+
generatedAt: string;
|
|
33
|
+
count: number;
|
|
34
|
+
entries: ManifestEntry[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Load the manifest from disk.
|
|
38
|
+
* @returns The parsed {@link IndexManifest}, or `null` if the file is absent or unparseable
|
|
39
|
+
*/
|
|
40
|
+
export declare function loadManifest(): IndexManifest | null;
|
|
41
|
+
/**
|
|
42
|
+
* Write a fresh manifest reflecting the current in-memory index state.
|
|
43
|
+
* Skips the write when the content is unchanged (stable `generatedAt` semantics).
|
|
44
|
+
* No-op when `INDEX_SERVER_MANIFEST_WRITE=0`.
|
|
45
|
+
* @returns The computed {@link IndexManifest}, or `null` when writing is disabled
|
|
46
|
+
*/
|
|
47
|
+
export declare function writeManifestFromIndex(): IndexManifest | null;
|
|
48
|
+
export interface DriftDetail {
|
|
49
|
+
id: string;
|
|
50
|
+
change: 'added' | 'removed' | 'hash-mismatch';
|
|
51
|
+
}
|
|
52
|
+
export interface ManifestDriftReport {
|
|
53
|
+
present: boolean;
|
|
54
|
+
drift: number;
|
|
55
|
+
details: DriftDetail[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Compare the on-disk manifest against the live in-memory index and report any drift.
|
|
59
|
+
* @returns A {@link ManifestDriftReport} describing added, removed, or hash-mismatched entries
|
|
60
|
+
*/
|
|
61
|
+
export declare function computeManifestDrift(): ManifestDriftReport;
|
|
62
|
+
/**
|
|
63
|
+
* Repair the manifest by rewriting it from the current in-memory index when drift is detected.
|
|
64
|
+
* @returns Object with `repaired` flag and drift counts before and after repair
|
|
65
|
+
*/
|
|
66
|
+
export declare function repairManifest(): {
|
|
67
|
+
repaired: boolean;
|
|
68
|
+
driftBefore: number;
|
|
69
|
+
driftAfter: number;
|
|
70
|
+
};
|
|
71
|
+
/** Synchronously write the manifest from the current in-memory index state. */
|
|
72
|
+
export declare function scheduleManifestUpdate(): void;
|
|
73
|
+
/** Alias for {@link scheduleManifestUpdate}; called after any index mutation. */
|
|
74
|
+
export declare function onIndexMutationManifestUpdate(): void;
|
|
75
|
+
/** Conditionally write the manifest; only executes when `INDEX_SERVER_MANIFEST_WRITE=1`. */
|
|
76
|
+
export declare function attemptManifestUpdate(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Check whether manifest fast-load mode is active (`INDEX_SERVER_MANIFEST_FASTLOAD=1`).
|
|
79
|
+
* In fast-load mode, drift detection skips per-entry hash comparison when entry counts match.
|
|
80
|
+
* @returns `true` when fast-load is enabled
|
|
81
|
+
*/
|
|
82
|
+
export declare function manifestFastLoadEnabled(): boolean;
|
|
@@ -0,0 +1,200 @@
|
|
|
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.loadManifest = loadManifest;
|
|
7
|
+
exports.writeManifestFromIndex = writeManifestFromIndex;
|
|
8
|
+
exports.computeManifestDrift = computeManifestDrift;
|
|
9
|
+
exports.repairManifest = repairManifest;
|
|
10
|
+
exports.scheduleManifestUpdate = scheduleManifestUpdate;
|
|
11
|
+
exports.onIndexMutationManifestUpdate = onIndexMutationManifestUpdate;
|
|
12
|
+
exports.attemptManifestUpdate = attemptManifestUpdate;
|
|
13
|
+
exports.manifestFastLoadEnabled = manifestFastLoadEnabled;
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
17
|
+
const indexContext_1 = require("./indexContext");
|
|
18
|
+
const tracing_1 = require("./tracing");
|
|
19
|
+
const features_1 = require("./features");
|
|
20
|
+
const logger_1 = require("./logger");
|
|
21
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
22
|
+
const MANIFEST_RELATIVE = path_1.default.join('snapshots', 'index-manifest.json');
|
|
23
|
+
function getManifestPath() { return path_1.default.join(process.cwd(), MANIFEST_RELATIVE); }
|
|
24
|
+
/**
|
|
25
|
+
* Load the manifest from disk.
|
|
26
|
+
* @returns The parsed {@link IndexManifest}, or `null` if the file is absent or unparseable
|
|
27
|
+
*/
|
|
28
|
+
function loadManifest() {
|
|
29
|
+
const fp = getManifestPath();
|
|
30
|
+
try {
|
|
31
|
+
if (!fs_1.default.existsSync(fp))
|
|
32
|
+
return null;
|
|
33
|
+
const data = JSON.parse(fs_1.default.readFileSync(fp, 'utf8'));
|
|
34
|
+
if (data && data.version === 1 && Array.isArray(data.entries))
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
catch { /* ignore */ }
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Write a fresh manifest reflecting the current in-memory index state.
|
|
42
|
+
* Skips the write when the content is unchanged (stable `generatedAt` semantics).
|
|
43
|
+
* No-op when `INDEX_SERVER_MANIFEST_WRITE=0`.
|
|
44
|
+
* @returns The computed {@link IndexManifest}, or `null` when writing is disabled
|
|
45
|
+
*/
|
|
46
|
+
function writeManifestFromIndex() {
|
|
47
|
+
if (!(0, runtimeConfig_1.getRuntimeConfig)().instructions.manifest.writeEnabled)
|
|
48
|
+
return null; // feature disabled
|
|
49
|
+
const started = Date.now();
|
|
50
|
+
const st = (0, indexContext_1.ensureLoaded)();
|
|
51
|
+
const entries = st.list.map(e => ({
|
|
52
|
+
id: e.id,
|
|
53
|
+
sourceHash: e.sourceHash,
|
|
54
|
+
bodyHash: crypto_1.default.createHash('sha256').update(e.body || '', 'utf8').digest('hex')
|
|
55
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
56
|
+
// We perform a two-phase write to enable generatedAt stability on no-op content:
|
|
57
|
+
// 1. Build a draft manifest with a placeholder timestamp.
|
|
58
|
+
// 2. If existing file content (ignoring generatedAt) is identical, we reuse the prior generatedAt
|
|
59
|
+
// so downstream processes observing timestamp do not treat the manifest as changed.
|
|
60
|
+
const draftGeneratedAt = new Date().toISOString();
|
|
61
|
+
let previousParsed = null;
|
|
62
|
+
const fp = getManifestPath();
|
|
63
|
+
if (fs_1.default.existsSync(fp)) {
|
|
64
|
+
try {
|
|
65
|
+
previousParsed = JSON.parse(fs_1.default.readFileSync(fp, 'utf8'));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
previousParsed = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const manifest = {
|
|
72
|
+
$schema: '../schemas/manifest.schema.json',
|
|
73
|
+
version: 1,
|
|
74
|
+
generatedAt: draftGeneratedAt,
|
|
75
|
+
count: entries.length,
|
|
76
|
+
entries
|
|
77
|
+
};
|
|
78
|
+
// If previous manifest exists and structural content (excluding generatedAt) matches, reuse old timestamp.
|
|
79
|
+
if (previousParsed) {
|
|
80
|
+
try {
|
|
81
|
+
const prevComparable = { ...previousParsed, generatedAt: undefined };
|
|
82
|
+
const nextComparable = { ...manifest, generatedAt: undefined };
|
|
83
|
+
if (JSON.stringify(prevComparable) === JSON.stringify(nextComparable)) {
|
|
84
|
+
// Reuse timestamp to provide full stability rather than rewriting with new time.
|
|
85
|
+
manifest.generatedAt = previousParsed.generatedAt;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch { /* ignore comparison errors */ }
|
|
89
|
+
}
|
|
90
|
+
// fp already declared above
|
|
91
|
+
try {
|
|
92
|
+
const dir = path_1.default.dirname(fp);
|
|
93
|
+
if (!fs_1.default.existsSync(dir))
|
|
94
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
95
|
+
// No-op short circuit: if existing manifest content is byte-identical we skip write.
|
|
96
|
+
let previous;
|
|
97
|
+
if (fs_1.default.existsSync(fp)) {
|
|
98
|
+
try {
|
|
99
|
+
previous = fs_1.default.readFileSync(fp, 'utf8');
|
|
100
|
+
}
|
|
101
|
+
catch { /* ignore */ }
|
|
102
|
+
}
|
|
103
|
+
const nextJson = JSON.stringify(manifest, null, 2);
|
|
104
|
+
if (previous && previous === nextJson) {
|
|
105
|
+
(0, features_1.incrementCounter)('manifest:skipNoChange');
|
|
106
|
+
if ((0, tracing_1.traceEnabled)(2))
|
|
107
|
+
(0, tracing_1.emitTrace)('[trace:manifest:skip-nochange]', { count: manifest.count });
|
|
108
|
+
return manifest; // treat as success (hash stable)
|
|
109
|
+
}
|
|
110
|
+
const tmp = fp + '.tmp';
|
|
111
|
+
fs_1.default.writeFileSync(tmp, nextJson);
|
|
112
|
+
fs_1.default.renameSync(tmp, fp);
|
|
113
|
+
(0, features_1.incrementCounter)('manifest:write');
|
|
114
|
+
(0, logger_1.logInfo)(`[manifest] wrote index-manifest.json count=${manifest.count} ms=${Date.now() - started}`);
|
|
115
|
+
if ((0, tracing_1.traceEnabled)(1))
|
|
116
|
+
(0, tracing_1.emitTrace)('[trace:manifest:write]', { count: manifest.count, ms: Date.now() - started, path: fp });
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
(0, features_1.incrementCounter)('manifest:writeFailed');
|
|
120
|
+
(0, logger_1.logWarn)('[manifest] write failed', err);
|
|
121
|
+
if ((0, tracing_1.traceEnabled)(1))
|
|
122
|
+
(0, tracing_1.emitTrace)('[trace:manifest:write-error]', { error: err.message });
|
|
123
|
+
}
|
|
124
|
+
return manifest;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Compare the on-disk manifest against the live in-memory index and report any drift.
|
|
128
|
+
* @returns A {@link ManifestDriftReport} describing added, removed, or hash-mismatched entries
|
|
129
|
+
*/
|
|
130
|
+
function computeManifestDrift() {
|
|
131
|
+
const st = (0, indexContext_1.ensureLoaded)();
|
|
132
|
+
const manifest = loadManifest();
|
|
133
|
+
if (!manifest)
|
|
134
|
+
return { present: false, drift: st.list.length ? st.list.length : 0, details: st.list.map(e => ({ id: e.id, change: 'added' })) };
|
|
135
|
+
// FASTLOAD SHORTCUT: if enabled and counts match we trust the manifest without recomputing hashes.
|
|
136
|
+
// Rationale: On typical startup we only need to know "is there obvious drift?" to skip O(N) hashing.
|
|
137
|
+
// If a subsequent mutation occurs we will rewrite manifest anyway. Safety: if counts differ we fall through
|
|
138
|
+
// to full verification.
|
|
139
|
+
const fastEnabled = manifestFastLoadEnabled();
|
|
140
|
+
if (fastEnabled && manifest.count === st.list.length) {
|
|
141
|
+
if ((0, tracing_1.traceEnabled)(2))
|
|
142
|
+
(0, tracing_1.emitTrace)('[trace:manifest:fastload]', { count: st.list.length });
|
|
143
|
+
return { present: true, drift: 0, details: [] };
|
|
144
|
+
}
|
|
145
|
+
const map = new Map(manifest.entries.map(e => [e.id, e]));
|
|
146
|
+
const details = [];
|
|
147
|
+
for (const e of st.list) {
|
|
148
|
+
const m = map.get(e.id);
|
|
149
|
+
const bodyHash = crypto_1.default.createHash('sha256').update(e.body || '', 'utf8').digest('hex');
|
|
150
|
+
if (!m)
|
|
151
|
+
details.push({ id: e.id, change: 'added' });
|
|
152
|
+
else if (m.sourceHash !== e.sourceHash || m.bodyHash !== bodyHash)
|
|
153
|
+
details.push({ id: e.id, change: 'hash-mismatch' });
|
|
154
|
+
}
|
|
155
|
+
for (const id of map.keys()) {
|
|
156
|
+
if (!st.byId.has(id))
|
|
157
|
+
details.push({ id, change: 'removed' });
|
|
158
|
+
}
|
|
159
|
+
const report = { present: true, drift: details.length, details };
|
|
160
|
+
if ((0, tracing_1.traceEnabled)(1))
|
|
161
|
+
(0, tracing_1.emitTrace)('[trace:manifest:drift]', { drift: report.drift, added: report.details.filter(d => d.change === 'added').length, removed: report.details.filter(d => d.change === 'removed').length, mismatch: report.details.filter(d => d.change === 'hash-mismatch').length, count: st.list.length, manifestCount: manifest.count });
|
|
162
|
+
return report;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Repair the manifest by rewriting it from the current in-memory index when drift is detected.
|
|
166
|
+
* @returns Object with `repaired` flag and drift counts before and after repair
|
|
167
|
+
*/
|
|
168
|
+
function repairManifest() {
|
|
169
|
+
const before = computeManifestDrift();
|
|
170
|
+
if (before.drift === 0) {
|
|
171
|
+
return { repaired: false, driftBefore: 0, driftAfter: 0 };
|
|
172
|
+
}
|
|
173
|
+
writeManifestFromIndex();
|
|
174
|
+
const after = computeManifestDrift();
|
|
175
|
+
if ((0, tracing_1.traceEnabled)(1))
|
|
176
|
+
(0, tracing_1.emitTrace)('[trace:manifest:repair]', { driftBefore: before.drift, driftAfter: after.drift });
|
|
177
|
+
return { repaired: true, driftBefore: before.drift, driftAfter: after.drift };
|
|
178
|
+
}
|
|
179
|
+
// Phase F: simplified scheduling; we keep exported names for backward compatibility.
|
|
180
|
+
/** Synchronously write the manifest from the current in-memory index state. */
|
|
181
|
+
function scheduleManifestUpdate() {
|
|
182
|
+
// Single synchronous write (fast for current index sizes). Future high-churn mode could reintroduce batching behind env flag.
|
|
183
|
+
writeManifestFromIndex();
|
|
184
|
+
}
|
|
185
|
+
/** Alias for {@link scheduleManifestUpdate}; called after any index mutation. */
|
|
186
|
+
function onIndexMutationManifestUpdate() { scheduleManifestUpdate(); }
|
|
187
|
+
// attemptManifestUpdate previously always invoked a write regardless of the INDEX_SERVER_MANIFEST_WRITE flag
|
|
188
|
+
// which caused tests expecting stability under INDEX_SERVER_MANIFEST_WRITE=0 to observe a timestamp change.
|
|
189
|
+
// We now explicitly no-op unless write mode is enabled, making "attempt" semantics truly conditional.
|
|
190
|
+
/** Conditionally write the manifest; only executes when `INDEX_SERVER_MANIFEST_WRITE=1`. */
|
|
191
|
+
function attemptManifestUpdate() {
|
|
192
|
+
if ((0, runtimeConfig_1.getRuntimeConfig)().instructions.manifest.writeEnabled)
|
|
193
|
+
scheduleManifestUpdate();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Check whether manifest fast-load mode is active (`INDEX_SERVER_MANIFEST_FASTLOAD=1`).
|
|
197
|
+
* In fast-load mode, drift detection skips per-entry hash comparison when entry counts match.
|
|
198
|
+
* @returns `true` when fast-load is enabled
|
|
199
|
+
*/
|
|
200
|
+
function manifestFastLoadEnabled() { return (0, runtimeConfig_1.getRuntimeConfig)().instructions.manifest.fastload; }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type AgentMessage, type SendMessageOptions, type ReadMessagesOptions, type ChannelInfo, type MessagingStats } from './messagingTypes';
|
|
2
|
+
import type { MessagingConfig } from '../../config/runtimeConfig';
|
|
3
|
+
export declare class AgentMailbox {
|
|
4
|
+
private readonly store;
|
|
5
|
+
private readonly idIndex;
|
|
6
|
+
private readonly config;
|
|
7
|
+
private sweepTimer;
|
|
8
|
+
private loaded;
|
|
9
|
+
constructor(config: MessagingConfig);
|
|
10
|
+
/** Load messages from disk if not already loaded. */
|
|
11
|
+
ensureLoaded(): void;
|
|
12
|
+
/** Send a message. Returns the message ID. */
|
|
13
|
+
send(opts: SendMessageOptions): Promise<string>;
|
|
14
|
+
/** Read messages with visibility filtering. */
|
|
15
|
+
read(opts?: ReadMessagesOptions): AgentMessage[];
|
|
16
|
+
/** List all channels with message counts. */
|
|
17
|
+
listChannels(): ChannelInfo[];
|
|
18
|
+
/** Acknowledge messages by marking them read. Returns count acknowledged. */
|
|
19
|
+
ack(messageIds: string[], reader: string): number;
|
|
20
|
+
/** Get stats for a reader. */
|
|
21
|
+
getStats(reader: string): MessagingStats;
|
|
22
|
+
/** Get a single message by ID. */
|
|
23
|
+
getMessage(id: string): AgentMessage | undefined;
|
|
24
|
+
/** Update mutable fields of a message. */
|
|
25
|
+
updateMessage(id: string, updates: {
|
|
26
|
+
body?: string;
|
|
27
|
+
recipients?: string[];
|
|
28
|
+
payload?: Record<string, unknown>;
|
|
29
|
+
persistent?: boolean;
|
|
30
|
+
}): AgentMessage | undefined;
|
|
31
|
+
/** Purge all messages. Returns count removed. */
|
|
32
|
+
purgeAll(): number;
|
|
33
|
+
/** Purge messages by channel. Returns count removed. */
|
|
34
|
+
purgeChannel(channel: string): number;
|
|
35
|
+
/** Delete specific messages by IDs. Returns count removed. */
|
|
36
|
+
deleteMessages(ids: string[]): number;
|
|
37
|
+
/** Remove expired non-persistent messages. */
|
|
38
|
+
sweepExpired(): number;
|
|
39
|
+
/** Reply to a message, auto-populating channel, parentId, and original recipients. */
|
|
40
|
+
reply(parentId: string, sender: string, body: string, opts?: {
|
|
41
|
+
replyAll?: boolean;
|
|
42
|
+
recipients?: string[];
|
|
43
|
+
priority?: string;
|
|
44
|
+
tags?: string[];
|
|
45
|
+
persistent?: boolean;
|
|
46
|
+
payload?: Record<string, unknown>;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
messageId: string;
|
|
49
|
+
channel: string;
|
|
50
|
+
recipients: string[];
|
|
51
|
+
}>;
|
|
52
|
+
/** Get all messages in a thread (by parentId). Returns parent + replies sorted chronologically. */
|
|
53
|
+
getThread(parentId: string): AgentMessage[];
|
|
54
|
+
/** Destroy the mailbox, stopping any timers. */
|
|
55
|
+
destroy(): void;
|
|
56
|
+
private makeKey;
|
|
57
|
+
private isRecipient;
|
|
58
|
+
private persistAll;
|
|
59
|
+
private startSweep;
|
|
60
|
+
}
|