@jagilber-org/index-server 1.22.1 → 1.26.4
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 +91 -2
- package/CODE_OF_CONDUCT.md +2 -0
- package/CONTRIBUTING.md +32 -2
- package/README.md +82 -19
- 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 +170 -53
- package/dist/dashboard/client/css/admin.css +132 -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 +5 -4
- 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 +263 -78
- 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 +1 -1
- 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 +12 -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/generate-certs.mjs +201 -0
- package/scripts/setup-wizard.mjs +781 -0
- package/server.json +20 -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
|
@@ -10,9 +10,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.migrateJsonToSqlite = migrateJsonToSqlite;
|
|
12
12
|
exports.migrateSqliteToJson = migrateSqliteToJson;
|
|
13
|
+
exports.migrateJsonEmbeddingsToStore = migrateJsonEmbeddingsToStore;
|
|
13
14
|
const fs_1 = __importDefault(require("fs"));
|
|
14
15
|
const path_1 = __importDefault(require("path"));
|
|
15
16
|
const jsonFileStore_js_1 = require("./jsonFileStore.js");
|
|
17
|
+
const jsonEmbeddingStore_js_1 = require("./jsonEmbeddingStore.js");
|
|
16
18
|
const sqliteStore_js_1 = require("./sqliteStore.js");
|
|
17
19
|
/**
|
|
18
20
|
* Migrate all instructions from JSON files to a SQLite database.
|
|
@@ -91,3 +93,32 @@ function migrateSqliteToJson(dbPath, jsonDir, opts) {
|
|
|
91
93
|
}
|
|
92
94
|
return { exported, errors };
|
|
93
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Migrate embeddings from a JSON file to an IEmbeddingStore (e.g. SqliteEmbeddingStore).
|
|
98
|
+
*
|
|
99
|
+
* Reads the JSON embedding cache and saves it into the target store.
|
|
100
|
+
* Idempotent: calling again with the same data overwrites safely.
|
|
101
|
+
*/
|
|
102
|
+
function migrateJsonEmbeddingsToStore(jsonEmbeddingPath, targetStore) {
|
|
103
|
+
try {
|
|
104
|
+
const jsonStore = new jsonEmbeddingStore_js_1.JsonEmbeddingStore(jsonEmbeddingPath);
|
|
105
|
+
const data = jsonStore.load();
|
|
106
|
+
jsonStore.close();
|
|
107
|
+
if (!data) {
|
|
108
|
+
return { migrated: 0, skipped: 0, error: 'No embedding data in JSON file' };
|
|
109
|
+
}
|
|
110
|
+
const count = Object.keys(data.embeddings).length;
|
|
111
|
+
if (count === 0) {
|
|
112
|
+
return { migrated: 0, skipped: 0 };
|
|
113
|
+
}
|
|
114
|
+
targetStore.save(data);
|
|
115
|
+
return { migrated: count, skipped: 0 };
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
return {
|
|
119
|
+
migrated: 0,
|
|
120
|
+
skipped: 0,
|
|
121
|
+
error: err instanceof Error ? err.message : 'Migration failed',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqliteEmbeddingStore — IEmbeddingStore backed by sqlite-vec (vec0 virtual table).
|
|
3
|
+
*
|
|
4
|
+
* Uses node:sqlite (DatabaseSync) with sqlite-vec extension for KNN vector search.
|
|
5
|
+
* Vectors stored as BLOB (Float32Array buffer), metadata in a companion table.
|
|
6
|
+
*
|
|
7
|
+
* Requires: Node.js ≥22.13.0, sqlite-vec npm package.
|
|
8
|
+
*/
|
|
9
|
+
import type { IEmbeddingStore, EmbeddingCacheData, EmbeddingSearchResult } from './types.js';
|
|
10
|
+
export declare class SqliteEmbeddingStore implements IEmbeddingStore {
|
|
11
|
+
private db;
|
|
12
|
+
private readonly dims;
|
|
13
|
+
private readonly dbPath;
|
|
14
|
+
constructor(dbPath: string, dims?: number);
|
|
15
|
+
private initExtension;
|
|
16
|
+
/**
|
|
17
|
+
* Run PRAGMA integrity_check to detect database corruption.
|
|
18
|
+
* @returns true if the database is intact, false if corrupt.
|
|
19
|
+
*/
|
|
20
|
+
private verifyIntegrity;
|
|
21
|
+
/**
|
|
22
|
+
* Rebuild a corrupt database by closing, deleting, and recreating it.
|
|
23
|
+
*/
|
|
24
|
+
private rebuildDatabase;
|
|
25
|
+
private initSchema;
|
|
26
|
+
load(): EmbeddingCacheData | null;
|
|
27
|
+
save(data: EmbeddingCacheData): void;
|
|
28
|
+
search(queryVector: Float32Array, limit: number): EmbeddingSearchResult[];
|
|
29
|
+
close(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SqliteEmbeddingStore — IEmbeddingStore backed by sqlite-vec (vec0 virtual table).
|
|
4
|
+
*
|
|
5
|
+
* Uses node:sqlite (DatabaseSync) with sqlite-vec extension for KNN vector search.
|
|
6
|
+
* Vectors stored as BLOB (Float32Array buffer), metadata in a companion table.
|
|
7
|
+
*
|
|
8
|
+
* Requires: Node.js ≥22.13.0, sqlite-vec npm package.
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.SqliteEmbeddingStore = void 0;
|
|
15
|
+
const node_sqlite_1 = require("node:sqlite");
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const sqlite_vec_1 = require("sqlite-vec");
|
|
19
|
+
const logger_js_1 = require("../logger.js");
|
|
20
|
+
const DEFAULT_VECTOR_DIMS = 384;
|
|
21
|
+
const MAX_VECTOR_DIMS = 65536;
|
|
22
|
+
const EMBEDDING_META_DDL = `CREATE TABLE IF NOT EXISTS embedding_meta (
|
|
23
|
+
instruction_id TEXT PRIMARY KEY,
|
|
24
|
+
model_name TEXT NOT NULL,
|
|
25
|
+
source_hash TEXT NOT NULL,
|
|
26
|
+
index_hash TEXT NOT NULL,
|
|
27
|
+
computed_at TEXT NOT NULL
|
|
28
|
+
)`;
|
|
29
|
+
/** Cache metadata stored in the SQLite metadata table. */
|
|
30
|
+
const META_INDEX_HASH_KEY = 'embedding_index_hash';
|
|
31
|
+
const META_MODEL_NAME_KEY = 'embedding_model_name';
|
|
32
|
+
class SqliteEmbeddingStore {
|
|
33
|
+
db;
|
|
34
|
+
dims;
|
|
35
|
+
dbPath;
|
|
36
|
+
constructor(dbPath, dims = DEFAULT_VECTOR_DIMS) {
|
|
37
|
+
if (!Number.isInteger(dims) || dims < 1 || dims > MAX_VECTOR_DIMS) {
|
|
38
|
+
throw new Error(`Invalid vector dimensions: ${dims}. Must be an integer between 1 and ${MAX_VECTOR_DIMS}.`);
|
|
39
|
+
}
|
|
40
|
+
this.dims = dims;
|
|
41
|
+
this.dbPath = dbPath;
|
|
42
|
+
this.db = new node_sqlite_1.DatabaseSync(dbPath, { allowExtension: true });
|
|
43
|
+
this.initExtension();
|
|
44
|
+
if (!this.verifyIntegrity()) {
|
|
45
|
+
this.rebuildDatabase();
|
|
46
|
+
}
|
|
47
|
+
this.initSchema();
|
|
48
|
+
}
|
|
49
|
+
initExtension() {
|
|
50
|
+
const extPath = (0, sqlite_vec_1.getLoadablePath)();
|
|
51
|
+
// Security: validate the extension path resolves within node_modules
|
|
52
|
+
const resolved = path_1.default.resolve(extPath);
|
|
53
|
+
const nmDir = path_1.default.resolve(__dirname, '..', '..', '..', 'node_modules');
|
|
54
|
+
if (!resolved.startsWith(nmDir + path_1.default.sep) && !resolved.startsWith(nmDir + '/')) {
|
|
55
|
+
throw new Error(`sqlite-vec extension path escapes node_modules: ${resolved}`);
|
|
56
|
+
}
|
|
57
|
+
this.db.loadExtension(extPath);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run PRAGMA integrity_check to detect database corruption.
|
|
61
|
+
* @returns true if the database is intact, false if corrupt.
|
|
62
|
+
*/
|
|
63
|
+
verifyIntegrity() {
|
|
64
|
+
try {
|
|
65
|
+
const result = this.db.prepare('PRAGMA integrity_check').all();
|
|
66
|
+
if (result.length === 1 && result[0].integrity_check === 'ok')
|
|
67
|
+
return true;
|
|
68
|
+
const issues = result.map(r => r.integrity_check).join('; ');
|
|
69
|
+
(0, logger_js_1.logWarn)(`[embedding-store] Integrity check failed: ${issues}`);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
(0, logger_js_1.logWarn)(`[embedding-store] Integrity check error: ${err instanceof Error ? err.message : 'unknown'}`);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Rebuild a corrupt database by closing, deleting, and recreating it.
|
|
79
|
+
*/
|
|
80
|
+
rebuildDatabase() {
|
|
81
|
+
(0, logger_js_1.logWarn)(`[embedding-store] Rebuilding corrupt database: ${this.dbPath}`);
|
|
82
|
+
try {
|
|
83
|
+
this.db.close();
|
|
84
|
+
}
|
|
85
|
+
catch { /* may already be unusable */ }
|
|
86
|
+
// Remove the corrupt DB and WAL/SHM files
|
|
87
|
+
for (const suffix of ['', '-wal', '-shm']) {
|
|
88
|
+
try {
|
|
89
|
+
fs_1.default.unlinkSync(this.dbPath + suffix);
|
|
90
|
+
}
|
|
91
|
+
catch { /* file may not exist */ }
|
|
92
|
+
}
|
|
93
|
+
this.db = new node_sqlite_1.DatabaseSync(this.dbPath, { allowExtension: true });
|
|
94
|
+
this.initExtension();
|
|
95
|
+
(0, logger_js_1.logInfo)(`[embedding-store] Database rebuilt successfully`);
|
|
96
|
+
}
|
|
97
|
+
initSchema() {
|
|
98
|
+
this.db.exec('PRAGMA journal_mode = WAL');
|
|
99
|
+
this.db.exec('PRAGMA busy_timeout = 5000');
|
|
100
|
+
// Ensure metadata table exists (may already exist from SqliteStore)
|
|
101
|
+
this.db.exec('CREATE TABLE IF NOT EXISTS metadata (key TEXT PRIMARY KEY, value TEXT)');
|
|
102
|
+
this.db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(
|
|
103
|
+
instruction_id TEXT PRIMARY KEY,
|
|
104
|
+
embedding float[${this.dims}]
|
|
105
|
+
)`);
|
|
106
|
+
this.db.exec(EMBEDDING_META_DDL);
|
|
107
|
+
}
|
|
108
|
+
load() {
|
|
109
|
+
// Read cache metadata
|
|
110
|
+
const hashRow = this.db.prepare('SELECT value FROM metadata WHERE key = ?').get(META_INDEX_HASH_KEY);
|
|
111
|
+
const modelRow = this.db.prepare('SELECT value FROM metadata WHERE key = ?').get(META_MODEL_NAME_KEY);
|
|
112
|
+
if (!hashRow)
|
|
113
|
+
return null;
|
|
114
|
+
// Read all embeddings
|
|
115
|
+
const rows = this.db.prepare('SELECT instruction_id, embedding FROM embeddings').all();
|
|
116
|
+
if (rows.length === 0) {
|
|
117
|
+
// CodeQL flagged the original `&& !hashRow` as dead code (already
|
|
118
|
+
// null-guarded at L115). We cannot upgrade to `if (rows.length === 0) return null`
|
|
119
|
+
// because the public contract (see embeddingStore.contract.spec.ts
|
|
120
|
+
// "save() with empty embeddings map succeeds") requires a non-null cache
|
|
121
|
+
// when hashRow exists but no embeddings have been persisted. Fall through
|
|
122
|
+
// to return { indexHash, entryHashes, embeddings: {} } so subsequent saves
|
|
123
|
+
// can layer onto the same metadata.
|
|
124
|
+
}
|
|
125
|
+
const embeddings = {};
|
|
126
|
+
for (const row of rows) {
|
|
127
|
+
// Validate buffer bounds before creating Float32Array view
|
|
128
|
+
const expectedBytes = this.dims * 4;
|
|
129
|
+
if (row.embedding.byteLength !== expectedBytes) {
|
|
130
|
+
(0, logger_js_1.logWarn)(`[embedding-store] Skipping entry '${row.instruction_id}': buffer size ${row.embedding.byteLength} bytes, expected ${expectedBytes} (${this.dims} dims × 4 bytes)`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
embeddings[row.instruction_id] = Array.from(new Float32Array(row.embedding.buffer, row.embedding.byteOffset, this.dims));
|
|
134
|
+
}
|
|
135
|
+
// Read entry hashes from embedding_meta
|
|
136
|
+
const metaRows = this.db.prepare('SELECT instruction_id, source_hash FROM embedding_meta').all();
|
|
137
|
+
const entryHashes = {};
|
|
138
|
+
for (const m of metaRows) {
|
|
139
|
+
entryHashes[m.instruction_id] = m.source_hash;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
indexHash: hashRow.value,
|
|
143
|
+
modelName: modelRow?.value,
|
|
144
|
+
entryHashes,
|
|
145
|
+
embeddings,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
save(data) {
|
|
149
|
+
// TODO: Replace full-table clear+reinsert with incremental upsert for large datasets.
|
|
150
|
+
// Use a diff of entryHashes to INSERT OR REPLACE only changed entries and DELETE removed ones.
|
|
151
|
+
// Use a transaction for atomicity
|
|
152
|
+
const tx = this.db.prepare('BEGIN');
|
|
153
|
+
const commit = this.db.prepare('COMMIT');
|
|
154
|
+
const rollback = this.db.prepare('ROLLBACK');
|
|
155
|
+
try {
|
|
156
|
+
tx.run();
|
|
157
|
+
// Clear existing data
|
|
158
|
+
this.db.exec('DELETE FROM embeddings');
|
|
159
|
+
this.db.exec('DELETE FROM embedding_meta');
|
|
160
|
+
// Upsert cache metadata
|
|
161
|
+
const upsertMeta = this.db.prepare('INSERT OR REPLACE INTO metadata (key, value) VALUES (?, ?)');
|
|
162
|
+
upsertMeta.run(META_INDEX_HASH_KEY, data.indexHash);
|
|
163
|
+
if (data.modelName) {
|
|
164
|
+
upsertMeta.run(META_MODEL_NAME_KEY, data.modelName);
|
|
165
|
+
}
|
|
166
|
+
// Insert embeddings
|
|
167
|
+
const insertVec = this.db.prepare('INSERT INTO embeddings (instruction_id, embedding) VALUES (?, ?)');
|
|
168
|
+
const insertMeta = this.db.prepare('INSERT INTO embedding_meta (instruction_id, model_name, source_hash, index_hash, computed_at) VALUES (?, ?, ?, ?, ?)');
|
|
169
|
+
const now = new Date().toISOString();
|
|
170
|
+
for (const [id, vec] of Object.entries(data.embeddings)) {
|
|
171
|
+
if (vec.length !== this.dims) {
|
|
172
|
+
throw new Error(`Vector dimension mismatch for '${id}': expected ${this.dims}, got ${vec.length}`);
|
|
173
|
+
}
|
|
174
|
+
for (let i = 0; i < vec.length; i++) {
|
|
175
|
+
if (!Number.isFinite(vec[i])) {
|
|
176
|
+
throw new Error(`Invalid vector value for '${id}' at index ${i}: ${vec[i]}. Vectors must contain only finite numbers.`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const buf = Buffer.from(new Float32Array(vec).buffer);
|
|
180
|
+
insertVec.run(id, buf);
|
|
181
|
+
insertMeta.run(id, data.modelName ?? 'unknown', data.entryHashes?.[id] ?? '', data.indexHash, now);
|
|
182
|
+
}
|
|
183
|
+
commit.run();
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
try {
|
|
187
|
+
rollback.run();
|
|
188
|
+
}
|
|
189
|
+
catch { /* rollback may fail if tx already aborted */ }
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
search(queryVector, limit) {
|
|
194
|
+
if (limit <= 0)
|
|
195
|
+
return [];
|
|
196
|
+
if (queryVector.length !== this.dims) {
|
|
197
|
+
(0, logger_js_1.logWarn)(`[embedding-store] Search query dimension mismatch: expected ${this.dims}, got ${queryVector.length}`);
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const buf = Buffer.from(queryVector.buffer, queryVector.byteOffset, queryVector.byteLength);
|
|
202
|
+
const rows = this.db.prepare('SELECT instruction_id, distance FROM embeddings WHERE embedding MATCH ? ORDER BY distance LIMIT ?').all(buf, limit);
|
|
203
|
+
return rows.map(r => ({
|
|
204
|
+
id: r.instruction_id,
|
|
205
|
+
distance: r.distance,
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
(0, logger_js_1.logWarn)(`[embedding-store] search failed: ${err instanceof Error ? err.message : 'unknown'}`);
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
close() {
|
|
214
|
+
try {
|
|
215
|
+
this.db.close();
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Already closed
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
exports.SqliteEmbeddingStore = SqliteEmbeddingStore;
|
|
@@ -23,7 +23,9 @@ export declare class SqliteStore implements IInstructionStore {
|
|
|
23
23
|
load(): LoadResult;
|
|
24
24
|
close(): void;
|
|
25
25
|
get(id: string): InstructionEntry | null;
|
|
26
|
-
write(entry: InstructionEntry
|
|
26
|
+
write(entry: InstructionEntry, opts?: {
|
|
27
|
+
createOnly?: boolean;
|
|
28
|
+
}): void;
|
|
27
29
|
remove(id: string): void;
|
|
28
30
|
list(opts?: ListOptions): InstructionEntry[];
|
|
29
31
|
query(opts: QueryOptions): InstructionEntry[];
|
|
@@ -162,8 +162,8 @@ class SqliteStore {
|
|
|
162
162
|
this.ensureLoaded();
|
|
163
163
|
return this.cache.get(id) ?? null;
|
|
164
164
|
}
|
|
165
|
-
write(entry) {
|
|
166
|
-
const sql =
|
|
165
|
+
write(entry, opts) {
|
|
166
|
+
const sql = `${opts?.createOnly ? 'INSERT INTO' : 'INSERT OR REPLACE INTO'} instructions (
|
|
167
167
|
id, title, body, rationale, priority, audience, requirement,
|
|
168
168
|
categories, content_type, primary_category, source_hash,
|
|
169
169
|
schema_version, deprecated_by, created_at, updated_at,
|
|
@@ -123,7 +123,9 @@ export interface IInstructionStore {
|
|
|
123
123
|
* Write (create or update) an instruction.
|
|
124
124
|
* @param entry - The instruction to persist.
|
|
125
125
|
*/
|
|
126
|
-
write(entry: InstructionEntry
|
|
126
|
+
write(entry: InstructionEntry, opts?: {
|
|
127
|
+
createOnly?: boolean;
|
|
128
|
+
}): void;
|
|
127
129
|
/**
|
|
128
130
|
* Remove an instruction by ID. No-op if not found.
|
|
129
131
|
* @param id - Instruction ID to remove.
|
|
@@ -169,3 +171,48 @@ export interface IInstructionStore {
|
|
|
169
171
|
*/
|
|
170
172
|
count(): number;
|
|
171
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Persisted embedding cache format (backwards-compatible: entryHashes is optional).
|
|
176
|
+
*/
|
|
177
|
+
export interface EmbeddingCacheData {
|
|
178
|
+
indexHash: string;
|
|
179
|
+
modelName?: string;
|
|
180
|
+
/** Per-entry content hashes for incremental invalidation (required for v2+). */
|
|
181
|
+
entryHashes?: Record<string, string>;
|
|
182
|
+
embeddings: Record<string, number[]>;
|
|
183
|
+
}
|
|
184
|
+
/** A single embedding search result with distance score. */
|
|
185
|
+
export interface EmbeddingSearchResult {
|
|
186
|
+
id: string;
|
|
187
|
+
distance: number;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Storage backend interface for embedding vectors.
|
|
191
|
+
*
|
|
192
|
+
* Implementations:
|
|
193
|
+
* - JsonEmbeddingStore: Flat JSON file (default, current behavior)
|
|
194
|
+
* - SqliteEmbeddingStore: sqlite-vec vec0 virtual table
|
|
195
|
+
*/
|
|
196
|
+
export interface IEmbeddingStore {
|
|
197
|
+
/**
|
|
198
|
+
* Load cached embedding data from the backing store.
|
|
199
|
+
* @returns The cached data, or null if no data exists.
|
|
200
|
+
*/
|
|
201
|
+
load(): EmbeddingCacheData | null;
|
|
202
|
+
/**
|
|
203
|
+
* Save embedding data to the backing store.
|
|
204
|
+
* @param data - The embedding cache data to persist.
|
|
205
|
+
*/
|
|
206
|
+
save(data: EmbeddingCacheData): void;
|
|
207
|
+
/**
|
|
208
|
+
* Search for the nearest vectors to a query vector (KNN).
|
|
209
|
+
* @param queryVector - The query embedding vector.
|
|
210
|
+
* @param limit - Maximum number of results to return.
|
|
211
|
+
* @returns Array of { id, distance } sorted by distance ascending.
|
|
212
|
+
*/
|
|
213
|
+
search(queryVector: Float32Array, limit: number): EmbeddingSearchResult[];
|
|
214
|
+
/**
|
|
215
|
+
* Close the store and release resources.
|
|
216
|
+
*/
|
|
217
|
+
close(): void;
|
|
218
|
+
}
|
|
@@ -10,8 +10,55 @@ exports.getToolRegistry = getToolRegistry;
|
|
|
10
10
|
*/
|
|
11
11
|
const schemas_1 = require("../schemas");
|
|
12
12
|
const featureFlags_1 = require("./featureFlags");
|
|
13
|
+
const envUtils_1 = require("../utils/envUtils");
|
|
14
|
+
const runtimeConfig_1 = require("../config/runtimeConfig");
|
|
13
15
|
// Input schema helpers (keep intentionally permissive if params optional)
|
|
14
16
|
const stringReq = (name) => ({ type: 'object', additionalProperties: false, required: [name], properties: { [name]: { type: 'string' } } });
|
|
17
|
+
const extensionsInputSchema = {
|
|
18
|
+
type: 'object',
|
|
19
|
+
additionalProperties: {
|
|
20
|
+
anyOf: [
|
|
21
|
+
{ type: 'string' },
|
|
22
|
+
{ type: 'number' },
|
|
23
|
+
{ type: 'boolean' },
|
|
24
|
+
{ type: 'array', items: {} },
|
|
25
|
+
{ type: 'object', additionalProperties: true },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const DANGEROUS_DIAGNOSTIC_TOOLS = new Set([
|
|
30
|
+
'diagnostics_block',
|
|
31
|
+
'diagnostics_microtaskFlood',
|
|
32
|
+
'diagnostics_memoryPressure',
|
|
33
|
+
]);
|
|
34
|
+
function buildInstructionBodyInputSchema(baseDescription) {
|
|
35
|
+
const maxLength = (0, runtimeConfig_1.getRuntimeConfig)().index.bodyWarnLength;
|
|
36
|
+
return {
|
|
37
|
+
type: 'string',
|
|
38
|
+
maxLength,
|
|
39
|
+
description: `${baseDescription} Current write limit: ${maxLength} characters via INDEX_SERVER_BODY_WARN_LENGTH. Split oversized content into cross-linked instructions.`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function withDynamicInstructionBodyLimits(name, inputSchema) {
|
|
43
|
+
const schema = JSON.parse(JSON.stringify(inputSchema));
|
|
44
|
+
if (name === 'index_add') {
|
|
45
|
+
const entryProps = schema.properties?.entry?.properties ?? {};
|
|
46
|
+
entryProps.body = buildInstructionBodyInputSchema('Instruction body.');
|
|
47
|
+
}
|
|
48
|
+
else if (name === 'index_import') {
|
|
49
|
+
const entries = schema.properties?.entries?.oneOf;
|
|
50
|
+
const arrayVariant = Array.isArray(entries) ? entries.find((candidate) => candidate.type === 'array') : undefined;
|
|
51
|
+
const itemProps = arrayVariant?.items?.properties ?? {};
|
|
52
|
+
itemProps.body = buildInstructionBodyInputSchema('Instruction body.');
|
|
53
|
+
}
|
|
54
|
+
else if (name === 'index_dispatch') {
|
|
55
|
+
const props = schema.properties ?? {};
|
|
56
|
+
const entryProps = props.entry?.properties ?? {};
|
|
57
|
+
entryProps.body = buildInstructionBodyInputSchema('Instruction body for action="add".');
|
|
58
|
+
props.body = buildInstructionBodyInputSchema('Flat instruction body for action="add".');
|
|
59
|
+
}
|
|
60
|
+
return schema;
|
|
61
|
+
}
|
|
15
62
|
// Explicit param schemas derived from handlers in toolHandlers.ts
|
|
16
63
|
const INPUT_SCHEMAS = {
|
|
17
64
|
// graph export (Phase 1 + Phase 2 enrichment). All params optional.
|
|
@@ -47,7 +94,7 @@ const INPUT_SCHEMAS = {
|
|
|
47
94
|
keywords: { type: 'array', items: { type: 'string' }, description: 'Explicit keyword array for search action when the caller wants direct token control.' },
|
|
48
95
|
ids: { type: 'array', items: { type: 'string' }, description: 'Array of instruction IDs for remove or export actions.' },
|
|
49
96
|
category: { type: 'string', description: 'Filter by category for list action.' },
|
|
50
|
-
contentType: { type: 'string', description: 'Filter by content type for list, search, or query actions.' },
|
|
97
|
+
contentType: { type: 'string', enum: ['instruction', 'template', 'chat-session', 'reference', 'example', 'agent'], description: 'Filter by content type for list, search, or query actions, or specify the entry content type for add action.' },
|
|
51
98
|
text: { type: 'string', description: 'Full-text search within query action.' },
|
|
52
99
|
includeCategories: { type: 'boolean', description: 'Search categories in addition to id/title/semanticSummary/body for search action.' },
|
|
53
100
|
caseSensitive: { type: 'boolean', description: 'Enable case-sensitive matching for search action.' },
|
|
@@ -59,6 +106,15 @@ const INPUT_SCHEMAS = {
|
|
|
59
106
|
offset: { type: 'number', description: 'Pagination offset (query action).' },
|
|
60
107
|
// Mutation params for add action (flat-param support: agents can pass these at top level instead of nested entry wrapper)
|
|
61
108
|
entry: { type: 'object', description: 'Instruction entry object for add action. Alternatively, pass id/body/title as top-level params.', additionalProperties: true, properties: { id: { type: 'string' }, title: { type: 'string' }, body: { type: 'string' } } },
|
|
109
|
+
priority: { type: 'number' },
|
|
110
|
+
audience: { type: 'string' },
|
|
111
|
+
requirement: { type: 'string' },
|
|
112
|
+
categories: { type: 'array', items: { type: 'string' } },
|
|
113
|
+
deprecatedBy: { type: 'string' },
|
|
114
|
+
riskScore: { type: 'number' },
|
|
115
|
+
version: { type: 'string' },
|
|
116
|
+
priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] },
|
|
117
|
+
classification: { type: 'string', enum: ['public', 'internal', 'restricted'] },
|
|
62
118
|
overwrite: { type: 'boolean', description: 'Allow overwriting existing instruction (add action).' },
|
|
63
119
|
lax: { type: 'boolean', description: 'Enable lax mode with default fills for missing optional fields (add action).' },
|
|
64
120
|
// Import action params
|
|
@@ -66,8 +122,8 @@ const INPUT_SCHEMAS = {
|
|
|
66
122
|
source: { type: 'string', description: 'Directory path containing .json instruction files to import (import action).' },
|
|
67
123
|
mode: { description: 'Import conflict resolution mode (import action) or groom mode object (groom action).' },
|
|
68
124
|
// Governance update params
|
|
69
|
-
owner: { type: 'string', description: 'Owner identifier for governanceUpdate action.' },
|
|
70
|
-
status: { type: 'string', description: 'Governance status for governanceUpdate action.', enum: ['approved', 'draft', 'deprecated'] },
|
|
125
|
+
owner: { type: 'string', description: 'Owner identifier for governanceUpdate action or add action.' },
|
|
126
|
+
status: { type: 'string', description: 'Governance status for governanceUpdate action or add action.', enum: ['approved', 'draft', 'review', 'deprecated'] },
|
|
71
127
|
bump: { type: 'string', description: 'Version bump level for governanceUpdate action.', enum: ['patch', 'minor', 'major', 'none'] },
|
|
72
128
|
lastReviewedAt: { type: 'string', description: 'Last review date (ISO 8601) for governanceUpdate action.' },
|
|
73
129
|
nextReviewDue: { type: 'string', description: 'Next review due date (ISO 8601) for governanceUpdate action.' },
|
|
@@ -91,8 +147,8 @@ const INPUT_SCHEMAS = {
|
|
|
91
147
|
// legacy read-only instruction method schemas removed in favor of dispatcher
|
|
92
148
|
'index_import': { type: 'object', additionalProperties: false, properties: {
|
|
93
149
|
entries: { oneOf: [
|
|
94
|
-
{ type: 'array', minItems: 1, items: { type: 'object', required: ['id', 'title', 'body', 'priority', 'audience', 'requirement'], additionalProperties:
|
|
95
|
-
id: { type: 'string' }, title: { type: 'string' }, body: { type: 'string',
|
|
150
|
+
{ type: 'array', minItems: 1, items: { type: 'object', required: ['id', 'title', 'body', 'priority', 'audience', 'requirement'], additionalProperties: false, properties: {
|
|
151
|
+
id: { type: 'string' }, title: { type: 'string' }, body: { type: 'string' }, rationale: { type: 'string' }, priority: { type: 'number' }, audience: { type: 'string' }, requirement: { type: 'string' }, categories: { type: 'array', items: { type: 'string' } }, version: { type: 'string' }, owner: { type: 'string' }, status: { type: 'string', enum: ['approved', 'draft', 'review', 'deprecated'] }, priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] }, classification: { type: 'string', enum: ['public', 'internal', 'restricted'] }, lastReviewedAt: { type: 'string' }, nextReviewDue: { type: 'string' }, semanticSummary: { type: 'string' }, changeLog: { type: 'array', items: { type: 'object', additionalProperties: true } }, contentType: { type: 'string', enum: ['instruction', 'template', 'chat-session', 'reference', 'example', 'agent'] }, extensions: extensionsInputSchema, mode: { type: 'string' }
|
|
96
152
|
} } },
|
|
97
153
|
{ type: 'string', description: 'Stringified JSON array of instruction entries, or a file path to a JSON array of instruction entries' }
|
|
98
154
|
] },
|
|
@@ -100,8 +156,8 @@ const INPUT_SCHEMAS = {
|
|
|
100
156
|
mode: { enum: ['skip', 'overwrite'] }
|
|
101
157
|
} },
|
|
102
158
|
'index_add': { type: 'object', additionalProperties: false, required: ['entry'], properties: {
|
|
103
|
-
entry: { type: 'object', required: ['id', 'body'], additionalProperties:
|
|
104
|
-
id: { type: 'string' }, title: { type: 'string' }, body: { type: 'string',
|
|
159
|
+
entry: { type: 'object', required: ['id', 'body'], additionalProperties: false, properties: {
|
|
160
|
+
id: { type: 'string', maxLength: 120 }, title: { type: 'string' }, body: { type: 'string' }, rationale: { type: 'string' }, priority: { type: 'number' }, audience: { type: 'string' }, requirement: { type: 'string' }, categories: { type: 'array', items: { type: 'string' } }, deprecatedBy: { type: 'string' }, riskScore: { type: 'number' }, version: { type: 'string' }, owner: { type: 'string' }, status: { type: 'string', enum: ['approved', 'draft', 'review', 'deprecated'] }, priorityTier: { type: 'string', enum: ['P1', 'P2', 'P3', 'P4'] }, classification: { type: 'string', enum: ['public', 'internal', 'restricted'] }, lastReviewedAt: { type: 'string' }, nextReviewDue: { type: 'string' }, semanticSummary: { type: 'string' }, changeLog: { type: 'array', items: { type: 'object', additionalProperties: true } }, contentType: { type: 'string', enum: ['instruction', 'template', 'chat-session', 'reference', 'example', 'agent'] }, extensions: extensionsInputSchema
|
|
105
161
|
} },
|
|
106
162
|
overwrite: { type: 'boolean' },
|
|
107
163
|
lax: { type: 'boolean' }
|
|
@@ -152,46 +208,6 @@ const INPUT_SCHEMAS = {
|
|
|
152
208
|
metadata: { type: 'object', additionalProperties: true },
|
|
153
209
|
tags: { type: 'array', maxItems: 10, items: { type: 'string' } }
|
|
154
210
|
} },
|
|
155
|
-
'feedback_list': { type: 'object', additionalProperties: false, properties: {
|
|
156
|
-
type: { type: 'string', enum: ['issue', 'status', 'security', 'feature-request', 'bug-report', 'performance', 'usability', 'other'] },
|
|
157
|
-
severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
|
|
158
|
-
status: { type: 'string', enum: ['new', 'acknowledged', 'in-progress', 'resolved', 'closed'] },
|
|
159
|
-
limit: { type: 'number', minimum: 1, maximum: 200 },
|
|
160
|
-
offset: { type: 'number', minimum: 0 },
|
|
161
|
-
since: { type: 'string' },
|
|
162
|
-
tags: { type: 'array', items: { type: 'string' } }
|
|
163
|
-
} },
|
|
164
|
-
'feedback_get': { type: 'object', additionalProperties: false, required: ['id'], properties: {
|
|
165
|
-
id: { type: 'string' }
|
|
166
|
-
} },
|
|
167
|
-
'feedback_update': { type: 'object', additionalProperties: false, required: ['id'], properties: {
|
|
168
|
-
id: { type: 'string' },
|
|
169
|
-
status: { type: 'string', enum: ['new', 'acknowledged', 'in-progress', 'resolved', 'closed'] },
|
|
170
|
-
metadata: { type: 'object', additionalProperties: true }
|
|
171
|
-
} },
|
|
172
|
-
'feedback_stats': { type: 'object', additionalProperties: false, properties: {
|
|
173
|
-
since: { type: 'string' }
|
|
174
|
-
} },
|
|
175
|
-
'feedback_health': { type: 'object', additionalProperties: true },
|
|
176
|
-
// Unified feedback dispatch (002 Phase 2a)
|
|
177
|
-
'feedback_dispatch': { type: 'object', additionalProperties: true, required: ['action'], properties: {
|
|
178
|
-
action: { type: 'string', enum: ['submit', 'list', 'get', 'update', 'stats', 'health', 'rate'], description: 'Feedback action to perform.' },
|
|
179
|
-
instructionId: { type: 'string', description: 'Instruction ID to rate (rate action).' },
|
|
180
|
-
rating: { type: 'string', enum: ['useful', 'not-useful', 'outdated', 'incomplete'], description: 'Rating value (rate action).' },
|
|
181
|
-
comment: { type: 'string', maxLength: 1000, description: 'Optional comment with rating (rate action).' },
|
|
182
|
-
type: { type: 'string', enum: ['issue', 'status', 'security', 'feature-request', 'bug-report', 'performance', 'usability', 'other'] },
|
|
183
|
-
severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
|
|
184
|
-
title: { type: 'string', maxLength: 200 },
|
|
185
|
-
description: { type: 'string', maxLength: 10000, description: 'Feedback description/body text (submit).' },
|
|
186
|
-
body: { type: 'string', maxLength: 10000, description: 'Alias for description (submit).' },
|
|
187
|
-
id: { type: 'string' },
|
|
188
|
-
status: { type: 'string', enum: ['new', 'acknowledged', 'in-progress', 'resolved', 'closed'] },
|
|
189
|
-
limit: { type: 'number', minimum: 1, maximum: 200 },
|
|
190
|
-
offset: { type: 'number', minimum: 0 },
|
|
191
|
-
since: { type: 'string' },
|
|
192
|
-
tags: { type: 'array', items: { type: 'string' } },
|
|
193
|
-
metadata: { type: 'object', additionalProperties: true }
|
|
194
|
-
} },
|
|
195
211
|
// instructions search tool - PRIMARY discovery mechanism
|
|
196
212
|
'index_search': { type: 'object', additionalProperties: false, required: ['keywords'], properties: {
|
|
197
213
|
keywords: {
|
|
@@ -226,9 +242,9 @@ const INPUT_SCHEMAS = {
|
|
|
226
242
|
token: { type: 'string', description: 'Token for confirm action.' }
|
|
227
243
|
} },
|
|
228
244
|
// diagnostics / test-only tools (not stable)
|
|
229
|
-
'diagnostics_block': { type: 'object', additionalProperties: false, required: ['ms'], properties: { ms: { type: 'number', minimum: 0, maximum:
|
|
230
|
-
'diagnostics_microtaskFlood': { type: 'object', additionalProperties: false, properties: { count: { type: 'number', minimum: 0, maximum:
|
|
231
|
-
'diagnostics_memoryPressure': { type: 'object', additionalProperties: false, properties: { mb: { type: 'number', minimum: 1, maximum:
|
|
245
|
+
'diagnostics_block': { type: 'object', additionalProperties: false, required: ['ms'], properties: { ms: { type: 'number', minimum: 0, maximum: 1000 } } },
|
|
246
|
+
'diagnostics_microtaskFlood': { type: 'object', additionalProperties: false, properties: { count: { type: 'number', minimum: 0, maximum: 25000 } } },
|
|
247
|
+
'diagnostics_memoryPressure': { type: 'object', additionalProperties: false, properties: { mb: { type: 'number', minimum: 1, maximum: 64 } } }
|
|
232
248
|
};
|
|
233
249
|
// Inject new schema after definition block (kept outside literal to avoid large diff churn if ordering changes)
|
|
234
250
|
// Provide permissive object with optional includeTrace boolean.
|
|
@@ -305,20 +321,19 @@ INPUT_SCHEMAS['trace_dump'] = { type: 'object', additionalProperties: false, pro
|
|
|
305
321
|
file: { type: 'string', description: 'Optional path to write the trace buffer JSON file' }
|
|
306
322
|
} };
|
|
307
323
|
// Stable & mutation classification lists (mirrors usage in toolHandlers; exported to remove duplication there).
|
|
308
|
-
exports.STABLE = new Set(['health_check', 'graph_export', 'index_dispatch', 'index_search', 'index_governanceHash', 'prompt_review', 'integrity_verify', 'usage_track', 'usage_hotset', 'metrics_snapshot', 'gates_evaluate', 'meta_tools', 'help_overview', 'index_schema', '
|
|
309
|
-
exports.MUTATION = new Set(['index_add', 'index_import', 'index_repair', 'index_reload', 'index_remove', 'index_groom', 'index_enrich', 'index_governanceUpdate', 'index_normalize', 'usage_flush', 'feedback_submit', '
|
|
324
|
+
exports.STABLE = new Set(['health_check', 'graph_export', 'index_dispatch', 'index_search', 'index_governanceHash', 'prompt_review', 'integrity_verify', 'usage_track', 'usage_hotset', 'metrics_snapshot', 'gates_evaluate', 'meta_tools', 'help_overview', 'index_schema', 'manifest_status', 'index_diagnostics', 'meta_activation_guide', 'meta_check_activation', 'bootstrap', 'bootstrap_status', 'feature_status', 'index_health', 'index_inspect', 'index_debug', 'integrity_manifest', 'messaging_read', 'messaging_list_channels', 'messaging_stats', 'messaging_get', 'messaging_thread', 'trace_dump']);
|
|
325
|
+
exports.MUTATION = new Set(['index_add', 'index_import', 'index_repair', 'index_reload', 'index_remove', 'index_groom', 'index_enrich', 'index_governanceUpdate', 'index_normalize', 'usage_flush', 'feedback_submit', 'manifest_refresh', 'manifest_repair', 'promote_from_repo', 'bootstrap_request', 'bootstrap_confirmFinalize', 'messaging_send', 'messaging_ack', 'messaging_update', 'messaging_purge', 'messaging_reply', 'diagnostics_block', 'diagnostics_microtaskFlood', 'diagnostics_memoryPressure']);
|
|
310
326
|
// Tool tier classification (002-tool-consolidation spec)
|
|
311
327
|
// core: always visible, essential daily use
|
|
312
328
|
// extended: opt-in via INDEX_SERVER_FLAG_TOOLS_EXTENDED=1 or flags.json tools_extended:true
|
|
313
329
|
// admin: opt-in via INDEX_SERVER_FLAG_TOOLS_ADMIN=1, rarely needed ops/debug tools
|
|
314
330
|
const TOOL_TIERS = {
|
|
315
|
-
// Core (7)
|
|
331
|
+
// Core (7 → 6 after feedback_dispatch removal)
|
|
316
332
|
'health_check': 'core',
|
|
317
333
|
'index_dispatch': 'core',
|
|
318
334
|
'index_search': 'core',
|
|
319
335
|
'prompt_review': 'core',
|
|
320
336
|
'help_overview': 'core',
|
|
321
|
-
'feedback_dispatch': 'core',
|
|
322
337
|
'bootstrap': 'core',
|
|
323
338
|
// Extended (14)
|
|
324
339
|
'graph_export': 'extended',
|
|
@@ -337,8 +352,6 @@ const TOOL_TIERS = {
|
|
|
337
352
|
'index_schema': 'extended',
|
|
338
353
|
// Admin (everything else)
|
|
339
354
|
'feedback_submit': 'admin',
|
|
340
|
-
'feedback_list': 'admin',
|
|
341
|
-
'feedback_get': 'admin',
|
|
342
355
|
'meta_tools': 'admin',
|
|
343
356
|
'meta_activation_guide': 'admin',
|
|
344
357
|
'meta_check_activation': 'admin',
|
|
@@ -350,9 +363,6 @@ const TOOL_TIERS = {
|
|
|
350
363
|
'index_enrich': 'admin',
|
|
351
364
|
'index_normalize': 'admin',
|
|
352
365
|
'usage_flush': 'admin',
|
|
353
|
-
'feedback_update': 'admin',
|
|
354
|
-
'feedback_stats': 'admin',
|
|
355
|
-
'feedback_health': 'admin',
|
|
356
366
|
'manifest_status': 'admin',
|
|
357
367
|
'manifest_refresh': 'admin',
|
|
358
368
|
'manifest_repair': 'admin',
|
|
@@ -391,12 +401,18 @@ function resolveActiveTier() {
|
|
|
391
401
|
function getToolRegistry(filter) {
|
|
392
402
|
const maxTier = filter?.tier ?? resolveActiveTier();
|
|
393
403
|
const maxLevel = TIER_LEVEL[maxTier];
|
|
404
|
+
const diagnosticsEnabled = (0, envUtils_1.dangerousDiagnosticsEnabled)();
|
|
394
405
|
const entries = [];
|
|
395
406
|
const names = new Set([...exports.STABLE, ...exports.MUTATION]);
|
|
396
407
|
// Ensure we also expose any tools that have schemas even if not in STABLE/MUTATION lists.
|
|
397
|
-
for (const k of Object.keys(INPUT_SCHEMAS))
|
|
408
|
+
for (const k of Object.keys(INPUT_SCHEMAS)) {
|
|
409
|
+
if (!diagnosticsEnabled && DANGEROUS_DIAGNOSTIC_TOOLS.has(k))
|
|
410
|
+
continue;
|
|
398
411
|
names.add(k);
|
|
412
|
+
}
|
|
399
413
|
for (const name of Array.from(names).sort()) {
|
|
414
|
+
if (!diagnosticsEnabled && DANGEROUS_DIAGNOSTIC_TOOLS.has(name))
|
|
415
|
+
continue;
|
|
400
416
|
const tier = TOOL_TIERS[name] || 'admin';
|
|
401
417
|
if (TIER_LEVEL[tier] > maxLevel)
|
|
402
418
|
continue;
|
|
@@ -407,7 +423,7 @@ function getToolRegistry(filter) {
|
|
|
407
423
|
stable: exports.STABLE.has(name),
|
|
408
424
|
mutation: exports.MUTATION.has(name),
|
|
409
425
|
tier,
|
|
410
|
-
inputSchema: INPUT_SCHEMAS[name] || { type: 'object' },
|
|
426
|
+
inputSchema: withDynamicInstructionBodyLimits(name, INPUT_SCHEMAS[name] || { type: 'object' }),
|
|
411
427
|
outputSchema,
|
|
412
428
|
// zodSchema to be attached incrementally by a forthcoming zodRegistry enhancer.
|
|
413
429
|
});
|
|
@@ -443,12 +459,6 @@ function describeTool(name) {
|
|
|
443
459
|
case 'meta_tools': return 'Enumerate available tools & their metadata.';
|
|
444
460
|
// feedback system descriptions
|
|
445
461
|
case 'feedback_submit': return 'Submit feedback entry (issue, status report, security alert, feature request, etc.).';
|
|
446
|
-
case 'feedback_list': return 'List feedback entries with filtering options (type, severity, status, date range).';
|
|
447
|
-
case 'feedback_get': return 'Get specific feedback entry by ID with full details.';
|
|
448
|
-
case 'feedback_update': return 'Update feedback entry status and metadata (admin function).';
|
|
449
|
-
case 'feedback_stats': return 'Get feedback system statistics and metrics dashboard.';
|
|
450
|
-
case 'feedback_health': return 'Health check for feedback system storage and configuration.';
|
|
451
|
-
case 'feedback_dispatch': return 'Unified feedback dispatcher. Actions: submit, list, get, update, stats, health, rate.';
|
|
452
462
|
case 'bootstrap': return 'Unified bootstrap dispatcher. Actions: request, confirm, status.';
|
|
453
463
|
case 'manifest_status': return 'Report index manifest presence and drift summary.';
|
|
454
464
|
case 'manifest_refresh': return 'Rewrite manifest from current index state.';
|