@jagilber-org/index-server 1.22.0 → 1.26.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 +87 -2
- package/CODE_OF_CONDUCT.md +2 -0
- package/CONTRIBUTING.md +32 -2
- package/README.md +83 -20
- package/SECURITY.md +17 -5
- package/dist/config/dashboardConfig.d.ts +3 -0
- package/dist/config/dashboardConfig.js +3 -0
- package/dist/config/defaultValues.d.ts +1 -1
- package/dist/config/defaultValues.js +1 -1
- package/dist/config/featureConfig.d.ts +2 -0
- package/dist/config/featureConfig.js +6 -1
- package/dist/config/runtimeConfig.d.ts +1 -1
- package/dist/config/runtimeConfig.js +8 -9
- package/dist/dashboard/client/admin.html +173 -54
- package/dist/dashboard/client/css/admin.css +151 -0
- package/dist/dashboard/client/js/admin.auth.js +25 -11
- package/dist/dashboard/client/js/admin.config.js +1 -1
- package/dist/dashboard/client/js/admin.feedback.js +328 -0
- package/dist/dashboard/client/js/admin.graph.js +120 -18
- package/dist/dashboard/client/js/admin.instructions.js +27 -13
- package/dist/dashboard/client/js/admin.logs.js +1 -5
- package/dist/dashboard/client/js/admin.maintenance.js +53 -8
- package/dist/dashboard/client/js/admin.messaging.js +1 -4
- package/dist/dashboard/client/js/admin.overview.js +5 -1
- package/dist/dashboard/client/js/admin.sessions.js +1 -1
- package/dist/dashboard/client/js/admin.utils.js +43 -1
- package/dist/dashboard/client/js/mermaid.min.js +813 -537
- package/dist/dashboard/export/DataExporter.js +2 -1
- package/dist/dashboard/server/AdminPanel.d.ts +3 -0
- package/dist/dashboard/server/AdminPanel.js +132 -35
- package/dist/dashboard/server/ApiRoutes.js +40 -9
- package/dist/dashboard/server/DashboardServer.js +1 -1
- package/dist/dashboard/server/FileMetricsStorage.d.ts +19 -0
- package/dist/dashboard/server/FileMetricsStorage.js +52 -5
- package/dist/dashboard/server/HttpTransport.js +6 -0
- package/dist/dashboard/server/InstanceManager.js +7 -2
- package/dist/dashboard/server/KnowledgeStore.js +7 -2
- package/dist/dashboard/server/MetricsCollector.d.ts +16 -0
- package/dist/dashboard/server/MetricsCollector.js +113 -17
- package/dist/dashboard/server/legacyDashboardHtml.js +7 -2
- package/dist/dashboard/server/middleware/ensureLoadedMiddleware.d.ts +1 -1
- package/dist/dashboard/server/middleware/ensureLoadedMiddleware.js +8 -3
- package/dist/dashboard/server/routes/admin.feedback.routes.d.ts +15 -0
- package/dist/dashboard/server/routes/admin.feedback.routes.js +188 -0
- package/dist/dashboard/server/routes/admin.routes.js +35 -27
- package/dist/dashboard/server/routes/alerts.routes.js +4 -3
- package/dist/dashboard/server/routes/api.feedback.routes.js +2 -1
- package/dist/dashboard/server/routes/api.usage.routes.js +8 -7
- package/dist/dashboard/server/routes/embeddings.routes.d.ts +2 -1
- package/dist/dashboard/server/routes/embeddings.routes.js +18 -9
- package/dist/dashboard/server/routes/graph.routes.js +10 -13
- package/dist/dashboard/server/routes/index.d.ts +1 -0
- package/dist/dashboard/server/routes/index.js +74 -39
- package/dist/dashboard/server/routes/instances.routes.js +2 -1
- package/dist/dashboard/server/routes/instructions.routes.js +46 -27
- package/dist/dashboard/server/routes/knowledge.routes.js +4 -3
- package/dist/dashboard/server/routes/logs.routes.js +5 -4
- package/dist/dashboard/server/routes/messaging.routes.js +15 -14
- package/dist/dashboard/server/routes/metrics.routes.js +14 -13
- package/dist/dashboard/server/routes/scripts.routes.js +6 -3
- package/dist/dashboard/server/routes/status.routes.js +25 -6
- package/dist/dashboard/server/routes/synthetic.routes.js +3 -2
- package/dist/dashboard/server/routes/usage.routes.js +2 -1
- package/dist/dashboard/server/utils/escapeHtml.d.ts +1 -0
- package/dist/dashboard/server/utils/escapeHtml.js +11 -0
- package/dist/dashboard/server/utils/pathContainment.d.ts +1 -0
- package/dist/dashboard/server/utils/pathContainment.js +15 -0
- package/dist/dashboard/server/wsInit.js +2 -2
- package/dist/lib/mcpStdioLogging.d.ts +165 -0
- package/dist/lib/mcpStdioLogging.js +287 -0
- package/dist/schemas/index.d.ts +37 -2
- package/dist/schemas/index.js +27 -3
- package/dist/server/backgroundServicesStartup.d.ts +7 -1
- package/dist/server/backgroundServicesStartup.js +25 -8
- package/dist/server/certInit.d.ts +97 -0
- package/dist/server/certInit.js +359 -0
- package/dist/server/certInit.types.d.ts +92 -0
- package/dist/server/certInit.types.js +34 -0
- package/dist/server/handshake/fallbackFrames.d.ts +31 -0
- package/dist/server/handshake/fallbackFrames.js +38 -0
- package/dist/server/handshake/initializeDetector.d.ts +31 -0
- package/dist/server/handshake/initializeDetector.js +88 -0
- package/dist/server/handshake/protocol.d.ts +15 -0
- package/dist/server/handshake/protocol.js +37 -0
- package/dist/server/handshake/readyEmitter.d.ts +6 -0
- package/dist/server/handshake/readyEmitter.js +88 -0
- package/dist/server/handshake/safetyFallbacks.d.ts +1 -0
- package/dist/server/handshake/safetyFallbacks.js +134 -0
- package/dist/server/handshake/stdinSniffer.d.ts +1 -0
- package/dist/server/handshake/stdinSniffer.js +260 -0
- package/dist/server/handshake/tracing.d.ts +16 -0
- package/dist/server/handshake/tracing.js +95 -0
- package/dist/server/handshakeManager.d.ts +23 -23
- package/dist/server/handshakeManager.js +36 -466
- package/dist/server/index-server.d.ts +23 -0
- package/dist/server/index-server.js +194 -9
- package/dist/server/mcpReadOnlySurfaces.d.ts +44 -0
- package/dist/server/mcpReadOnlySurfaces.js +297 -0
- package/dist/server/sdkServer.js +69 -7
- package/dist/server/transport.d.ts +5 -6
- package/dist/server/transport.js +46 -64
- package/dist/server/transportFactory.d.ts +3 -9
- package/dist/server/transportFactory.js +18 -380
- package/dist/services/atomicFs.d.ts +3 -0
- package/dist/services/atomicFs.js +171 -13
- package/dist/services/auditLog.d.ts +17 -2
- package/dist/services/auditLog.js +75 -14
- package/dist/services/bootstrapGating.js +1 -1
- package/dist/services/categoryRules.d.ts +10 -0
- package/dist/services/categoryRules.js +17 -0
- package/dist/services/classificationService.js +7 -5
- package/dist/services/embeddingService.d.ts +27 -11
- package/dist/services/embeddingService.js +51 -14
- package/dist/services/feedbackStorage.d.ts +39 -0
- package/dist/services/feedbackStorage.js +88 -0
- package/dist/services/handlers/instructions.add.js +429 -317
- package/dist/services/handlers/instructions.groom.js +128 -31
- package/dist/services/handlers/instructions.import.js +56 -23
- package/dist/services/handlers/instructions.patch.js +43 -32
- package/dist/services/handlers/instructions.query.js +20 -29
- package/dist/services/handlers/instructions.shared.d.ts +54 -0
- package/dist/services/handlers/instructions.shared.js +126 -1
- package/dist/services/handlers.activation.js +83 -81
- package/dist/services/handlers.dashboardConfig.d.ts +2 -2
- package/dist/services/handlers.dashboardConfig.js +1 -2
- package/dist/services/handlers.diagnostics.js +75 -54
- package/dist/services/handlers.feedback.d.ts +4 -11
- package/dist/services/handlers.feedback.js +11 -333
- package/dist/services/handlers.gates.js +69 -37
- package/dist/services/handlers.graph.js +2 -2
- package/dist/services/handlers.help.js +2 -2
- package/dist/services/handlers.instructionSchema.js +4 -2
- package/dist/services/handlers.integrity.js +42 -22
- package/dist/services/handlers.messaging.js +1 -1
- package/dist/services/handlers.metrics.js +51 -6
- package/dist/services/handlers.prompt.js +10 -2
- package/dist/services/handlers.search.js +94 -44
- package/dist/services/handlers.trace.js +1 -1
- package/dist/services/handlers.usage.js +38 -7
- package/dist/services/indexContext.d.ts +21 -1
- package/dist/services/indexContext.js +267 -82
- package/dist/services/indexLoader.d.ts +1 -0
- package/dist/services/indexLoader.js +28 -8
- package/dist/services/instructionRecordValidation.d.ts +39 -0
- package/dist/services/instructionRecordValidation.js +388 -0
- package/dist/services/instructions.dispatcher.js +4 -4
- package/dist/services/loaderSchemaValidator.d.ts +15 -0
- package/dist/services/loaderSchemaValidator.js +69 -0
- package/dist/services/logger.js +11 -2
- package/dist/services/mcpLogBridge.d.ts +49 -0
- package/dist/services/mcpLogBridge.js +83 -0
- package/dist/services/ownershipService.js +18 -8
- package/dist/services/performanceBaseline.js +23 -22
- package/dist/services/promptReviewService.d.ts +3 -1
- package/dist/services/promptReviewService.js +41 -13
- package/dist/services/regexSafety.d.ts +6 -0
- package/dist/services/regexSafety.js +46 -0
- package/dist/services/seedBootstrap.js +4 -4
- package/dist/services/storage/factory.d.ts +14 -1
- package/dist/services/storage/factory.js +61 -1
- package/dist/services/storage/jsonEmbeddingStore.d.ts +15 -0
- package/dist/services/storage/jsonEmbeddingStore.js +83 -0
- package/dist/services/storage/jsonFileStore.d.ts +3 -1
- package/dist/services/storage/jsonFileStore.js +8 -6
- package/dist/services/storage/migrationEngine.d.ts +13 -0
- package/dist/services/storage/migrationEngine.js +31 -0
- package/dist/services/storage/sqliteEmbeddingStore.d.ts +30 -0
- package/dist/services/storage/sqliteEmbeddingStore.js +222 -0
- package/dist/services/storage/sqliteStore.d.ts +3 -1
- package/dist/services/storage/sqliteStore.js +2 -2
- package/dist/services/storage/types.d.ts +48 -1
- package/dist/services/toolRegistry.js +77 -67
- package/dist/services/toolRegistry.zod.js +89 -86
- package/dist/services/tracing.js +5 -4
- package/dist/utils/envUtils.d.ts +4 -0
- package/dist/utils/envUtils.js +7 -0
- package/dist/utils/memoryMonitor.js +11 -10
- package/package.json +11 -4
- package/schemas/instruction.schema.json +38 -1
- package/scripts/copy-dashboard-assets.mjs +1 -1
- package/scripts/dist/README.md +1 -1
- package/scripts/setup-wizard.mjs +781 -0
- package/server.json +1 -0
- package/dist/externalClientLib.d.ts +0 -1
- package/dist/externalClientLib.js +0 -2
- package/dist/portableClientWrapper.d.ts +0 -1
- package/dist/portableClientWrapper.js +0 -2
- package/dist/services/indexingService.d.ts +0 -1
- package/dist/services/indexingService.js +0 -2
|
@@ -18,6 +18,7 @@ exports.__resetGraphCache = __resetGraphCache;
|
|
|
18
18
|
const registry_1 = require("../server/registry");
|
|
19
19
|
const indexContext_1 = require("./indexContext");
|
|
20
20
|
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
21
|
+
const logger_js_1 = require("./logger.js");
|
|
21
22
|
// NOTE: For enriched responses we bump schema version to 2 (only when enrich=true)
|
|
22
23
|
const GRAPH_SCHEMA_VERSION_V1 = 1;
|
|
23
24
|
const GRAPH_SCHEMA_VERSION_V2 = 2;
|
|
@@ -216,8 +217,7 @@ function buildGraph(params, graphCfg = (0, runtimeConfig_1.getRuntimeConfig)().g
|
|
|
216
217
|
const graph = buildGraph(p, graphCfg);
|
|
217
218
|
// Defensive: unexpected undefined safeguard (should never happen). Emit diagnostic once.
|
|
218
219
|
if (!graph) {
|
|
219
|
-
|
|
220
|
-
console.error('[graph_export] buildGraph returned undefined - returning empty graph (diagnostic)');
|
|
220
|
+
(0, logger_js_1.logError)('[graph_export] buildGraph returned undefined - returning empty graph (diagnostic)');
|
|
221
221
|
return { meta: { graphSchemaVersion: 1, nodeCount: 0, edgeCount: 0 }, nodes: [], edges: [] };
|
|
222
222
|
}
|
|
223
223
|
if (cacheEligible && !envExplicit) {
|
|
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
* onboarding guidance so a naive / first-time agent can self-bootstrap:
|
|
8
8
|
* - Discover tools & their purpose
|
|
9
9
|
* - Understand local (P0) vs indexed (P1+) lifecycle & promotion workflow
|
|
10
|
-
* - Learn safe mutation
|
|
10
|
+
* - Learn safe mutation override pattern (INDEX_SERVER_MUTATION)
|
|
11
11
|
* - Follow a deterministic promotion checklist
|
|
12
12
|
* - Avoid governance/spec recursion (documents intentionally NOT ingested)
|
|
13
13
|
*/
|
|
@@ -64,7 +64,7 @@ function buildSections() {
|
|
|
64
64
|
{
|
|
65
65
|
id: 'mutation-safety',
|
|
66
66
|
title: 'Safe Mutation',
|
|
67
|
-
content: '
|
|
67
|
+
content: 'Write operations are enabled by default, but bootstrap confirmation and reference mode still gate risky changes. Set INDEX_SERVER_MUTATION=0 when you need an explicit read-only runtime.'
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
id: 'recursion-safeguards',
|
|
@@ -48,6 +48,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
48
48
|
const registry_1 = require("../server/registry");
|
|
49
49
|
const fs = __importStar(require("fs"));
|
|
50
50
|
const path = __importStar(require("path"));
|
|
51
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
51
52
|
const SCHEMA_VERSION = '1.0.0';
|
|
52
53
|
/**
|
|
53
54
|
* Load the canonical instruction.schema.json from disk
|
|
@@ -158,11 +159,12 @@ function definePromotionWorkflow() {
|
|
|
158
159
|
* Define key validation rules
|
|
159
160
|
*/
|
|
160
161
|
function defineValidationRules() {
|
|
162
|
+
const bodyWarnLength = (0, runtimeConfig_1.getRuntimeConfig)().index.bodyWarnLength.toLocaleString('en-US');
|
|
161
163
|
return [
|
|
162
164
|
{ field: 'id', rule: 'Pattern', constraint: '^[a-z0-9](?:[a-z0-9-_]{0,118}[a-z0-9])?$ (120 chars max, lowercase, no leading/trailing hyphen/underscore)' },
|
|
163
165
|
{ field: 'id', rule: 'Uniqueness', constraint: 'Must be unique across the index' },
|
|
164
166
|
{ field: 'title', rule: 'Length', constraint: '1-200 characters, non-empty' },
|
|
165
|
-
{ field: 'body', rule: 'Length', constraint:
|
|
167
|
+
{ field: 'body', rule: 'Length', constraint: `1-${bodyWarnLength} characters on add/import writes (INDEX_SERVER_BODY_WARN_LENGTH), markdown supported` },
|
|
166
168
|
{ field: 'priority', rule: 'Range', constraint: '1-100 (lower number = higher priority)' },
|
|
167
169
|
{ field: 'audience', rule: 'Enum', constraint: 'One of: individual, group, all' },
|
|
168
170
|
{ field: 'requirement', rule: 'Enum', constraint: 'One of: mandatory, critical, recommended, optional, deprecated' },
|
|
@@ -216,7 +218,7 @@ function defineValidationRules() {
|
|
|
216
218
|
'1. Review the minimalExample for required fields',
|
|
217
219
|
'2. Study promotionWorkflow stages (P0 → P1 → P2+)',
|
|
218
220
|
'3. Validate against validationRules before submission',
|
|
219
|
-
'4. Use index_dispatch {action: "add"} to create (
|
|
221
|
+
'4. Use index_dispatch {action: "add"} to create (writes are enabled by default; set INDEX_SERVER_MUTATION=0 for read-only mode)',
|
|
220
222
|
'5. Monitor index_health for recursionRisk and drift',
|
|
221
223
|
'6. Track usage with usage_track',
|
|
222
224
|
'7. Iterate via index_dispatch {action: "update"} as needed',
|
|
@@ -9,27 +9,47 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const registry_1 = require("../server/registry");
|
|
10
10
|
const indexContext_1 = require("./indexContext");
|
|
11
11
|
const features_1 = require("./features");
|
|
12
|
-
(0, registry_1.registerHandler)('integrity_verify', () => {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
12
|
+
(0, registry_1.registerHandler)('integrity_verify', () => {
|
|
13
|
+
const st = (0, indexContext_1.ensureLoaded)();
|
|
14
|
+
const issues = [];
|
|
15
|
+
for (const e of st.list) {
|
|
16
|
+
const actual = crypto_1.default.createHash('sha256').update(e.body, 'utf8').digest('hex');
|
|
17
|
+
if (actual !== e.sourceHash) {
|
|
18
|
+
issues.push({ id: e.id, expected: e.sourceHash, actual });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return { hash: st.hash, count: st.list.length, issues, issueCount: issues.length };
|
|
22
|
+
});
|
|
23
|
+
(0, registry_1.registerHandler)('integrity_manifest', () => {
|
|
24
|
+
const manifestPath = path_1.default.join(process.cwd(), 'snapshots', 'index-manifest.json');
|
|
25
|
+
if (!fs_1.default.existsSync(manifestPath))
|
|
26
|
+
return { manifest: 'missing' };
|
|
27
|
+
let manifest;
|
|
28
|
+
try {
|
|
29
|
+
manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
return { manifest: 'invalid', error: e instanceof Error ? e.message : String(e) };
|
|
33
|
+
}
|
|
34
|
+
const entries = Array.isArray(manifest.entries) ? manifest.entries : [];
|
|
35
|
+
const map = new Map(entries.map(e => [e.id, e]));
|
|
36
|
+
const st = (0, indexContext_1.ensureLoaded)();
|
|
37
|
+
const drift = [];
|
|
38
|
+
for (const e of st.list) {
|
|
39
|
+
const entry = map.get(e.id);
|
|
40
|
+
const bodyHash = crypto_1.default.createHash('sha256').update(e.body, 'utf8').digest('hex');
|
|
41
|
+
if (!entry) {
|
|
42
|
+
drift.push({ id: e.id, change: 'added' });
|
|
43
|
+
}
|
|
44
|
+
else if (entry.sourceHash !== e.sourceHash || entry.bodyHash !== bodyHash) {
|
|
45
|
+
drift.push({ id: e.id, change: 'hash-mismatch' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const id of map.keys()) {
|
|
49
|
+
if (!st.byId.has(id))
|
|
50
|
+
drift.push({ id, change: 'removed' });
|
|
51
|
+
}
|
|
52
|
+
return { manifest: 'present', drift: drift.length, details: drift };
|
|
53
|
+
});
|
|
34
54
|
// Phase 0: feature flags status
|
|
35
55
|
(0, registry_1.registerHandler)('feature_status', () => (0, features_1.featureStatus)());
|
|
@@ -138,7 +138,7 @@ function _resetMailbox() {
|
|
|
138
138
|
(0, registry_1.registerHandler)('messaging_purge', (params = {}) => {
|
|
139
139
|
const mailbox = getMailbox();
|
|
140
140
|
let removed;
|
|
141
|
-
let action
|
|
141
|
+
let action;
|
|
142
142
|
if (params.all) {
|
|
143
143
|
removed = mailbox.purgeAll();
|
|
144
144
|
action = 'purge_all';
|
|
@@ -10,7 +10,22 @@ const InstanceManager_1 = require("../dashboard/server/InstanceManager");
|
|
|
10
10
|
const fs_1 = __importDefault(require("fs"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const validationService_1 = require("./validationService");
|
|
13
|
-
|
|
13
|
+
const auditLog_1 = require("./auditLog");
|
|
14
|
+
const features_2 = require("./features");
|
|
15
|
+
(0, registry_1.registerHandler)('metrics_snapshot', () => {
|
|
16
|
+
const raw = (0, registry_1.getMetricsRaw)();
|
|
17
|
+
const methods = Object.entries(raw)
|
|
18
|
+
.map(([method, rec]) => ({
|
|
19
|
+
method,
|
|
20
|
+
count: rec.count,
|
|
21
|
+
avgMs: rec.count ? +(rec.totalMs / rec.count).toFixed(2) : 0,
|
|
22
|
+
maxMs: +rec.maxMs.toFixed(2),
|
|
23
|
+
}))
|
|
24
|
+
.sort((a, b) => a.method.localeCompare(b.method));
|
|
25
|
+
const features = (0, features_1.featureStatus)();
|
|
26
|
+
const validation = (0, validationService_1.getValidationMetrics)();
|
|
27
|
+
return { generatedAt: new Date().toISOString(), methods, features, validation };
|
|
28
|
+
});
|
|
14
29
|
// health_check retained here (meta_tools provided by shim for rich output)
|
|
15
30
|
// Resolve version locally (mirrors transport logic) to avoid import cycles
|
|
16
31
|
let VERSION = '0.0.0';
|
|
@@ -23,21 +38,51 @@ try {
|
|
|
23
38
|
}
|
|
24
39
|
}
|
|
25
40
|
catch { /* ignore */ }
|
|
26
|
-
(0, registry_1.registerHandler)('health_check', () => {
|
|
41
|
+
(0, registry_1.registerHandler)('health_check', async () => {
|
|
27
42
|
let summary;
|
|
28
43
|
try {
|
|
29
|
-
const st = (0, indexContext_1.
|
|
44
|
+
const st = await (0, indexContext_1.getIndexStateAsync)();
|
|
30
45
|
if (st.loadSummary) {
|
|
31
46
|
const s = st.loadSummary;
|
|
32
|
-
summary = {
|
|
47
|
+
summary = {
|
|
48
|
+
scanned: s.scanned,
|
|
49
|
+
accepted: s.accepted,
|
|
50
|
+
skipped: s.skipped,
|
|
51
|
+
reasons: s.reasons,
|
|
52
|
+
salvage: s.salvage,
|
|
53
|
+
softWarnings: s.softWarnings,
|
|
54
|
+
};
|
|
33
55
|
}
|
|
34
56
|
}
|
|
35
57
|
catch { /* swallow to keep health resilient */ }
|
|
36
58
|
// Instance discovery — resilient: never fail health due to port-file read errors
|
|
37
59
|
let instances = [];
|
|
38
60
|
try {
|
|
39
|
-
instances = (0, InstanceManager_1.getActiveInstances)().map(i => ({
|
|
61
|
+
instances = (0, InstanceManager_1.getActiveInstances)().map(i => ({
|
|
62
|
+
pid: i.pid,
|
|
63
|
+
port: i.port,
|
|
64
|
+
host: i.host,
|
|
65
|
+
startedAt: i.startedAt,
|
|
66
|
+
current: i.current,
|
|
67
|
+
}));
|
|
40
68
|
}
|
|
41
69
|
catch { /* swallow */ }
|
|
42
|
-
|
|
70
|
+
// Expose usage invariant repair counters so operators can see silent data reconstruction
|
|
71
|
+
const allCounters = (0, features_2.getCounters)();
|
|
72
|
+
const repairCounters = {};
|
|
73
|
+
for (const [key, val] of Object.entries(allCounters)) {
|
|
74
|
+
if (key.startsWith('usage:') && val > 0)
|
|
75
|
+
repairCounters[key] = val;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
status: 'ok',
|
|
79
|
+
timestamp: new Date().toISOString(),
|
|
80
|
+
version: VERSION,
|
|
81
|
+
pid: process.pid,
|
|
82
|
+
uptime: Math.round(process.uptime()),
|
|
83
|
+
index: summary,
|
|
84
|
+
instances,
|
|
85
|
+
audit: (0, auditLog_1.getAuditLogHealth)(),
|
|
86
|
+
...(Object.keys(repairCounters).length ? { usageRepairs: repairCounters } : {}),
|
|
87
|
+
};
|
|
43
88
|
});
|
|
@@ -3,5 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const registry_1 = require("../server/registry");
|
|
4
4
|
const promptReviewService_1 = require("./promptReviewService");
|
|
5
5
|
const promptService = new promptReviewService_1.PromptReviewService();
|
|
6
|
-
(0, registry_1.registerHandler)('prompt_review', (p) => {
|
|
7
|
-
|
|
6
|
+
(0, registry_1.registerHandler)('prompt_review', (p) => {
|
|
7
|
+
const raw = p.prompt || '';
|
|
8
|
+
const MAX = 10_000;
|
|
9
|
+
if (raw.length > MAX)
|
|
10
|
+
return { truncated: true, message: 'prompt too large', max: MAX };
|
|
11
|
+
const sanitized = raw.replace(/\0/g, '');
|
|
12
|
+
const issues = promptService.review(sanitized);
|
|
13
|
+
const summary = (0, promptReviewService_1.summarizeIssues)(issues);
|
|
14
|
+
return { issues, summary, length: sanitized.length };
|
|
15
|
+
});
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* - Proper tool registration
|
|
20
20
|
* - Input sanitization and limits
|
|
21
21
|
*/
|
|
22
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
|
+
};
|
|
22
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
26
|
exports.handleInstructionsSearch = handleInstructionsSearch;
|
|
24
27
|
exports.buildAfterRetrievalMeta = buildAfterRetrievalMeta;
|
|
@@ -28,6 +31,7 @@ const indexContext_1 = require("./indexContext");
|
|
|
28
31
|
const errors_1 = require("./errors");
|
|
29
32
|
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
30
33
|
const embeddingService_1 = require("./embeddingService");
|
|
34
|
+
const safe_regex2_1 = __importDefault(require("safe-regex2"));
|
|
31
35
|
const SEARCH_SCHEMA = {
|
|
32
36
|
type: 'object',
|
|
33
37
|
required: ['keywords'],
|
|
@@ -42,6 +46,7 @@ const SEARCH_SCHEMA = {
|
|
|
42
46
|
example: { keywords: ['build', 'validate', 'discipline'], limit: 10, includeCategories: true }
|
|
43
47
|
};
|
|
44
48
|
const VALID_MODES = ['keyword', 'regex', 'semantic'];
|
|
49
|
+
const MAX_REGEX_PATTERN_LENGTH = 200;
|
|
45
50
|
function normalizeSearchText(text, caseSensitive) {
|
|
46
51
|
const normalized = text
|
|
47
52
|
.normalize('NFD')
|
|
@@ -123,18 +128,32 @@ function buildKeywordSearchContext(instructions, keywords, caseSensitive, includ
|
|
|
123
128
|
/**
|
|
124
129
|
* Calculate relevance score for an instruction based on keyword matches
|
|
125
130
|
*/
|
|
126
|
-
function calculateRelevance(instruction, keywords, caseSensitive, includeCategories, mode = 'keyword', keywordContext) {
|
|
131
|
+
function calculateRelevance(instruction, keywords, caseSensitive, includeCategories, mode = 'keyword', keywordContext, regexKeywords) {
|
|
127
132
|
let score = 0;
|
|
128
133
|
const matchedFieldSet = new Set();
|
|
129
134
|
const prepareText = (text) => caseSensitive ? text : text.toLowerCase();
|
|
130
135
|
const preparedKeywords = keywords.map(k => mode === 'keyword' ? prepareText(k) : k);
|
|
131
136
|
const regexFlags = caseSensitive ? 'g' : 'gi';
|
|
137
|
+
const compiledRegexKeywords = mode === 'regex'
|
|
138
|
+
? (regexKeywords ?? keywords.map((keyword) => {
|
|
139
|
+
// Defense-in-depth: production callers route through compileRegexKeywords →
|
|
140
|
+
// validateRegexKeyword. Re-validate here in the fallback path so direct
|
|
141
|
+
// invocations (tests, future handlers) cannot bypass ReDoS / unsupported-
|
|
142
|
+
// construct rejection. Throws on invalid pattern.
|
|
143
|
+
return {
|
|
144
|
+
source: keyword,
|
|
145
|
+
testRegex: compileSafeUserRegex(keyword, caseSensitive ? '' : 'i'),
|
|
146
|
+
countRegex: compileSafeUserRegex(keyword, regexFlags),
|
|
147
|
+
};
|
|
148
|
+
}))
|
|
149
|
+
: [];
|
|
132
150
|
// Build matchers: regex mode uses raw patterns, keyword mode uses substring/escaped regex
|
|
133
151
|
const testMatch = (text, keyword) => {
|
|
134
152
|
if (mode === 'regex') {
|
|
135
153
|
try {
|
|
136
|
-
|
|
137
|
-
|
|
154
|
+
const compiled = keyword;
|
|
155
|
+
compiled.testRegex.lastIndex = 0;
|
|
156
|
+
return compiled.testRegex.test(text); // lgtm[js/regex-injection] — patterns pre-validated and pre-compiled at handler entry
|
|
138
157
|
}
|
|
139
158
|
catch {
|
|
140
159
|
return false;
|
|
@@ -228,7 +247,9 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
228
247
|
const countMatches = (text, keyword) => {
|
|
229
248
|
if (mode === 'regex') {
|
|
230
249
|
try {
|
|
231
|
-
|
|
250
|
+
const compiled = keyword;
|
|
251
|
+
compiled.countRegex.lastIndex = 0;
|
|
252
|
+
return (text.match(compiled.countRegex) || []).length; // lgtm[js/regex-injection] — patterns pre-validated and pre-compiled at handler entry
|
|
232
253
|
}
|
|
233
254
|
catch {
|
|
234
255
|
return 0;
|
|
@@ -237,7 +258,7 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
237
258
|
return (text.match(new RegExp(escapeRegex(keyword), regexFlags)) || []).length;
|
|
238
259
|
};
|
|
239
260
|
let idMatches = 0;
|
|
240
|
-
for (const keyword of preparedKeywords) {
|
|
261
|
+
for (const keyword of mode === 'regex' ? compiledRegexKeywords : preparedKeywords) {
|
|
241
262
|
if (testMatch(instruction.id, keyword)) {
|
|
242
263
|
idMatches += countMatches(instruction.id, keyword);
|
|
243
264
|
}
|
|
@@ -247,7 +268,7 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
247
268
|
matchedFieldSet.add('id');
|
|
248
269
|
}
|
|
249
270
|
let titleMatches = 0;
|
|
250
|
-
for (const keyword of preparedKeywords) {
|
|
271
|
+
for (const keyword of mode === 'regex' ? compiledRegexKeywords : preparedKeywords) {
|
|
251
272
|
titleMatches += countMatches(instruction.title, keyword);
|
|
252
273
|
}
|
|
253
274
|
if (titleMatches > 0) {
|
|
@@ -255,7 +276,7 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
255
276
|
matchedFieldSet.add('title');
|
|
256
277
|
}
|
|
257
278
|
let summaryMatches = 0;
|
|
258
|
-
for (const keyword of preparedKeywords) {
|
|
279
|
+
for (const keyword of mode === 'regex' ? compiledRegexKeywords : preparedKeywords) {
|
|
259
280
|
summaryMatches += countMatches(instruction.semanticSummary || '', keyword);
|
|
260
281
|
}
|
|
261
282
|
if (summaryMatches > 0) {
|
|
@@ -263,7 +284,7 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
263
284
|
matchedFieldSet.add('semanticSummary');
|
|
264
285
|
}
|
|
265
286
|
let bodyMatches = 0;
|
|
266
|
-
for (const keyword of preparedKeywords) {
|
|
287
|
+
for (const keyword of mode === 'regex' ? compiledRegexKeywords : preparedKeywords) {
|
|
267
288
|
bodyMatches += countMatches(instruction.body, keyword);
|
|
268
289
|
}
|
|
269
290
|
if (bodyMatches > 0) {
|
|
@@ -273,7 +294,7 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
273
294
|
if (includeCategories && instruction.categories?.length) {
|
|
274
295
|
const categoryText = instruction.categories.join(' ');
|
|
275
296
|
let categoryMatches = 0;
|
|
276
|
-
for (const keyword of preparedKeywords) {
|
|
297
|
+
for (const keyword of mode === 'regex' ? compiledRegexKeywords : preparedKeywords) {
|
|
277
298
|
categoryMatches += countMatches(categoryText, keyword);
|
|
278
299
|
}
|
|
279
300
|
if (categoryMatches > 0) {
|
|
@@ -282,13 +303,14 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
282
303
|
}
|
|
283
304
|
}
|
|
284
305
|
const uniqueMatches = new Set();
|
|
285
|
-
for (const keyword of preparedKeywords) {
|
|
306
|
+
for (const keyword of mode === 'regex' ? compiledRegexKeywords : preparedKeywords) {
|
|
307
|
+
const keywordSource = mode === 'regex' ? keyword.source : keyword;
|
|
286
308
|
if (testMatch(instruction.id, keyword) ||
|
|
287
309
|
testMatch(instruction.title, keyword) ||
|
|
288
310
|
testMatch(instruction.semanticSummary || '', keyword) ||
|
|
289
311
|
testMatch(instruction.body, keyword) ||
|
|
290
312
|
(includeCategories && instruction.categories?.some((cat) => testMatch(cat, keyword)))) {
|
|
291
|
-
uniqueMatches.add(
|
|
313
|
+
uniqueMatches.add(keywordSource);
|
|
292
314
|
}
|
|
293
315
|
}
|
|
294
316
|
if (uniqueMatches.size > 1) {
|
|
@@ -302,6 +324,58 @@ function calculateRelevance(instruction, keywords, caseSensitive, includeCategor
|
|
|
302
324
|
function escapeRegex(string) {
|
|
303
325
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
304
326
|
}
|
|
327
|
+
function sanitizeKeywords(keywords) {
|
|
328
|
+
return keywords
|
|
329
|
+
.filter(k => typeof k === 'string' && k.trim().length > 0)
|
|
330
|
+
.map(k => k.trim())
|
|
331
|
+
.slice(0, 10);
|
|
332
|
+
}
|
|
333
|
+
function validateRegexKeyword(keyword) {
|
|
334
|
+
if (keyword.length > MAX_REGEX_PATTERN_LENGTH) {
|
|
335
|
+
throw new Error(`Regex patterns must not exceed ${MAX_REGEX_PATTERN_LENGTH} characters to prevent ReDoS`);
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
new RegExp(keyword); // lgtm[js/regex-injection] — this IS the syntax validation step
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
throw new Error(`Invalid regex pattern "${keyword}": check syntax and try again`);
|
|
342
|
+
}
|
|
343
|
+
if (/\(\?(?:[=!]|<[=!])/.test(keyword)) {
|
|
344
|
+
throw new Error('Regex pattern rejected: lookaround assertions are not supported in regex search mode');
|
|
345
|
+
}
|
|
346
|
+
if (/\\[1-9]/.test(keyword)) {
|
|
347
|
+
throw new Error('Regex pattern rejected: backreferences are not supported in regex search mode');
|
|
348
|
+
}
|
|
349
|
+
if (/\([^)]*[+*?}]\)[+*?{]/.test(keyword)) {
|
|
350
|
+
throw new Error('Regex pattern rejected: nested quantifiers can cause catastrophic backtracking');
|
|
351
|
+
}
|
|
352
|
+
if (/\)[+*?}][^(]*\)[+*?{]/.test(keyword)) {
|
|
353
|
+
throw new Error('Regex pattern rejected: nested quantifiers can cause catastrophic backtracking');
|
|
354
|
+
}
|
|
355
|
+
if (/\([^)]*\|[^)]*\)[+*?{]/.test(keyword)) {
|
|
356
|
+
throw new Error('Regex pattern rejected: alternation with quantifiers can cause catastrophic backtracking');
|
|
357
|
+
}
|
|
358
|
+
if (!(0, safe_regex2_1.default)(keyword)) {
|
|
359
|
+
throw new Error('Regex pattern rejected: potentially catastrophic backtracking detected');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Compile a user-supplied regex pattern after running ReDoS / unsupported-
|
|
364
|
+
* construct validation. This is the single trusted construction site for
|
|
365
|
+
* `new RegExp(<user input>)` in the search pipeline; all callers must route
|
|
366
|
+
* through here so the validation step is provably adjacent to construction.
|
|
367
|
+
*/
|
|
368
|
+
function compileSafeUserRegex(pattern, flags) {
|
|
369
|
+
validateRegexKeyword(pattern);
|
|
370
|
+
return new RegExp(pattern, flags); // lgtm[js/regex-injection] — pattern validated by validateRegexKeyword above
|
|
371
|
+
}
|
|
372
|
+
function compileRegexKeywords(keywords, caseSensitive) {
|
|
373
|
+
return keywords.map((keyword) => ({
|
|
374
|
+
source: keyword,
|
|
375
|
+
testRegex: compileSafeUserRegex(keyword, caseSensitive ? '' : 'i'),
|
|
376
|
+
countRegex: compileSafeUserRegex(keyword, caseSensitive ? 'g' : 'gi'),
|
|
377
|
+
}));
|
|
378
|
+
}
|
|
305
379
|
/**
|
|
306
380
|
* Load and search instructions from the index
|
|
307
381
|
*/
|
|
@@ -325,10 +399,7 @@ function performSearch(params) {
|
|
|
325
399
|
throw new Error(`Invalid contentType: must be one of ${validContentTypes.join(', ')}`);
|
|
326
400
|
}
|
|
327
401
|
// Validate and sanitize keywords
|
|
328
|
-
const sanitizedKeywords = keywords
|
|
329
|
-
.filter(k => typeof k === 'string' && k.trim().length > 0)
|
|
330
|
-
.map(k => k.trim())
|
|
331
|
-
.slice(0, 10); // Enforce max 10 keywords
|
|
402
|
+
const sanitizedKeywords = sanitizeKeywords(keywords);
|
|
332
403
|
if (sanitizedKeywords.length === 0) {
|
|
333
404
|
throw new Error('At least one valid keyword is required');
|
|
334
405
|
}
|
|
@@ -351,7 +422,7 @@ function performSearch(params) {
|
|
|
351
422
|
continue; // Skip instructions that don't match the contentType filter
|
|
352
423
|
}
|
|
353
424
|
}
|
|
354
|
-
const { score, matchedFields } = calculateRelevance(instruction, sanitizedKeywords, caseSensitive, includeCategories, mode, keywordContext);
|
|
425
|
+
const { score, matchedFields } = calculateRelevance(instruction, sanitizedKeywords, caseSensitive, includeCategories, mode, keywordContext, params.compiledRegexKeywords);
|
|
355
426
|
if (score > 0) {
|
|
356
427
|
results.push({
|
|
357
428
|
instructionId: instruction.id,
|
|
@@ -496,33 +567,11 @@ async function handleInstructionsSearch(params) {
|
|
|
496
567
|
throw new Error(`Invalid mode: must be one of ${VALID_MODES.join(', ')}`);
|
|
497
568
|
}
|
|
498
569
|
(0, logger_1.logInfo)(`[search] Search request: mode=${mode}, keywords=[${params.keywords.join(', ')}], limit=${params.limit ?? 50}, contentType=${params.contentType ?? 'any'}`);
|
|
570
|
+
const sanitizedKeywords = sanitizeKeywords(params.keywords);
|
|
499
571
|
// Regex mode validation: pattern safety checks
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
throw new Error('Regex patterns must not exceed 200 characters to prevent ReDoS');
|
|
504
|
-
}
|
|
505
|
-
// Reject patterns with nested quantifiers that cause catastrophic backtracking
|
|
506
|
-
if (/\([^)]*[+*}]\)[+*{]/.test(keyword)) {
|
|
507
|
-
throw new Error('Regex pattern rejected: nested quantifiers can cause catastrophic backtracking');
|
|
508
|
-
}
|
|
509
|
-
// Also catch double-nested quantified groups like ((a)+)+ where inner )+
|
|
510
|
-
// is followed by more chars and another )+
|
|
511
|
-
if (/\)[+*}][^(]*\)[+*{]/.test(keyword)) {
|
|
512
|
-
throw new Error('Regex pattern rejected: nested quantifiers can cause catastrophic backtracking');
|
|
513
|
-
}
|
|
514
|
-
// Reject overlapping alternations with quantifiers: (a|a)+
|
|
515
|
-
if (/\([^)]*\|[^)]*\)[+*]{1,}/.test(keyword)) {
|
|
516
|
-
throw new Error('Regex pattern rejected: alternation with quantifiers can cause catastrophic backtracking');
|
|
517
|
-
}
|
|
518
|
-
try {
|
|
519
|
-
new RegExp(keyword); // lgtm[js/regex-injection] — this IS the validation code
|
|
520
|
-
}
|
|
521
|
-
catch {
|
|
522
|
-
throw new Error(`Invalid regex pattern "${keyword}": check syntax and try again`);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
572
|
+
const compiledRegexKeywords = mode === 'regex'
|
|
573
|
+
? compileRegexKeywords(sanitizedKeywords, params.caseSensitive ?? false)
|
|
574
|
+
: undefined;
|
|
526
575
|
// Semantic mode: check feature flag
|
|
527
576
|
if (mode === 'semantic') {
|
|
528
577
|
const cfg = (0, runtimeConfig_1.getRuntimeConfig)().semantic;
|
|
@@ -534,12 +583,13 @@ async function handleInstructionsSearch(params) {
|
|
|
534
583
|
}
|
|
535
584
|
// Ensure case-insensitive search by default
|
|
536
585
|
const searchParams = {
|
|
537
|
-
keywords:
|
|
586
|
+
keywords: sanitizedKeywords,
|
|
538
587
|
mode: mode,
|
|
539
588
|
limit: params.limit,
|
|
540
589
|
includeCategories: params.includeCategories,
|
|
541
590
|
caseSensitive: params.caseSensitive ?? false, // Explicit default to false for case-insensitive search
|
|
542
|
-
contentType: params.contentType
|
|
591
|
+
contentType: params.contentType,
|
|
592
|
+
compiledRegexKeywords,
|
|
543
593
|
};
|
|
544
594
|
// Semantic mode: embedding-based similarity search
|
|
545
595
|
if (mode === 'semantic') {
|
|
@@ -30,6 +30,6 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
30
30
|
if (raw && Array.isArray(raw.records))
|
|
31
31
|
size = raw.records.length;
|
|
32
32
|
}
|
|
33
|
-
catch { /* ignore */ }
|
|
33
|
+
catch { /* ignore */ } // lgtm[js/file-system-race] — file path containment to cwd validated above
|
|
34
34
|
return { dumped: true, file, records: size, bytes, env: (0, tracing_1.summarizeTraceEnv)(), bufferEnabled: (0, tracing_1.getTraceBuffer)().length > 0 };
|
|
35
35
|
});
|
|
@@ -2,10 +2,41 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const registry_1 = require("../server/registry");
|
|
4
4
|
const indexContext_1 = require("./indexContext");
|
|
5
|
-
(0, registry_1.registerHandler)('usage_track', (p) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
(0, registry_1.registerHandler)('usage_track', (p) => {
|
|
6
|
+
if (!p.id)
|
|
7
|
+
return { error: 'missing id' };
|
|
8
|
+
const opts = { action: p.action, signal: p.signal, comment: p.comment };
|
|
9
|
+
const r = (0, indexContext_1.incrementUsage)(p.id, opts);
|
|
10
|
+
if (!r)
|
|
11
|
+
return { notFound: true };
|
|
12
|
+
return r;
|
|
13
|
+
});
|
|
14
|
+
(0, registry_1.registerHandler)('usage_hotset', (p) => {
|
|
15
|
+
const st = (0, indexContext_1.ensureLoaded)();
|
|
16
|
+
const snap = (0, indexContext_1.loadUsageSnapshot)();
|
|
17
|
+
const limit = Math.max(1, Math.min(p.limit ?? 10, 100));
|
|
18
|
+
const items = [...st.list]
|
|
19
|
+
.filter(e => (e.usageCount ?? 0) > 0)
|
|
20
|
+
.sort((a, b) => {
|
|
21
|
+
const ua = a.usageCount ?? 0;
|
|
22
|
+
const ub = b.usageCount ?? 0;
|
|
23
|
+
if (ub !== ua)
|
|
24
|
+
return ub - ua;
|
|
25
|
+
return (b.lastUsedAt || '').localeCompare(a.lastUsedAt || '');
|
|
26
|
+
})
|
|
27
|
+
.slice(0, limit)
|
|
28
|
+
.map(e => {
|
|
29
|
+
const rec = snap[e.id] || {};
|
|
30
|
+
const item = {
|
|
31
|
+
id: e.id,
|
|
32
|
+
usageCount: e.usageCount,
|
|
33
|
+
lastUsedAt: e.lastUsedAt,
|
|
34
|
+
};
|
|
35
|
+
if (rec.lastSignal)
|
|
36
|
+
item.lastSignal = rec.lastSignal;
|
|
37
|
+
if (rec.lastComment)
|
|
38
|
+
item.lastComment = rec.lastComment;
|
|
39
|
+
return item;
|
|
40
|
+
});
|
|
41
|
+
return { hash: st.hash, count: items.length, items, limit };
|
|
42
|
+
});
|
|
@@ -43,6 +43,17 @@ export interface UsageTrackOptions {
|
|
|
43
43
|
signal?: string;
|
|
44
44
|
comment?: string;
|
|
45
45
|
}
|
|
46
|
+
declare const invariantRepairLog: {
|
|
47
|
+
ts: string;
|
|
48
|
+
id: string;
|
|
49
|
+
field: string;
|
|
50
|
+
source: string;
|
|
51
|
+
}[];
|
|
52
|
+
/** Returns a summary of invariant repairs for health check visibility. */
|
|
53
|
+
export declare function getInvariantRepairSummary(): {
|
|
54
|
+
totalRepairs: number;
|
|
55
|
+
recentRepairs: typeof invariantRepairLog;
|
|
56
|
+
};
|
|
46
57
|
export declare function clearUsageRateLimit(id?: string): void;
|
|
47
58
|
export declare function loadUsageSnapshot(): Record<string, UsagePersistRecord>;
|
|
48
59
|
export declare function getInstructionsDir(): string;
|
|
@@ -55,6 +66,7 @@ export declare function diagnoseInstructionsDir(): {
|
|
|
55
66
|
export declare function touchIndexVersion(): void;
|
|
56
67
|
export declare function markindexDirty(): void;
|
|
57
68
|
export declare function ensureLoaded(): IndexState;
|
|
69
|
+
export declare function ensureLoadedAsync(): Promise<IndexState>;
|
|
58
70
|
export interface IndexPollerOptions {
|
|
59
71
|
intervalMs?: number;
|
|
60
72
|
proactive?: boolean;
|
|
@@ -63,6 +75,7 @@ export declare function startIndexVersionPoller(opts?: IndexPollerOptions): void
|
|
|
63
75
|
export declare function stopIndexVersionPoller(): void;
|
|
64
76
|
export declare function invalidate(): void;
|
|
65
77
|
export declare function getIndexState(): IndexState;
|
|
78
|
+
export declare function getIndexStateAsync(): Promise<IndexState>;
|
|
66
79
|
export declare function getDebugIndexSnapshot(): {
|
|
67
80
|
dir: string;
|
|
68
81
|
fileCountOnDisk: number;
|
|
@@ -110,8 +123,15 @@ export declare function projectGovernance(e: InstructionEntry): {
|
|
|
110
123
|
changeLogLength: number;
|
|
111
124
|
};
|
|
112
125
|
export declare function computeGovernanceHash(entries: InstructionEntry[]): string;
|
|
113
|
-
export declare function
|
|
126
|
+
export declare function isDuplicateInstructionWriteError(error: unknown): boolean;
|
|
127
|
+
export declare function writeEntry(entry: InstructionEntry, opts?: {
|
|
128
|
+
createOnly?: boolean;
|
|
129
|
+
}): void;
|
|
130
|
+
export declare function writeEntryAsync(entry: InstructionEntry, opts?: {
|
|
131
|
+
createOnly?: boolean;
|
|
132
|
+
}): Promise<void>;
|
|
114
133
|
export declare function removeEntry(id: string): void;
|
|
115
134
|
export declare function scheduleUsagePersist(): void;
|
|
116
135
|
export declare function incrementUsage(id: string, opts?: UsageTrackOptions): Record<string, unknown> | null;
|
|
117
136
|
export declare function __testResetUsageState(): void;
|
|
137
|
+
export {};
|