@jagilber-org/index-server 1.28.1 → 1.28.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +15 -3
  3. package/dist/config/runtimeConfig.d.ts +1 -0
  4. package/dist/config/runtimeConfig.js +1 -0
  5. package/dist/dashboard/client/admin.html +27 -27
  6. package/dist/server/certInit.js +4 -2
  7. package/dist/server/index-server.js +102 -1
  8. package/dist/server/sdkServer.js +2 -2
  9. package/dist/server/transport.js +2 -2
  10. package/dist/services/handlers.dashboardConfig.js +1 -0
  11. package/dist/services/handlers.search.js +4 -0
  12. package/dist/services/handlers.usage.js +11 -0
  13. package/dist/services/mcpConfig/backup.d.ts +17 -0
  14. package/dist/services/mcpConfig/backup.js +114 -0
  15. package/dist/services/mcpConfig/flagCatalog.d.ts +44 -0
  16. package/dist/services/mcpConfig/flagCatalog.js +301 -0
  17. package/dist/services/mcpConfig/formats.d.ts +30 -0
  18. package/dist/services/mcpConfig/formats.js +116 -0
  19. package/dist/services/mcpConfig/index.d.ts +44 -0
  20. package/dist/services/mcpConfig/index.js +130 -0
  21. package/dist/services/mcpConfig/jsoncEdit.d.ts +2 -0
  22. package/dist/services/mcpConfig/jsoncEdit.js +29 -0
  23. package/dist/services/mcpConfig/paths.d.ts +18 -0
  24. package/dist/services/mcpConfig/paths.js +50 -0
  25. package/dist/services/mcpConfig/validate.d.ts +7 -0
  26. package/dist/services/mcpConfig/validate.js +62 -0
  27. package/package.json +3 -2
  28. package/schemas/mcp.claude.schema.json +27 -0
  29. package/schemas/mcp.copilot-cli.schema.json +28 -0
  30. package/schemas/mcp.indexServerEnv.schema.json +9 -0
  31. package/schemas/mcp.vscode.schema.json +28 -0
  32. package/scripts/build/generate-certs.mjs +1 -1
  33. package/scripts/build/setup-wizard.mjs +71 -352
  34. package/server.json +2 -2
@@ -0,0 +1,301 @@
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.DOCUMENTED_INDEX_SERVER_FLAGS = void 0;
7
+ exports.toForwardSlashes = toForwardSlashes;
8
+ exports.resolveDataPaths = resolveDataPaths;
9
+ exports.buildEnvCatalog = buildEnvCatalog;
10
+ exports.activeEnvFromCatalog = activeEnvFromCatalog;
11
+ const path_1 = __importDefault(require("path"));
12
+ exports.DOCUMENTED_INDEX_SERVER_FLAGS = [
13
+ 'INDEX_SERVER_ADD_TIMING',
14
+ 'INDEX_SERVER_ADMIN_API_KEY',
15
+ 'INDEX_SERVER_ADMIN_MAX_SESSION_HISTORY',
16
+ 'INDEX_SERVER_AGENT_ID',
17
+ 'INDEX_SERVER_ALWAYS_RELOAD',
18
+ 'INDEX_SERVER_ATOMIC_WRITE_BACKOFF_MS',
19
+ 'INDEX_SERVER_ATOMIC_WRITE_RETRIES',
20
+ 'INDEX_SERVER_AUTH_KEY',
21
+ 'INDEX_SERVER_AUTO_BACKUP',
22
+ 'INDEX_SERVER_AUTO_BACKUP_INTERVAL_MS',
23
+ 'INDEX_SERVER_AUTO_BACKUP_MAX_COUNT',
24
+ 'INDEX_SERVER_AUTO_SEED',
25
+ 'INDEX_SERVER_AUTO_SPLIT_OVERSIZED',
26
+ 'INDEX_SERVER_AUTO_USAGE_TRACK',
27
+ 'INDEX_SERVER_BACKUP_BEFORE_BULK_DELETE',
28
+ 'INDEX_SERVER_BACKUPS_DIR',
29
+ 'INDEX_SERVER_BODY_WARN_LENGTH',
30
+ 'INDEX_SERVER_BOOTSTRAP_AUTOCONFIRM',
31
+ 'INDEX_SERVER_BOOTSTRAP_TOKEN_TTL_SEC',
32
+ 'INDEX_SERVER_BUFFER_RING_APPEND',
33
+ 'INDEX_SERVER_BUFFER_RING_PRELOAD',
34
+ 'INDEX_SERVER_CACHE_MODE',
35
+ 'INDEX_SERVER_CANONICAL_DISABLE',
36
+ 'INDEX_SERVER_DASHBOARD',
37
+ 'INDEX_SERVER_DASHBOARD_GRAPH',
38
+ 'INDEX_SERVER_DASHBOARD_HOST',
39
+ 'INDEX_SERVER_DASHBOARD_PORT',
40
+ 'INDEX_SERVER_DASHBOARD_TLS',
41
+ 'INDEX_SERVER_DASHBOARD_TLS_CA',
42
+ 'INDEX_SERVER_DASHBOARD_TLS_CERT',
43
+ 'INDEX_SERVER_DASHBOARD_TLS_KEY',
44
+ 'INDEX_SERVER_DASHBOARD_TRIES',
45
+ 'INDEX_SERVER_DEBUG',
46
+ 'INDEX_SERVER_DIR',
47
+ 'INDEX_SERVER_DISABLE_EARLY_STDIN_BUFFER',
48
+ 'INDEX_SERVER_DISABLE_USAGE_CLAMP',
49
+ 'INDEX_SERVER_EMBEDDING_PATH',
50
+ 'INDEX_SERVER_ENABLE_INDEX_SERVER_POLLER',
51
+ 'INDEX_SERVER_EVENT_SILENT',
52
+ 'INDEX_SERVER_FATAL_EXIT_DELAY_MS',
53
+ 'INDEX_SERVER_FEATURES',
54
+ 'INDEX_SERVER_FEEDBACK_DIR',
55
+ 'INDEX_SERVER_FEEDBACK_MAX_ENTRIES',
56
+ 'INDEX_SERVER_FILE_TRACE',
57
+ 'INDEX_SERVER_FLAG_TOOLS_ADMIN',
58
+ 'INDEX_SERVER_FLAG_TOOLS_EXTENDED',
59
+ 'INDEX_SERVER_FLAGS_FILE',
60
+ 'INDEX_SERVER_FORCE_REBUILD',
61
+ 'INDEX_SERVER_GOV_HASH_CANON_VARIANTS',
62
+ 'INDEX_SERVER_GOV_HASH_HARDENING',
63
+ 'INDEX_SERVER_GOV_HASH_IMPORT_SET_SIZE',
64
+ 'INDEX_SERVER_GRAPH_INCLUDE_PRIMARY_EDGES',
65
+ 'INDEX_SERVER_GRAPH_LARGE_CATEGORY_CAP',
66
+ 'INDEX_SERVER_HEALTH_ERROR_THRESHOLD',
67
+ 'INDEX_SERVER_HEALTH_MEMORY_THRESHOLD',
68
+ 'INDEX_SERVER_HEALTH_MIN_UPTIME',
69
+ 'INDEX_SERVER_HEARTBEAT_MS',
70
+ 'INDEX_SERVER_HTTP_METRICS',
71
+ 'INDEX_SERVER_IDLE_KEEPALIVE_MS',
72
+ 'INDEX_SERVER_IDLE_READY_SENTINEL',
73
+ 'INDEX_SERVER_INIT_FEATURES',
74
+ 'INDEX_SERVER_ISSUE_317_COUNTER',
75
+ 'INDEX_SERVER_LEADER_PORT',
76
+ 'INDEX_SERVER_LEADER_URL',
77
+ 'INDEX_SERVER_LOAD_WARN_MS',
78
+ 'INDEX_SERVER_LOG_DIAG',
79
+ 'INDEX_SERVER_LOG_FILE',
80
+ 'INDEX_SERVER_LOG_JSON',
81
+ 'INDEX_SERVER_LOG_LEVEL',
82
+ 'INDEX_SERVER_LOG_MUTATION',
83
+ 'INDEX_SERVER_LOG_PROTOCOL',
84
+ 'INDEX_SERVER_LOG_SEARCH',
85
+ 'INDEX_SERVER_LOG_SYNC',
86
+ 'INDEX_SERVER_LOG_TOOLS',
87
+ 'INDEX_SERVER_MANIFEST_FASTLOAD',
88
+ 'INDEX_SERVER_MANIFEST_WRITE',
89
+ 'INDEX_SERVER_MAX_BULK_DELETE',
90
+ 'INDEX_SERVER_MAX_CONNECTIONS',
91
+ 'INDEX_SERVER_MAX_FILES',
92
+ 'INDEX_SERVER_MEMOIZE',
93
+ 'INDEX_SERVER_MEMOIZE_HASH',
94
+ 'INDEX_SERVER_MEMORY_MONITOR',
95
+ 'INDEX_SERVER_METRICS_DIR',
96
+ 'INDEX_SERVER_METRICS_FILE_STORAGE',
97
+ 'INDEX_SERVER_METRICS_MAX_FILES',
98
+ 'INDEX_SERVER_MINIMAL_DEBUG',
99
+ 'INDEX_SERVER_MODE',
100
+ 'INDEX_SERVER_MUTATION',
101
+ 'INDEX_SERVER_NORMALIZATION_LOG',
102
+ 'INDEX_SERVER_POLL_MS',
103
+ 'INDEX_SERVER_POLL_PROACTIVE',
104
+ 'INDEX_SERVER_PREFLIGHT_MODULES',
105
+ 'INDEX_SERVER_PREFLIGHT_STRICT',
106
+ 'INDEX_SERVER_PROFILE',
107
+ 'INDEX_SERVER_PWS_EXIT_MS',
108
+ 'INDEX_SERVER_RATE_LIMIT',
109
+ 'INDEX_SERVER_READ_BACKOFF_MS',
110
+ 'INDEX_SERVER_READ_RETRIES',
111
+ 'INDEX_SERVER_REFERENCE_MODE',
112
+ 'INDEX_SERVER_REQUEST_TIMEOUT',
113
+ 'INDEX_SERVER_REQUIRE_AUTH_ALL',
114
+ 'INDEX_SERVER_REQUIRE_CATEGORY',
115
+ 'INDEX_SERVER_RESOURCE_CAPACITY',
116
+ 'INDEX_SERVER_RESOURCE_SAMPLE_INTERVAL_MS',
117
+ 'INDEX_SERVER_SEED_VERBOSE',
118
+ 'INDEX_SERVER_SEMANTIC_CACHE_DIR',
119
+ 'INDEX_SERVER_SEMANTIC_DEVICE',
120
+ 'INDEX_SERVER_SEMANTIC_ENABLED',
121
+ 'INDEX_SERVER_SEMANTIC_LOCAL_ONLY',
122
+ 'INDEX_SERVER_SEMANTIC_MODEL',
123
+ 'INDEX_SERVER_SEARCH_OMIT_ZERO_QUERY',
124
+ 'INDEX_SERVER_SESSION_BACKUP_INTEGRATION',
125
+ 'INDEX_SERVER_SESSION_DEDUPLICATION_ENABLED',
126
+ 'INDEX_SERVER_SESSION_MAX_CONNECTION_HISTORY_DAYS',
127
+ 'INDEX_SERVER_SESSION_MAX_HISTORY_DAYS',
128
+ 'INDEX_SERVER_SESSION_MAX_HISTORY_ENTRIES',
129
+ 'INDEX_SERVER_SESSION_PERSISTENCE_DIR',
130
+ 'INDEX_SERVER_SESSION_PERSISTENCE_ENABLED',
131
+ 'INDEX_SERVER_SESSION_PERSISTENCE_INTERVAL_MS',
132
+ 'INDEX_SERVER_SHARED_SERVER_SENTINEL',
133
+ 'INDEX_SERVER_SQLITE_MIGRATE_ON_START',
134
+ 'INDEX_SERVER_SQLITE_PATH',
135
+ 'INDEX_SERVER_SQLITE_VEC_ENABLED',
136
+ 'INDEX_SERVER_SQLITE_VEC_PATH',
137
+ 'INDEX_SERVER_SQLITE_WAL',
138
+ 'INDEX_SERVER_STALE_THRESHOLD_MS',
139
+ 'INDEX_SERVER_STATE_DIR',
140
+ 'INDEX_SERVER_STORAGE_BACKEND',
141
+ 'INDEX_SERVER_STRESS_DIAG',
142
+ 'INDEX_SERVER_STRESS_MODE',
143
+ 'INDEX_SERVER_STRICT_',
144
+ 'INDEX_SERVER_STRICT_CREATE',
145
+ 'INDEX_SERVER_STRICT_REMOVE',
146
+ 'INDEX_SERVER_TEST_MODE',
147
+ 'INDEX_SERVER_TEST_STRICT_VISIBILITY',
148
+ 'INDEX_SERVER_TIMING_JSON',
149
+ 'INDEX_SERVER_TOOLCALL_APPEND_LOG',
150
+ 'INDEX_SERVER_TOOLCALL_CHUNK_SIZE',
151
+ 'INDEX_SERVER_TOOLCALL_COMPACT_MS',
152
+ 'INDEX_SERVER_TOOLCALL_FLUSH_MS',
153
+ 'INDEX_SERVER_TRACE',
154
+ 'INDEX_SERVER_TRACE_',
155
+ 'INDEX_SERVER_TRACE_ALL',
156
+ 'INDEX_SERVER_TRACE_BUFFER_',
157
+ 'INDEX_SERVER_TRACE_BUFFER_DUMP_ON_EXIT',
158
+ 'INDEX_SERVER_TRACE_BUFFER_FILE',
159
+ 'INDEX_SERVER_TRACE_BUFFER_SIZE',
160
+ 'INDEX_SERVER_TRACE_CALLSITE',
161
+ 'INDEX_SERVER_TRACE_CATEGORIES',
162
+ 'INDEX_SERVER_TRACE_DIR',
163
+ 'INDEX_SERVER_TRACE_DISPATCH_DIAG',
164
+ 'INDEX_SERVER_TRACE_FILE',
165
+ 'INDEX_SERVER_TRACE_FSYNC',
166
+ 'INDEX_SERVER_TRACE_LEVEL',
167
+ 'INDEX_SERVER_TRACE_MAX_FILE_SIZE',
168
+ 'INDEX_SERVER_TRACE_PERSIST',
169
+ 'INDEX_SERVER_TRACE_QUERY_DIAG',
170
+ 'INDEX_SERVER_TRACE_SESSION',
171
+ 'INDEX_SERVER_USAGE_FLUSH_MS',
172
+ 'INDEX_SERVER_USAGE_SNAPSHOT_PATH',
173
+ 'INDEX_SERVER_VALIDATION_MODE',
174
+ 'INDEX_SERVER_VERBOSE_LOGGING',
175
+ 'INDEX_SERVER_VISIBILITY_DIAG',
176
+ 'INDEX_SERVER_WORKSPACE',
177
+ ];
178
+ function toForwardSlashes(value) {
179
+ return value.split(path_1.default.sep).join('/');
180
+ }
181
+ function resolveDataPaths(root) {
182
+ const resolveUnder = (...segments) => toForwardSlashes(path_1.default.resolve(root, ...segments));
183
+ return {
184
+ instructions: resolveUnder('instructions'),
185
+ feedback: resolveUnder('feedback'),
186
+ backups: resolveUnder('backups'),
187
+ state: resolveUnder('data', 'state'),
188
+ auditLog: resolveUnder('logs', 'instruction-transactions.log.jsonl'),
189
+ logFile: resolveUnder('logs', 'mcp-server.log'),
190
+ metrics: resolveUnder('metrics'),
191
+ messaging: resolveUnder('data', 'messaging'),
192
+ embeddings: resolveUnder('data', 'embeddings.json'),
193
+ modelCache: resolveUnder('data', 'models'),
194
+ sqliteDb: resolveUnder('data', 'index.db'),
195
+ certs: resolveUnder('certs'),
196
+ flags: resolveUnder('flags.json'),
197
+ };
198
+ }
199
+ function buildEnvCatalog(config, paths) {
200
+ const isEnhanced = config.profile === 'enhanced' || config.profile === 'experimental';
201
+ const isSqlite = config.profile === 'experimental';
202
+ const entries = [
203
+ { section: 'Core Paths - where your data lives' },
204
+ { key: 'INDEX_SERVER_PROFILE', desc: 'Configuration profile: default | enhanced | experimental', active: true, value: config.profile },
205
+ { key: 'INDEX_SERVER_ALWAYS_RELOAD', desc: 'Reload index on each read for generated config verification', active: true, value: '1' },
206
+ { key: 'INDEX_SERVER_DIR', desc: 'Instruction catalog directory', active: false, value: paths.instructions },
207
+ { key: 'INDEX_SERVER_FEEDBACK_DIR', desc: 'Feedback entries storage directory', active: false, value: paths.feedback },
208
+ { key: 'INDEX_SERVER_BACKUPS_DIR', desc: 'Backup snapshots directory', active: false, value: paths.backups },
209
+ { key: 'INDEX_SERVER_STATE_DIR', desc: 'Runtime state files directory', active: false, value: paths.state },
210
+ { key: 'INDEX_SERVER_MESSAGING_DIR', desc: 'Message queue storage directory', active: false, value: paths.messaging },
211
+ { section: 'Dashboard - HTTP/HTTPS admin interface' },
212
+ { key: 'INDEX_SERVER_DASHBOARD', desc: 'Enable the web dashboard', active: true, value: '1' },
213
+ { key: 'INDEX_SERVER_DASHBOARD_PORT', desc: 'Dashboard listen port', active: true, value: String(config.port) },
214
+ { key: 'INDEX_SERVER_DASHBOARD_HOST', desc: 'Dashboard bind address', active: true, value: config.host },
215
+ { key: 'INDEX_SERVER_DASHBOARD_GRAPH', desc: 'Enable graph visualization', active: false, value: '0' },
216
+ { section: 'Security - mutation control and TLS' },
217
+ { key: 'INDEX_SERVER_MUTATION', desc: 'Enable write operations', active: true, value: config.mutation ? '1' : '0' },
218
+ { key: 'INDEX_SERVER_ADMIN_API_KEY', desc: 'Dashboard admin API key', active: false, value: '' },
219
+ { key: 'INDEX_SERVER_DASHBOARD_TLS', desc: 'Enable HTTPS dashboard', active: config.tls, value: config.tls ? '1' : '0' },
220
+ { key: 'INDEX_SERVER_DASHBOARD_TLS_CERT', desc: 'Path to TLS certificate file', active: false, value: `${paths.certs}/server.crt` },
221
+ { key: 'INDEX_SERVER_DASHBOARD_TLS_KEY', desc: 'Path to TLS private key file', active: false, value: `${paths.certs}/server.key` },
222
+ { key: 'INDEX_SERVER_DASHBOARD_TLS_CA', desc: 'Path to CA certificate', active: false, value: '' },
223
+ { section: 'Semantic Search - embeddings' },
224
+ { key: 'INDEX_SERVER_SEMANTIC_ENABLED', desc: 'Enable semantic search', active: isEnhanced, value: isEnhanced ? '1' : '0' },
225
+ { key: 'INDEX_SERVER_SEMANTIC_MODEL', desc: 'HuggingFace model name', active: false, value: 'Xenova/all-MiniLM-L6-v2' },
226
+ { key: 'INDEX_SERVER_SEMANTIC_DEVICE', desc: 'Compute device', active: false, value: 'cpu' },
227
+ { key: 'INDEX_SERVER_SEMANTIC_CACHE_DIR', desc: 'Downloaded model cache directory', active: false, value: paths.modelCache },
228
+ { key: 'INDEX_SERVER_EMBEDDING_PATH', desc: 'Cached embeddings file', active: false, value: paths.embeddings },
229
+ { key: 'INDEX_SERVER_SEMANTIC_LOCAL_ONLY', desc: 'Block remote model downloads', active: false, value: isEnhanced ? '0' : '1' },
230
+ { section: 'Storage Backend - JSON or SQLite' },
231
+ { key: 'INDEX_SERVER_STORAGE_BACKEND', desc: 'Storage engine', active: isSqlite, value: isSqlite ? 'sqlite' : 'json' },
232
+ { key: 'INDEX_SERVER_SQLITE_PATH', desc: 'SQLite database file path', active: false, value: paths.sqliteDb },
233
+ { key: 'INDEX_SERVER_SQLITE_WAL', desc: 'Enable SQLite WAL mode', active: false, value: '1' },
234
+ { key: 'INDEX_SERVER_SQLITE_MIGRATE_ON_START', desc: 'Auto-migrate JSON to SQLite', active: false, value: '1' },
235
+ { section: 'Logging and diagnostics' },
236
+ { key: 'INDEX_SERVER_LOG_LEVEL', desc: 'Log level', active: true, value: config.logLevel },
237
+ { key: 'INDEX_SERVER_LOG_FILE', desc: 'Enable file logging', active: isEnhanced, value: isEnhanced ? '1' : '0' },
238
+ { key: 'INDEX_SERVER_VERBOSE_LOGGING', desc: 'Verbose stderr output', active: false, value: '0' },
239
+ { key: 'INDEX_SERVER_LOG_JSON', desc: 'JSON-formatted logs', active: false, value: '0' },
240
+ { key: 'INDEX_SERVER_LOG_DIAG', desc: 'Diagnostic startup logging', active: false, value: '0' },
241
+ { key: 'INDEX_SERVER_AUDIT_LOG', desc: 'Audit log path', active: false, value: paths.auditLog },
242
+ { section: 'Backup and recovery' },
243
+ { key: 'INDEX_SERVER_AUTO_BACKUP', desc: 'Enable instruction backups', active: false, value: config.mutation ? '1' : '0' },
244
+ { key: 'INDEX_SERVER_AUTO_BACKUP_INTERVAL_MS', desc: 'Backup interval in ms', active: false, value: '3600000' },
245
+ { key: 'INDEX_SERVER_AUTO_BACKUP_MAX_COUNT', desc: 'Max instruction backups retained', active: false, value: '10' },
246
+ { key: 'INDEX_SERVER_BACKUP_BEFORE_BULK_DELETE', desc: 'Backup before bulk delete', active: false, value: '1' },
247
+ { section: 'Features and flags' },
248
+ { key: 'INDEX_SERVER_FEATURES', desc: 'Comma-separated feature flags', active: isEnhanced, value: isEnhanced ? 'usage' : '' },
249
+ { key: 'INDEX_SERVER_FLAG_TOOLS_EXTENDED', desc: 'Expose extended index mutation tools', active: true, value: '1' },
250
+ { key: 'INDEX_SERVER_SEARCH_OMIT_ZERO_QUERY', desc: 'Omit echoed query metadata on zero-result search responses', active: true, value: '1' },
251
+ { key: 'INDEX_SERVER_METRICS_FILE_STORAGE', desc: 'Persist metrics to disk', active: isEnhanced, value: isEnhanced ? '1' : '0' },
252
+ { key: 'INDEX_SERVER_METRICS_DIR', desc: 'Metrics storage directory', active: false, value: paths.metrics },
253
+ { key: 'INDEX_SERVER_FLAGS_FILE', desc: 'Feature flags JSON file path', active: false, value: paths.flags },
254
+ { section: 'Server and transport' },
255
+ { key: 'INDEX_SERVER_MODE', desc: 'Instance mode', active: false, value: 'standalone' },
256
+ { key: 'INDEX_SERVER_DISABLE_EARLY_STDIN_BUFFER', desc: 'Disable stdin handshake hardening', active: false, value: '0' },
257
+ { key: 'INDEX_SERVER_IDLE_KEEPALIVE_MS', desc: 'Keepalive interval in ms', active: false, value: '30000' },
258
+ { key: 'INDEX_SERVER_POLL_MS', desc: 'Index filesystem poll interval', active: false, value: '10000' },
259
+ { section: 'Advanced tuning' },
260
+ { key: 'INDEX_SERVER_BODY_WARN_LENGTH', desc: 'Instruction body warning length', active: false, value: '50000' },
261
+ { key: 'INDEX_SERVER_AUTO_SPLIT_OVERSIZED', desc: 'Auto-split oversized entries', active: false, value: '0' },
262
+ { key: 'INDEX_SERVER_READ_RETRIES', desc: 'File read retry attempts', active: false, value: '3' },
263
+ { key: 'INDEX_SERVER_MAX_BULK_DELETE', desc: 'Max bulk delete entries', active: false, value: '5' },
264
+ { key: 'INDEX_SERVER_FEEDBACK_MAX_ENTRIES', desc: 'Max feedback entries', active: false, value: '1000' },
265
+ { key: 'INDEX_SERVER_MESSAGING_MAX', desc: 'Max messages in queue', active: false, value: '10000' },
266
+ { key: 'INDEX_SERVER_MAX_CONNECTIONS', desc: 'Max dashboard connections', active: false, value: '100' },
267
+ { key: 'INDEX_SERVER_CACHE_MODE', desc: 'Index cache mode', active: false, value: 'normal' },
268
+ { key: 'INDEX_SERVER_WORKSPACE', desc: 'Workspace identifier', active: false, value: '' },
269
+ { key: 'INDEX_SERVER_AGENT_ID', desc: 'Agent identifier', active: false, value: '' },
270
+ ];
271
+ const seen = new Set(entries.flatMap(entry => 'key' in entry ? [entry.key] : []));
272
+ for (const flag of exports.DOCUMENTED_INDEX_SERVER_FLAGS) {
273
+ if (!seen.has(flag))
274
+ entries.push({ key: flag, desc: 'Documented runtime configuration flag', active: false, value: '' });
275
+ }
276
+ return entries.map((entry) => {
277
+ if ('section' in entry)
278
+ return entry;
279
+ const value = String(entry.value);
280
+ const variable = {
281
+ ...entry,
282
+ value,
283
+ defaultByProfile: {
284
+ default: value,
285
+ enhanced: value,
286
+ experimental: value,
287
+ },
288
+ mcpEnvVisibility: entry.active ? 'always' : 'when-set',
289
+ validate: 'string',
290
+ };
291
+ return variable;
292
+ });
293
+ }
294
+ function activeEnvFromCatalog(catalog) {
295
+ const env = {};
296
+ for (const entry of catalog) {
297
+ if ('key' in entry && entry.active)
298
+ env[entry.key] = entry.value;
299
+ }
300
+ return env;
301
+ }
@@ -0,0 +1,30 @@
1
+ import { McpDataPaths, McpProfileConfig } from './flagCatalog';
2
+ import type { McpConfigFormat } from './paths';
3
+ export interface McpServerEntry {
4
+ type?: string;
5
+ command: string;
6
+ args: string[];
7
+ cwd?: string;
8
+ env?: Record<string, string>;
9
+ tools?: string[];
10
+ }
11
+ export interface ServerBuildConfig extends McpProfileConfig {
12
+ serverName: string;
13
+ }
14
+ export declare function rootKeyForFormat(format: McpConfigFormat): 'servers' | 'mcpServers';
15
+ export declare function emptyConfigForFormat(format: McpConfigFormat): Record<string, unknown>;
16
+ export declare function parseConfigText(format: McpConfigFormat, text: string): Record<string, unknown>;
17
+ export declare function readConfigFile(format: McpConfigFormat, filePath: string): Record<string, unknown>;
18
+ export declare function getServerMap(config: Record<string, unknown>, format: McpConfigFormat): Record<string, McpServerEntry>;
19
+ export declare function resolveServerLaunch(config: {
20
+ root: string;
21
+ }): {
22
+ command: string;
23
+ args: string[];
24
+ cwd?: string;
25
+ source: 'local' | 'packaged' | 'npx';
26
+ };
27
+ export declare function buildServerEntry(format: McpConfigFormat, config: ServerBuildConfig, paths: McpDataPaths, envOverrides?: Record<string, string>): McpServerEntry;
28
+ export declare function renderConfig(format: McpConfigFormat, serverName: string, entry: McpServerEntry): string;
29
+ export declare function upsertConfigText(format: McpConfigFormat, existingText: string, serverName: string, entry: McpServerEntry): string;
30
+ export declare function removeConfigText(format: McpConfigFormat, existingText: string, serverName: string): string;
@@ -0,0 +1,116 @@
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.rootKeyForFormat = rootKeyForFormat;
7
+ exports.emptyConfigForFormat = emptyConfigForFormat;
8
+ exports.parseConfigText = parseConfigText;
9
+ exports.readConfigFile = readConfigFile;
10
+ exports.getServerMap = getServerMap;
11
+ exports.resolveServerLaunch = resolveServerLaunch;
12
+ exports.buildServerEntry = buildServerEntry;
13
+ exports.renderConfig = renderConfig;
14
+ exports.upsertConfigText = upsertConfigText;
15
+ exports.removeConfigText = removeConfigText;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const jsoncEdit_1 = require("./jsoncEdit");
19
+ const flagCatalog_1 = require("./flagCatalog");
20
+ function rootKeyForFormat(format) {
21
+ return format === 'vscode' || format === 'vscode-global' ? 'servers' : 'mcpServers';
22
+ }
23
+ function emptyConfigForFormat(format) {
24
+ const rootKey = rootKeyForFormat(format);
25
+ const value = { [rootKey]: {} };
26
+ if (rootKey === 'servers')
27
+ value.inputs = [];
28
+ return value;
29
+ }
30
+ function parseConfigText(format, text) {
31
+ if (text.trim().length === 0)
32
+ return emptyConfigForFormat(format);
33
+ return format === 'vscode' || format === 'vscode-global'
34
+ ? (0, jsoncEdit_1.parseJsonc)(text)
35
+ : JSON.parse(text);
36
+ }
37
+ function readConfigFile(format, filePath) {
38
+ if (!fs_1.default.existsSync(filePath))
39
+ return emptyConfigForFormat(format);
40
+ return parseConfigText(format, fs_1.default.readFileSync(filePath, 'utf8'));
41
+ }
42
+ function getServerMap(config, format) {
43
+ const rootKey = rootKeyForFormat(format);
44
+ const servers = config[rootKey];
45
+ if (servers === undefined)
46
+ return {};
47
+ if (!servers || typeof servers !== 'object' || Array.isArray(servers)) {
48
+ throw new Error(`Invalid MCP config: ${rootKey} must be an object`);
49
+ }
50
+ return servers;
51
+ }
52
+ function resolveServerLaunch(config) {
53
+ const packageRoot = path_1.default.resolve(__dirname, '..', '..', '..');
54
+ const entryRelative = path_1.default.join('dist', 'server', 'index-server.js');
55
+ const localEntry = path_1.default.join(config.root, entryRelative);
56
+ const packagedEntry = path_1.default.join(packageRoot, entryRelative);
57
+ if (fs_1.default.existsSync(localEntry)) {
58
+ return { command: 'node', args: [(0, flagCatalog_1.toForwardSlashes)(entryRelative)], cwd: config.root, source: 'local' };
59
+ }
60
+ if (fs_1.default.existsSync(packagedEntry)) {
61
+ return { command: 'node', args: [(0, flagCatalog_1.toForwardSlashes)(packagedEntry)], source: 'packaged' };
62
+ }
63
+ return { command: 'npx', args: ['-y', '@jagilber-org/index-server'], source: 'npx' };
64
+ }
65
+ function buildServerEntry(format, config, paths, envOverrides = {}) {
66
+ const launch = resolveServerLaunch(config);
67
+ const catalog = (0, flagCatalog_1.buildEnvCatalog)(config, paths);
68
+ const env = { ...(0, flagCatalog_1.activeEnvFromCatalog)(catalog), ...envOverrides };
69
+ const entry = {
70
+ command: launch.command,
71
+ args: launch.args,
72
+ env,
73
+ };
74
+ if (format === 'vscode' || format === 'vscode-global')
75
+ entry.type = 'stdio';
76
+ if (format === 'vscode' && launch.cwd)
77
+ entry.cwd = (0, flagCatalog_1.toForwardSlashes)(launch.cwd);
78
+ if (format === 'vscode-global' && launch.command === 'node') {
79
+ const firstArg = launch.args[0] ?? '';
80
+ entry.args = [path_1.default.isAbsolute(firstArg) ? (0, flagCatalog_1.toForwardSlashes)(firstArg) : (0, flagCatalog_1.toForwardSlashes)(path_1.default.resolve(launch.cwd ?? config.root, firstArg))];
81
+ entry.cwd = (0, flagCatalog_1.toForwardSlashes)(path_1.default.resolve(__dirname, '..', '..', '..'));
82
+ }
83
+ return entry;
84
+ }
85
+ function renderConfig(format, serverName, entry) {
86
+ const config = emptyConfigForFormat(format);
87
+ const rootKey = rootKeyForFormat(format);
88
+ config[rootKey][serverName] = entry;
89
+ return format === 'vscode' || format === 'vscode-global'
90
+ ? JSON.stringify(config, null, 2)
91
+ : `${JSON.stringify(config, null, 2)}\n`;
92
+ }
93
+ function upsertConfigText(format, existingText, serverName, entry) {
94
+ if (format === 'vscode' || format === 'vscode-global') {
95
+ const base = existingText.trim().length > 0 ? existingText : JSON.stringify(emptyConfigForFormat(format), null, 2);
96
+ return (0, jsoncEdit_1.applyJsoncEdit)(base, [rootKeyForFormat(format), serverName], entry);
97
+ }
98
+ const config = parseConfigText(format, existingText);
99
+ const rootKey = rootKeyForFormat(format);
100
+ const servers = getServerMap(config, format);
101
+ servers[serverName] = entry;
102
+ config[rootKey] = servers;
103
+ return `${JSON.stringify(config, null, 2)}\n`;
104
+ }
105
+ function removeConfigText(format, existingText, serverName) {
106
+ if (format === 'vscode' || format === 'vscode-global') {
107
+ const base = existingText.trim().length > 0 ? existingText : JSON.stringify(emptyConfigForFormat(format), null, 2);
108
+ return (0, jsoncEdit_1.applyJsoncEdit)(base, [rootKeyForFormat(format), serverName], undefined);
109
+ }
110
+ const config = parseConfigText(format, existingText);
111
+ const rootKey = rootKeyForFormat(format);
112
+ const servers = getServerMap(config, format);
113
+ delete servers[serverName];
114
+ config[rootKey] = servers;
115
+ return `${JSON.stringify(config, null, 2)}\n`;
116
+ }
@@ -0,0 +1,44 @@
1
+ import { resolveServerLaunch, type McpServerEntry, type ServerBuildConfig } from './formats';
2
+ import { buildEnvCatalog, resolveDataPaths } from './flagCatalog';
3
+ import { resolveConfigTargets, type McpClientTarget, type McpConfigFormat, type McpScope, type McpTargetInfo } from './paths';
4
+ import { type ValidationResult } from './validate';
5
+ export type { McpClientTarget, McpConfigFormat, McpScope, McpTargetInfo, McpServerEntry, ServerBuildConfig, ValidationResult };
6
+ export { buildEnvCatalog, resolveConfigTargets, resolveDataPaths, resolveServerLaunch };
7
+ export interface McpOperationOptions {
8
+ target?: McpClientTarget;
9
+ targets?: McpClientTarget[];
10
+ scope?: McpScope;
11
+ root?: string;
12
+ name?: string;
13
+ profile?: 'default' | 'enhanced' | 'experimental';
14
+ port?: number;
15
+ host?: string;
16
+ tls?: boolean;
17
+ mutation?: boolean;
18
+ logLevel?: string;
19
+ env?: Record<string, string>;
20
+ dryRun?: boolean;
21
+ backup?: string;
22
+ }
23
+ export interface McpOperationResult {
24
+ ok: boolean;
25
+ action: string;
26
+ target: McpClientTarget;
27
+ format: McpConfigFormat;
28
+ path: string;
29
+ name?: string;
30
+ server?: McpServerEntry | null;
31
+ servers?: string[];
32
+ validation?: ValidationResult;
33
+ backupPath?: string;
34
+ dryRun?: boolean;
35
+ }
36
+ export declare function listServers(options?: McpOperationOptions): McpOperationResult;
37
+ export declare function getServer(options?: McpOperationOptions): McpOperationResult;
38
+ export declare function upsertServer(options?: McpOperationOptions): McpOperationResult;
39
+ export declare function removeServer(options?: McpOperationOptions): McpOperationResult;
40
+ export declare function restoreLatestBackup(options?: McpOperationOptions): McpOperationResult;
41
+ export declare function restoreServer(options?: McpOperationOptions): McpOperationResult;
42
+ export declare function validateFile(options?: McpOperationOptions): McpOperationResult;
43
+ export declare function renderServerConfigForTarget(target: McpTargetInfo, options?: McpOperationOptions): string;
44
+ export declare function writeGeneratedConfig(filePath: string, content: string): void;
@@ -0,0 +1,130 @@
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.resolveServerLaunch = exports.resolveDataPaths = exports.resolveConfigTargets = exports.buildEnvCatalog = void 0;
7
+ exports.listServers = listServers;
8
+ exports.getServer = getServer;
9
+ exports.upsertServer = upsertServer;
10
+ exports.removeServer = removeServer;
11
+ exports.restoreLatestBackup = restoreLatestBackup;
12
+ exports.restoreServer = restoreServer;
13
+ exports.validateFile = validateFile;
14
+ exports.renderServerConfigForTarget = renderServerConfigForTarget;
15
+ exports.writeGeneratedConfig = writeGeneratedConfig;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const backup_1 = require("./backup");
19
+ const formats_1 = require("./formats");
20
+ Object.defineProperty(exports, "resolveServerLaunch", { enumerable: true, get: function () { return formats_1.resolveServerLaunch; } });
21
+ const flagCatalog_1 = require("./flagCatalog");
22
+ Object.defineProperty(exports, "buildEnvCatalog", { enumerable: true, get: function () { return flagCatalog_1.buildEnvCatalog; } });
23
+ Object.defineProperty(exports, "resolveDataPaths", { enumerable: true, get: function () { return flagCatalog_1.resolveDataPaths; } });
24
+ const paths_1 = require("./paths");
25
+ Object.defineProperty(exports, "resolveConfigTargets", { enumerable: true, get: function () { return paths_1.resolveConfigTargets; } });
26
+ const validate_1 = require("./validate");
27
+ const backup_2 = require("./backup");
28
+ function firstTarget(options) {
29
+ return (0, paths_1.resolveConfigTargets)({
30
+ target: options.target,
31
+ targets: options.targets,
32
+ scope: options.scope,
33
+ root: options.root,
34
+ })[0];
35
+ }
36
+ function defaultName(options) {
37
+ return options.name ?? 'index-server';
38
+ }
39
+ function buildConfig(options) {
40
+ const profile = options.profile ?? 'default';
41
+ const tls = options.tls ?? (profile === 'enhanced' || profile === 'experimental');
42
+ return {
43
+ profile,
44
+ root: path_1.default.resolve(options.root ?? process.env.INDEX_SERVER_MCP_CONFIG_ROOT ?? process.cwd()),
45
+ port: options.port ?? 8787,
46
+ host: options.host ?? '127.0.0.1',
47
+ tls,
48
+ mutation: options.mutation ?? true,
49
+ logLevel: options.logLevel ?? (profile === 'experimental' ? 'debug' : 'info'),
50
+ serverName: defaultName(options),
51
+ };
52
+ }
53
+ function readExistingText(filePath, format) {
54
+ if (fs_1.default.existsSync(filePath))
55
+ return fs_1.default.readFileSync(filePath, 'utf8');
56
+ return (0, formats_1.renderConfig)(format, '__placeholder__', {
57
+ command: 'node',
58
+ args: ['dist/server/index-server.js'],
59
+ }).split('__placeholder__').join('index-server');
60
+ }
61
+ function listServers(options = {}) {
62
+ const target = firstTarget(options);
63
+ const config = (0, formats_1.readConfigFile)(target.format, target.path);
64
+ const servers = Object.keys((0, formats_1.getServerMap)(config, target.format));
65
+ return { ok: true, action: 'list', ...target, servers };
66
+ }
67
+ function getServer(options = {}) {
68
+ const target = firstTarget(options);
69
+ const config = (0, formats_1.readConfigFile)(target.format, target.path);
70
+ const server = (0, formats_1.getServerMap)(config, target.format)[defaultName(options)] ?? null;
71
+ return { ok: true, action: 'get', ...target, name: defaultName(options), server };
72
+ }
73
+ function upsertServer(options = {}) {
74
+ const target = firstTarget(options);
75
+ const config = buildConfig(options);
76
+ const paths = (0, flagCatalog_1.resolveDataPaths)(config.root);
77
+ const entry = (0, formats_1.buildServerEntry)(target.format, config, paths, options.env);
78
+ const existingText = fs_1.default.existsSync(target.path) ? fs_1.default.readFileSync(target.path, 'utf8') : '';
79
+ if (existingText)
80
+ (0, validate_1.assertValidConfigObject)(target.format, (0, formats_1.parseConfigText)(target.format, existingText), 'read');
81
+ const nextText = (0, formats_1.upsertConfigText)(target.format, existingText, config.serverName, entry);
82
+ const nextConfig = (0, formats_1.parseConfigText)(target.format, nextText);
83
+ (0, validate_1.assertValidConfigObject)(target.format, nextConfig, 'write');
84
+ if (!options.dryRun) {
85
+ const backup = (0, backup_1.createBackup)(target.path, 'upsert', config.serverName);
86
+ (0, backup_2.atomicWriteText)(target.path, nextText);
87
+ (0, validate_1.assertValidConfigObject)(target.format, (0, formats_1.readConfigFile)(target.format, target.path), 'post-write');
88
+ return { ok: true, action: 'upsert', ...target, name: config.serverName, server: entry, backupPath: backup?.backupPath };
89
+ }
90
+ return { ok: true, action: 'upsert', ...target, name: config.serverName, server: entry, dryRun: true };
91
+ }
92
+ function removeServer(options = {}) {
93
+ const target = firstTarget(options);
94
+ const name = defaultName(options);
95
+ const existingText = readExistingText(target.path, target.format);
96
+ (0, validate_1.assertValidConfigObject)(target.format, (0, formats_1.parseConfigText)(target.format, existingText), 'read');
97
+ const nextText = (0, formats_1.removeConfigText)(target.format, existingText, name);
98
+ (0, validate_1.assertValidConfigObject)(target.format, (0, formats_1.parseConfigText)(target.format, nextText), 'write');
99
+ if (!options.dryRun) {
100
+ const backup = (0, backup_1.createBackup)(target.path, 'remove', name);
101
+ (0, backup_2.atomicWriteText)(target.path, nextText);
102
+ (0, validate_1.assertValidConfigObject)(target.format, (0, formats_1.readConfigFile)(target.format, target.path), 'post-write');
103
+ return { ok: true, action: 'remove', ...target, name, backupPath: backup?.backupPath };
104
+ }
105
+ return { ok: true, action: 'remove', ...target, name, dryRun: true };
106
+ }
107
+ function restoreLatestBackup(options = {}) {
108
+ const target = firstTarget(options);
109
+ const restored = (0, backup_1.restoreBackup)(target.path, options.backup);
110
+ (0, validate_1.assertValidConfigObject)(target.format, (0, formats_1.readConfigFile)(target.format, target.path), 'restore');
111
+ return { ok: true, action: 'restore', ...target, backupPath: restored.backupPath };
112
+ }
113
+ function restoreServer(options = {}) {
114
+ return restoreLatestBackup(options);
115
+ }
116
+ function validateFile(options = {}) {
117
+ const target = firstTarget(options);
118
+ const config = (0, formats_1.readConfigFile)(target.format, target.path);
119
+ const validation = (0, validate_1.validateConfigObject)(target.format, config);
120
+ return { ok: validation.ok, action: 'validate', ...target, validation };
121
+ }
122
+ function renderServerConfigForTarget(target, options = {}) {
123
+ const config = buildConfig({ ...options, target: target.target, scope: target.format === 'vscode-global' ? 'global' : options.scope });
124
+ const paths = (0, flagCatalog_1.resolveDataPaths)(config.root);
125
+ const entry = (0, formats_1.buildServerEntry)(target.format, config, paths, options.env);
126
+ return (0, formats_1.renderConfig)(target.format, config.serverName, entry);
127
+ }
128
+ function writeGeneratedConfig(filePath, content) {
129
+ (0, backup_2.atomicWriteText)(filePath, content);
130
+ }
@@ -0,0 +1,2 @@
1
+ export declare function parseJsonc(text: string): Record<string, unknown>;
2
+ export declare function applyJsoncEdit(text: string, editPath: Array<string | number>, value: unknown): string;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseJsonc = parseJsonc;
4
+ exports.applyJsoncEdit = applyJsoncEdit;
5
+ const jsonc_parser_1 = require("jsonc-parser");
6
+ function formatErrors(errors) {
7
+ return errors.map(error => `${error.error} at offset ${error.offset}`).join(', ');
8
+ }
9
+ function parseJsonc(text) {
10
+ const errors = [];
11
+ const parsed = (0, jsonc_parser_1.parse)(text, errors, { allowTrailingComma: true, disallowComments: false });
12
+ if (errors.length > 0)
13
+ throw new Error(`Invalid JSONC: ${formatErrors(errors)}`);
14
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
15
+ throw new Error('Invalid JSONC: expected object root');
16
+ }
17
+ return parsed;
18
+ }
19
+ function applyJsoncEdit(text, editPath, value) {
20
+ const errors = [];
21
+ (0, jsonc_parser_1.parse)(text, errors, { allowTrailingComma: true, disallowComments: false });
22
+ if (errors.length > 0)
23
+ throw new Error(`Invalid JSONC: ${formatErrors(errors)}`);
24
+ const edits = (0, jsonc_parser_1.modify)(text, editPath, value, {
25
+ formattingOptions: { insertSpaces: true, tabSize: 2, eol: '\n' },
26
+ getInsertionIndex: properties => properties.length,
27
+ });
28
+ return (0, jsonc_parser_1.applyEdits)(text, edits);
29
+ }