@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,142 @@
|
|
|
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.runWithCorrelation = runWithCorrelation;
|
|
7
|
+
exports.getCurrentCorrelationId = getCurrentCorrelationId;
|
|
8
|
+
exports.resetAuditLogCache = resetAuditLogCache;
|
|
9
|
+
exports.logAudit = logAudit;
|
|
10
|
+
exports.logToolAudit = logToolAudit;
|
|
11
|
+
exports.logHttpAudit = logHttpAudit;
|
|
12
|
+
exports.readAuditEntries = readAuditEntries;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const async_hooks_1 = require("async_hooks");
|
|
16
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
17
|
+
const toolRegistry_1 = require("./toolRegistry");
|
|
18
|
+
// Append-only JSONL audit log for all server operations.
|
|
19
|
+
// Each line: { ts, kind, action, ids?, meta? }
|
|
20
|
+
// kind: 'mutation' | 'read' | 'http' — classifies the entry type.
|
|
21
|
+
// Path and enablement are driven by runtime configuration (instructions.auditLog).
|
|
22
|
+
// AsyncLocalStorage carries the correlation ID from registry wrapper into handler scope.
|
|
23
|
+
// This lets logAudit() calls inside handlers automatically include correlationId
|
|
24
|
+
// without changing handler signatures or passing context explicitly.
|
|
25
|
+
const auditContext = new async_hooks_1.AsyncLocalStorage();
|
|
26
|
+
/** Run a function with a correlation ID accessible to all logAudit() calls within. */
|
|
27
|
+
function runWithCorrelation(correlationId, fn) {
|
|
28
|
+
return auditContext.run({ correlationId }, fn);
|
|
29
|
+
}
|
|
30
|
+
/** Get the current correlation ID from the async context (if any). */
|
|
31
|
+
function getCurrentCorrelationId() {
|
|
32
|
+
return auditContext.getStore()?.correlationId;
|
|
33
|
+
}
|
|
34
|
+
let cachedKey;
|
|
35
|
+
let cachedPath;
|
|
36
|
+
function resolveLogPath() {
|
|
37
|
+
const { auditLog } = (0, runtimeConfig_1.getRuntimeConfig)().instructions;
|
|
38
|
+
const key = auditLog.enabled && auditLog.file ? `on:${auditLog.file}` : 'off';
|
|
39
|
+
if (cachedKey === key && cachedPath !== undefined) {
|
|
40
|
+
return cachedPath;
|
|
41
|
+
}
|
|
42
|
+
cachedKey = key;
|
|
43
|
+
if (!auditLog.enabled || !auditLog.file) {
|
|
44
|
+
cachedPath = null;
|
|
45
|
+
return cachedPath;
|
|
46
|
+
}
|
|
47
|
+
const file = auditLog.file;
|
|
48
|
+
try {
|
|
49
|
+
const dir = path_1.default.dirname(file);
|
|
50
|
+
if (!fs_1.default.existsSync(dir))
|
|
51
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
52
|
+
fs_1.default.appendFileSync(file, '');
|
|
53
|
+
cachedPath = file;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
cachedPath = null;
|
|
57
|
+
}
|
|
58
|
+
return cachedPath;
|
|
59
|
+
}
|
|
60
|
+
/** Reset the cached audit log path, forcing re-resolution on next write. */
|
|
61
|
+
function resetAuditLogCache() {
|
|
62
|
+
cachedKey = undefined;
|
|
63
|
+
cachedPath = undefined;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Append an entry to the audit log file. Silent no-op when logging is disabled.
|
|
67
|
+
* @param action - Tool or operation name being recorded
|
|
68
|
+
* @param ids - Instruction IDs affected by this operation (if any)
|
|
69
|
+
* @param meta - Lightweight result summary (counts, flags, etc.)
|
|
70
|
+
* @param kind - Entry classification; defaults to `'mutation'`
|
|
71
|
+
*/
|
|
72
|
+
function logAudit(action, ids, meta, kind) {
|
|
73
|
+
const file = resolveLogPath();
|
|
74
|
+
if (!file)
|
|
75
|
+
return; // silent no-op when logging disabled
|
|
76
|
+
const entry = { ts: new Date().toISOString(), kind: kind ?? 'mutation', action };
|
|
77
|
+
if (ids) {
|
|
78
|
+
entry.ids = Array.isArray(ids) ? ids : [ids];
|
|
79
|
+
}
|
|
80
|
+
// Auto-inject correlationId from async context if not already present in meta
|
|
81
|
+
const ctxCorr = getCurrentCorrelationId();
|
|
82
|
+
if (ctxCorr || meta) {
|
|
83
|
+
const m = meta ? { ...meta } : {};
|
|
84
|
+
if (ctxCorr && !m.correlationId)
|
|
85
|
+
m.correlationId = ctxCorr;
|
|
86
|
+
entry.meta = m;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
fs_1.default.appendFileSync(file, JSON.stringify(entry) + '\n', 'utf8');
|
|
90
|
+
}
|
|
91
|
+
catch { /* swallow logging errors to avoid impacting primary operation path */ }
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Log a tool invocation to the audit trail. Called from the registry wrapper
|
|
95
|
+
* so ALL tool calls (reads + mutations) are captured automatically.
|
|
96
|
+
*/
|
|
97
|
+
function logToolAudit(toolName, success, durationMs, correlationId, errorType) {
|
|
98
|
+
const kind = toolRegistry_1.MUTATION.has(toolName) ? 'mutation' : 'read';
|
|
99
|
+
const meta = { success, durationMs: Math.round(durationMs * 100) / 100 };
|
|
100
|
+
if (correlationId)
|
|
101
|
+
meta.correlationId = correlationId;
|
|
102
|
+
if (!success && errorType)
|
|
103
|
+
meta.errorType = errorType;
|
|
104
|
+
logAudit(toolName, undefined, meta, kind);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Log an HTTP request to the audit trail. Called from dashboard middleware
|
|
108
|
+
* so all API requests are captured with client IP and user-agent.
|
|
109
|
+
*/
|
|
110
|
+
function logHttpAudit(method, route, statusCode, durationMs, clientIp, userAgent) {
|
|
111
|
+
const meta = { statusCode, durationMs: Math.round(durationMs * 100) / 100 };
|
|
112
|
+
if (clientIp)
|
|
113
|
+
meta.clientIp = clientIp;
|
|
114
|
+
if (userAgent)
|
|
115
|
+
meta.userAgent = userAgent;
|
|
116
|
+
logAudit(`${method} ${route}`, undefined, meta, 'http');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read the most recent audit log entries from disk.
|
|
120
|
+
* @param limit - Maximum number of lines to return from the tail of the file (default 1000)
|
|
121
|
+
* @returns Parsed audit entries, or an empty array if logging is disabled or the file is missing
|
|
122
|
+
*/
|
|
123
|
+
function readAuditEntries(limit = 1000) {
|
|
124
|
+
const file = resolveLogPath();
|
|
125
|
+
if (!file || !fs_1.default.existsSync(file))
|
|
126
|
+
return [];
|
|
127
|
+
try {
|
|
128
|
+
const lines = fs_1.default.readFileSync(file, 'utf8').split(/\r?\n/).filter(l => l.trim());
|
|
129
|
+
const recent = lines.slice(-limit);
|
|
130
|
+
const parsed = [];
|
|
131
|
+
for (const l of recent) {
|
|
132
|
+
try {
|
|
133
|
+
parsed.push(JSON.parse(l));
|
|
134
|
+
}
|
|
135
|
+
catch { /* ignore */ }
|
|
136
|
+
}
|
|
137
|
+
return parsed;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a single auto-backup cycle. Returns the backup zip file path,
|
|
3
|
+
* or null if the instructions directory is empty / doesn't exist.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runAutoBackupOnce(): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Start the periodic auto-backup timer. Returns the interval handle.
|
|
8
|
+
* No-op if already running.
|
|
9
|
+
*/
|
|
10
|
+
export declare function startAutoBackup(): ReturnType<typeof setInterval> | null;
|
|
11
|
+
/**
|
|
12
|
+
* Stop the periodic auto-backup timer.
|
|
13
|
+
*/
|
|
14
|
+
export declare function stopAutoBackup(): void;
|
|
@@ -0,0 +1,171 @@
|
|
|
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.runAutoBackupOnce = runAutoBackupOnce;
|
|
7
|
+
exports.startAutoBackup = startAutoBackup;
|
|
8
|
+
exports.stopAutoBackup = stopAutoBackup;
|
|
9
|
+
/**
|
|
10
|
+
* Automatic periodic backup of the instruction index.
|
|
11
|
+
*
|
|
12
|
+
* Creates zip archives of all .json files from the instructions directory
|
|
13
|
+
* into the configured backups directory. Old auto-backups are pruned when
|
|
14
|
+
* their count exceeds the configured maximum.
|
|
15
|
+
*
|
|
16
|
+
* Env vars (via runtimeConfig.mutation):
|
|
17
|
+
* INDEX_SERVER_AUTO_BACKUP_INTERVAL_MS — timer interval (default 3600000 = 1h)
|
|
18
|
+
* INDEX_SERVER_AUTO_BACKUP_MAX_COUNT — max retained auto-backups (default 10)
|
|
19
|
+
*/
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
21
|
+
const path_1 = __importDefault(require("path"));
|
|
22
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
23
|
+
const backupZip_1 = require("./backupZip");
|
|
24
|
+
const AUTO_BACKUP_PREFIX = 'auto-backup-';
|
|
25
|
+
let _timer = null;
|
|
26
|
+
function getInstructionsDir() {
|
|
27
|
+
return (0, runtimeConfig_1.getRuntimeConfig)().index.baseDir;
|
|
28
|
+
}
|
|
29
|
+
function getBackupsDir() {
|
|
30
|
+
return (0, runtimeConfig_1.getRuntimeConfig)().dashboard.admin.backupsDir;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Run a single auto-backup cycle. Returns the backup zip file path,
|
|
34
|
+
* or null if the instructions directory is empty / doesn't exist.
|
|
35
|
+
*/
|
|
36
|
+
function runAutoBackupOnce() {
|
|
37
|
+
const instrDir = getInstructionsDir();
|
|
38
|
+
if (!fs_1.default.existsSync(instrDir))
|
|
39
|
+
return null;
|
|
40
|
+
const backupsRoot = getBackupsDir();
|
|
41
|
+
fs_1.default.mkdirSync(backupsRoot, { recursive: true });
|
|
42
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '').replace('T', '-').slice(0, 15);
|
|
43
|
+
let zipPath = path_1.default.join(backupsRoot, `${AUTO_BACKUP_PREFIX}${stamp}.zip`);
|
|
44
|
+
let i = 1;
|
|
45
|
+
while (fs_1.default.existsSync(zipPath)) {
|
|
46
|
+
zipPath = path_1.default.join(backupsRoot, `${AUTO_BACKUP_PREFIX}${stamp}-${i++}.zip`);
|
|
47
|
+
}
|
|
48
|
+
// Backup SQLite DB if present — still uses a directory for binary DB files
|
|
49
|
+
const storageBackend = (0, runtimeConfig_1.getRuntimeConfig)().storage?.backend ?? 'json';
|
|
50
|
+
if (storageBackend === 'sqlite') {
|
|
51
|
+
const sqlitePath = (0, runtimeConfig_1.getRuntimeConfig)().storage?.sqlitePath;
|
|
52
|
+
if (sqlitePath && fs_1.default.existsSync(sqlitePath)) {
|
|
53
|
+
const backupDir = zipPath.replace(/\.zip$/, '');
|
|
54
|
+
fs_1.default.mkdirSync(backupDir, { recursive: true });
|
|
55
|
+
fs_1.default.copyFileSync(sqlitePath, path_1.default.join(backupDir, 'index.db'));
|
|
56
|
+
if (fs_1.default.existsSync(sqlitePath + '-wal'))
|
|
57
|
+
fs_1.default.copyFileSync(sqlitePath + '-wal', path_1.default.join(backupDir, 'index.db-wal'));
|
|
58
|
+
if (fs_1.default.existsSync(sqlitePath + '-shm'))
|
|
59
|
+
fs_1.default.copyFileSync(sqlitePath + '-shm', path_1.default.join(backupDir, 'index.db-shm'));
|
|
60
|
+
pruneOldBackups(backupsRoot);
|
|
61
|
+
try {
|
|
62
|
+
process.stderr.write(`[auto-backup] created ${backupDir} (sqlite)\n`);
|
|
63
|
+
}
|
|
64
|
+
catch { /* ignore */ }
|
|
65
|
+
return backupDir;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Default: backup JSON files into a zip
|
|
69
|
+
const files = fs_1.default.readdirSync(instrDir).filter(f => f.endsWith('.json'));
|
|
70
|
+
if (files.length === 0)
|
|
71
|
+
return null;
|
|
72
|
+
const { zipPath: resultPath, fileCount } = (0, backupZip_1.createZipBackup)(instrDir, zipPath);
|
|
73
|
+
// Prune old auto-backups beyond maxCount
|
|
74
|
+
pruneOldBackups(backupsRoot);
|
|
75
|
+
try {
|
|
76
|
+
process.stderr.write(`[auto-backup] created ${resultPath} (${fileCount} files)\n`);
|
|
77
|
+
}
|
|
78
|
+
catch { /* ignore */ }
|
|
79
|
+
return resultPath;
|
|
80
|
+
}
|
|
81
|
+
function pruneOldBackups(backupsRoot) {
|
|
82
|
+
const maxCount = (0, runtimeConfig_1.getRuntimeConfig)().mutation.autoBackupMaxCount;
|
|
83
|
+
try {
|
|
84
|
+
const entries = fs_1.default.readdirSync(backupsRoot)
|
|
85
|
+
.filter(d => {
|
|
86
|
+
if (!d.startsWith(AUTO_BACKUP_PREFIX))
|
|
87
|
+
return false;
|
|
88
|
+
const full = path_1.default.join(backupsRoot, d);
|
|
89
|
+
// Accept both zip files and legacy directories
|
|
90
|
+
return d.endsWith('.zip') ? fs_1.default.statSync(full).isFile() : fs_1.default.statSync(full).isDirectory();
|
|
91
|
+
})
|
|
92
|
+
.sort(); // lexicographic = chronological for ISO timestamps
|
|
93
|
+
while (entries.length > maxCount) {
|
|
94
|
+
const oldest = entries.shift();
|
|
95
|
+
const full = path_1.default.join(backupsRoot, oldest);
|
|
96
|
+
if (oldest.endsWith('.zip')) {
|
|
97
|
+
fs_1.default.unlinkSync(full);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
fs_1.default.rmSync(full, { recursive: true, force: true });
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
process.stderr.write(`[auto-backup] pruned old backup: ${oldest}\n`);
|
|
104
|
+
}
|
|
105
|
+
catch { /* ignore */ }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
try {
|
|
110
|
+
process.stderr.write(`[auto-backup] pruning failed: ${e}\n`);
|
|
111
|
+
}
|
|
112
|
+
catch { /* ignore */ }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Start the periodic auto-backup timer. Returns the interval handle.
|
|
117
|
+
* No-op if already running.
|
|
118
|
+
*/
|
|
119
|
+
function startAutoBackup() {
|
|
120
|
+
if (_timer)
|
|
121
|
+
return _timer;
|
|
122
|
+
const cfg = (0, runtimeConfig_1.getRuntimeConfig)().mutation;
|
|
123
|
+
if (!cfg.autoBackupEnabled) {
|
|
124
|
+
try {
|
|
125
|
+
process.stderr.write('[auto-backup] disabled (INDEX_SERVER_AUTO_BACKUP=0)\n');
|
|
126
|
+
}
|
|
127
|
+
catch { /* ignore */ }
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const intervalMs = cfg.autoBackupIntervalMs;
|
|
131
|
+
if (intervalMs <= 0)
|
|
132
|
+
return null;
|
|
133
|
+
_timer = setInterval(() => {
|
|
134
|
+
try {
|
|
135
|
+
runAutoBackupOnce();
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
try {
|
|
139
|
+
process.stderr.write(`[auto-backup] interval run failed: ${e}\n`);
|
|
140
|
+
}
|
|
141
|
+
catch { /* ignore */ }
|
|
142
|
+
}
|
|
143
|
+
}, intervalMs);
|
|
144
|
+
// Unref so the timer doesn't keep the process alive
|
|
145
|
+
if (_timer && typeof _timer.unref === 'function')
|
|
146
|
+
_timer.unref();
|
|
147
|
+
// Run first backup after a short delay (don't block caller)
|
|
148
|
+
setTimeout(() => { try {
|
|
149
|
+
runAutoBackupOnce();
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
try {
|
|
153
|
+
process.stderr.write(`[auto-backup] initial run failed: ${e}\n`);
|
|
154
|
+
}
|
|
155
|
+
catch { /* ignore */ }
|
|
156
|
+
} }, 5000).unref();
|
|
157
|
+
try {
|
|
158
|
+
process.stderr.write(`[auto-backup] started (interval=${intervalMs}ms, maxCount=${(0, runtimeConfig_1.getRuntimeConfig)().mutation.autoBackupMaxCount})\n`);
|
|
159
|
+
}
|
|
160
|
+
catch { /* ignore */ }
|
|
161
|
+
return _timer;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Stop the periodic auto-backup timer.
|
|
165
|
+
*/
|
|
166
|
+
function stopAutoBackup() {
|
|
167
|
+
if (_timer) {
|
|
168
|
+
clearInterval(_timer);
|
|
169
|
+
_timer = null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-split oversized instruction entries into cross-linked sub-instructions.
|
|
3
|
+
* Used by the index loader on startup to handle entries written directly to disk
|
|
4
|
+
* by agents that bypass MCP tool size validation.
|
|
5
|
+
*/
|
|
6
|
+
interface InstructionLike {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
body: string;
|
|
10
|
+
priority: number;
|
|
11
|
+
audience: string;
|
|
12
|
+
requirement: string;
|
|
13
|
+
categories: string[];
|
|
14
|
+
schemaVersion?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Split an oversized instruction entry into multiple parts that each fit within the body limit.
|
|
19
|
+
* If the entry body is within the limit, returns a single-element array with the original entry.
|
|
20
|
+
*
|
|
21
|
+
* Splitting strategy:
|
|
22
|
+
* 1. Attempt to split by markdown H2 headings (## Section)
|
|
23
|
+
* 2. If sections are still too large, split by paragraphs (double newline)
|
|
24
|
+
* 3. As a last resort, split at character boundaries
|
|
25
|
+
*
|
|
26
|
+
* Each part gets:
|
|
27
|
+
* - Sequential ID: `{original-id}-part-{n}`
|
|
28
|
+
* - Preserved metadata (priority, audience, requirement, categories)
|
|
29
|
+
* - Cross-link footer referencing all sibling parts
|
|
30
|
+
*/
|
|
31
|
+
export declare function splitOversizedEntry(entry: InstructionLike, maxLength: number): InstructionLike[];
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auto-split oversized instruction entries into cross-linked sub-instructions.
|
|
4
|
+
* Used by the index loader on startup to handle entries written directly to disk
|
|
5
|
+
* by agents that bypass MCP tool size validation.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.splitOversizedEntry = splitOversizedEntry;
|
|
9
|
+
/**
|
|
10
|
+
* Split an oversized instruction entry into multiple parts that each fit within the body limit.
|
|
11
|
+
* If the entry body is within the limit, returns a single-element array with the original entry.
|
|
12
|
+
*
|
|
13
|
+
* Splitting strategy:
|
|
14
|
+
* 1. Attempt to split by markdown H2 headings (## Section)
|
|
15
|
+
* 2. If sections are still too large, split by paragraphs (double newline)
|
|
16
|
+
* 3. As a last resort, split at character boundaries
|
|
17
|
+
*
|
|
18
|
+
* Each part gets:
|
|
19
|
+
* - Sequential ID: `{original-id}-part-{n}`
|
|
20
|
+
* - Preserved metadata (priority, audience, requirement, categories)
|
|
21
|
+
* - Cross-link footer referencing all sibling parts
|
|
22
|
+
*/
|
|
23
|
+
function splitOversizedEntry(entry, maxLength) {
|
|
24
|
+
if (entry.body.length <= maxLength) {
|
|
25
|
+
return [{ ...entry }];
|
|
26
|
+
}
|
|
27
|
+
// Try heading-based split first
|
|
28
|
+
let chunks = splitByHeadings(entry.body);
|
|
29
|
+
// If any chunk is still too large, further split by paragraphs
|
|
30
|
+
chunks = chunks.flatMap(chunk => chunk.length > maxLength ? splitByParagraphs(chunk, maxLength) : [chunk]);
|
|
31
|
+
// Last resort: hard split at character boundary
|
|
32
|
+
chunks = chunks.flatMap(chunk => chunk.length > maxLength ? hardSplit(chunk, maxLength) : [chunk]);
|
|
33
|
+
// Merge tiny trailing chunks into the previous one when possible
|
|
34
|
+
const merged = [];
|
|
35
|
+
for (const chunk of chunks) {
|
|
36
|
+
if (merged.length > 0 && merged[merged.length - 1].length + chunk.length + 2 <= maxLength) {
|
|
37
|
+
merged[merged.length - 1] += '\n\n' + chunk;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
merged.push(chunk);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// If merging produced a single chunk (edge case), return as-is
|
|
44
|
+
if (merged.length <= 1) {
|
|
45
|
+
return [{ ...entry, body: merged[0] || entry.body.slice(0, maxLength) }];
|
|
46
|
+
}
|
|
47
|
+
// Generate part IDs
|
|
48
|
+
const partIds = merged.map((_, i) => `${entry.id}-part-${i + 1}`);
|
|
49
|
+
// Build cross-link footer
|
|
50
|
+
const parts = merged.map((chunk, i) => {
|
|
51
|
+
const siblingIds = partIds.filter((_, j) => j !== i);
|
|
52
|
+
const crossLinkFooter = `\n\n---\n**Cross-linked parts:** ${siblingIds.join(', ')}`;
|
|
53
|
+
// Reserve space for footer in body
|
|
54
|
+
const maxBodyContent = maxLength - crossLinkFooter.length;
|
|
55
|
+
const bodyContent = chunk.length > maxBodyContent ? chunk.slice(0, maxBodyContent) : chunk;
|
|
56
|
+
const { body: _body, id: _id, title: _title, ...rest } = entry;
|
|
57
|
+
return {
|
|
58
|
+
...rest,
|
|
59
|
+
id: partIds[i],
|
|
60
|
+
title: `${entry.title} (Part ${i + 1}/${merged.length})`,
|
|
61
|
+
body: bodyContent + crossLinkFooter,
|
|
62
|
+
categories: [...entry.categories],
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
return parts;
|
|
66
|
+
}
|
|
67
|
+
/** Split body text at ## heading boundaries */
|
|
68
|
+
function splitByHeadings(body) {
|
|
69
|
+
const headingPattern = /^## /m;
|
|
70
|
+
if (!headingPattern.test(body))
|
|
71
|
+
return [body];
|
|
72
|
+
const parts = [];
|
|
73
|
+
const lines = body.split('\n');
|
|
74
|
+
let current = [];
|
|
75
|
+
for (const line of lines) {
|
|
76
|
+
if (/^## /.test(line) && current.length > 0) {
|
|
77
|
+
parts.push(current.join('\n').trim());
|
|
78
|
+
current = [];
|
|
79
|
+
}
|
|
80
|
+
current.push(line);
|
|
81
|
+
}
|
|
82
|
+
if (current.length > 0) {
|
|
83
|
+
parts.push(current.join('\n').trim());
|
|
84
|
+
}
|
|
85
|
+
return parts.filter(p => p.length > 0);
|
|
86
|
+
}
|
|
87
|
+
/** Split a chunk by double-newline paragraph boundaries */
|
|
88
|
+
function splitByParagraphs(text, maxLength) {
|
|
89
|
+
const paragraphs = text.split(/\n\n+/);
|
|
90
|
+
const chunks = [];
|
|
91
|
+
let current = '';
|
|
92
|
+
for (const para of paragraphs) {
|
|
93
|
+
if (current.length + para.length + 2 > maxLength && current.length > 0) {
|
|
94
|
+
chunks.push(current.trim());
|
|
95
|
+
current = para;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
current = current ? current + '\n\n' + para : para;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (current.trim()) {
|
|
102
|
+
chunks.push(current.trim());
|
|
103
|
+
}
|
|
104
|
+
return chunks;
|
|
105
|
+
}
|
|
106
|
+
/** Hard split at character boundaries (last resort) */
|
|
107
|
+
function hardSplit(text, maxLength) {
|
|
108
|
+
const chunks = [];
|
|
109
|
+
for (let i = 0; i < text.length; i += maxLength) {
|
|
110
|
+
chunks.push(text.slice(i, i + maxLength));
|
|
111
|
+
}
|
|
112
|
+
return chunks;
|
|
113
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Create a zip from every .json file in `sourceDir`. Returns the written zip path. */
|
|
2
|
+
export declare function createZipBackup(sourceDir: string, outputZipPath: string): {
|
|
3
|
+
zipPath: string;
|
|
4
|
+
fileCount: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Create a zip that also includes a manifest.json entry.
|
|
8
|
+
* The manifest is written as an in-memory entry (not read from disk).
|
|
9
|
+
*/
|
|
10
|
+
export declare function createZipBackupWithManifest(sourceDir: string, outputZipPath: string, manifest: Record<string, unknown>): {
|
|
11
|
+
zipPath: string;
|
|
12
|
+
fileCount: number;
|
|
13
|
+
};
|
|
14
|
+
/** Extract all .json files from a zip into `targetDir`. Returns count of extracted files. */
|
|
15
|
+
export declare function extractZipBackup(zipPath: string, targetDir: string): number;
|
|
16
|
+
/** Read and parse the manifest.json from inside a zip (if present). */
|
|
17
|
+
export declare function readZipManifest(zipPath: string): Record<string, unknown> | null;
|
|
18
|
+
/** List .json filenames inside a zip (excluding manifest.json). */
|
|
19
|
+
export declare function listZipInstructionFiles(zipPath: string): string[];
|
|
20
|
+
/** Read a single file from a zip as parsed JSON. */
|
|
21
|
+
export declare function readZipEntry(zipPath: string, entryName: string): unknown | null;
|
|
22
|
+
/** Get size of a zip file in bytes. */
|
|
23
|
+
export declare function getZipSizeBytes(zipPath: string): number;
|
|
24
|
+
/** Check whether a path is a zip backup (by extension). */
|
|
25
|
+
export declare function isZipBackup(filePath: string): boolean;
|
|
@@ -0,0 +1,110 @@
|
|
|
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.createZipBackup = createZipBackup;
|
|
7
|
+
exports.createZipBackupWithManifest = createZipBackupWithManifest;
|
|
8
|
+
exports.extractZipBackup = extractZipBackup;
|
|
9
|
+
exports.readZipManifest = readZipManifest;
|
|
10
|
+
exports.listZipInstructionFiles = listZipInstructionFiles;
|
|
11
|
+
exports.readZipEntry = readZipEntry;
|
|
12
|
+
exports.getZipSizeBytes = getZipSizeBytes;
|
|
13
|
+
exports.isZipBackup = isZipBackup;
|
|
14
|
+
/**
|
|
15
|
+
* Shared zip-based backup utilities.
|
|
16
|
+
*
|
|
17
|
+
* All backup producers (autoBackup, bulk-delete, AdminPanel) converge here
|
|
18
|
+
* so there is a single implementation for creating, reading, and extracting
|
|
19
|
+
* zip backup archives.
|
|
20
|
+
*/
|
|
21
|
+
const fs_1 = __importDefault(require("fs"));
|
|
22
|
+
const path_1 = __importDefault(require("path"));
|
|
23
|
+
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
24
|
+
/** Create a zip from every .json file in `sourceDir`. Returns the written zip path. */
|
|
25
|
+
function createZipBackup(sourceDir, outputZipPath) {
|
|
26
|
+
const zip = new adm_zip_1.default();
|
|
27
|
+
const files = fs_1.default.readdirSync(sourceDir).filter(f => f.endsWith('.json'));
|
|
28
|
+
for (const f of files) {
|
|
29
|
+
zip.addLocalFile(path_1.default.join(sourceDir, f));
|
|
30
|
+
}
|
|
31
|
+
zip.writeZip(outputZipPath);
|
|
32
|
+
return { zipPath: outputZipPath, fileCount: files.length };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a zip that also includes a manifest.json entry.
|
|
36
|
+
* The manifest is written as an in-memory entry (not read from disk).
|
|
37
|
+
*/
|
|
38
|
+
function createZipBackupWithManifest(sourceDir, outputZipPath, manifest) {
|
|
39
|
+
const zip = new adm_zip_1.default();
|
|
40
|
+
const files = fs_1.default.readdirSync(sourceDir).filter(f => f.endsWith('.json'));
|
|
41
|
+
for (const f of files) {
|
|
42
|
+
zip.addLocalFile(path_1.default.join(sourceDir, f));
|
|
43
|
+
}
|
|
44
|
+
zip.addFile('manifest.json', Buffer.from(JSON.stringify(manifest, null, 2)));
|
|
45
|
+
zip.writeZip(outputZipPath);
|
|
46
|
+
return { zipPath: outputZipPath, fileCount: files.length };
|
|
47
|
+
}
|
|
48
|
+
/** Extract all .json files from a zip into `targetDir`. Returns count of extracted files. */
|
|
49
|
+
function extractZipBackup(zipPath, targetDir) {
|
|
50
|
+
if (!fs_1.default.existsSync(targetDir))
|
|
51
|
+
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
52
|
+
const zip = new adm_zip_1.default(zipPath);
|
|
53
|
+
let count = 0;
|
|
54
|
+
for (const entry of zip.getEntries()) {
|
|
55
|
+
const name = path_1.default.basename(entry.entryName);
|
|
56
|
+
if (!name.toLowerCase().endsWith('.json'))
|
|
57
|
+
continue;
|
|
58
|
+
if (name.includes('..') || name !== entry.entryName)
|
|
59
|
+
continue; // path traversal guard
|
|
60
|
+
fs_1.default.writeFileSync(path_1.default.join(targetDir, name), entry.getData());
|
|
61
|
+
count++;
|
|
62
|
+
}
|
|
63
|
+
return count;
|
|
64
|
+
}
|
|
65
|
+
/** Read and parse the manifest.json from inside a zip (if present). */
|
|
66
|
+
function readZipManifest(zipPath) {
|
|
67
|
+
try {
|
|
68
|
+
const zip = new adm_zip_1.default(zipPath);
|
|
69
|
+
const entry = zip.getEntry('manifest.json');
|
|
70
|
+
if (!entry)
|
|
71
|
+
return null;
|
|
72
|
+
return JSON.parse(entry.getData().toString('utf-8'));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** List .json filenames inside a zip (excluding manifest.json). */
|
|
79
|
+
function listZipInstructionFiles(zipPath) {
|
|
80
|
+
const zip = new adm_zip_1.default(zipPath);
|
|
81
|
+
return zip.getEntries()
|
|
82
|
+
.map(e => e.entryName)
|
|
83
|
+
.filter(n => n.toLowerCase().endsWith('.json') && n !== 'manifest.json');
|
|
84
|
+
}
|
|
85
|
+
/** Read a single file from a zip as parsed JSON. */
|
|
86
|
+
function readZipEntry(zipPath, entryName) {
|
|
87
|
+
try {
|
|
88
|
+
const zip = new adm_zip_1.default(zipPath);
|
|
89
|
+
const entry = zip.getEntry(entryName);
|
|
90
|
+
if (!entry)
|
|
91
|
+
return null;
|
|
92
|
+
return JSON.parse(entry.getData().toString('utf-8'));
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Get size of a zip file in bytes. */
|
|
99
|
+
function getZipSizeBytes(zipPath) {
|
|
100
|
+
try {
|
|
101
|
+
return fs_1.default.statSync(zipPath).size;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Check whether a path is a zip backup (by extension). */
|
|
108
|
+
function isZipBackup(filePath) {
|
|
109
|
+
return filePath.toLowerCase().endsWith('.zip');
|
|
110
|
+
}
|