@jagilber-org/index-server 1.26.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 CHANGED
@@ -1437,3 +1437,7 @@ No client changes required. Enable `INDEX_SERVER_MEMOIZE=1` (and optionally `IND
1437
1437
  ### Added
1438
1438
 
1439
1439
  - Add --init-cert CLI switch for self-signed dashboard TLS bootstrap (PR #233, issue #232)
1440
+
1441
+ ## [1.26.2] - 2026-04-27
1442
+
1443
+ ## [1.26.4] - 2026-04-28
@@ -1,29 +1,29 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta name="dashboard-build-version" content="1.26.1-9badd8dd">
4
+ <meta name="dashboard-build-version" content="1.26.4-9badd8dd">
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>Index Server Admin</title>
8
- <link rel="stylesheet" href="css/admin.css?v=1.26.1-9badd8dd">
9
- <script defer src="js/admin.utils.js?v=1.26.1-9badd8dd"></script>
10
- <script defer src="js/admin.auth.js?v=1.26.1-9badd8dd"></script>
11
- <script defer src="js/admin.overview.js?v=1.26.1-9badd8dd"></script>
12
- <script defer src="js/admin.sessions.js?v=1.26.1-9badd8dd"></script>
13
- <script defer src="js/admin.monitor.js?v=1.26.1-9badd8dd"></script>
14
- <script defer src="js/admin.graph.js?v=1.26.1-9badd8dd"></script>
8
+ <link rel="stylesheet" href="css/admin.css?v=1.26.4-9badd8dd">
9
+ <script defer src="js/admin.utils.js?v=1.26.4-9badd8dd"></script>
10
+ <script defer src="js/admin.auth.js?v=1.26.4-9badd8dd"></script>
11
+ <script defer src="js/admin.overview.js?v=1.26.4-9badd8dd"></script>
12
+ <script defer src="js/admin.sessions.js?v=1.26.4-9badd8dd"></script>
13
+ <script defer src="js/admin.monitor.js?v=1.26.4-9badd8dd"></script>
14
+ <script defer src="js/admin.graph.js?v=1.26.4-9badd8dd"></script>
15
15
  <script defer src="js/marked.umd.js"></script>
16
- <script defer src="js/admin.instructions.js?v=1.26.1-9badd8dd"></script>
17
- <script defer src="js/admin.logs.js?v=1.26.1-9badd8dd"></script>
18
- <script defer src="js/admin.maintenance.js?v=1.26.1-9badd8dd"></script>
19
- <script defer src="js/admin.config.js?v=1.26.1-9badd8dd"></script>
20
- <script defer src="js/admin.performance.js?v=1.26.1-9badd8dd"></script>
21
- <script defer src="js/admin.instances.js?v=1.26.1-9badd8dd"></script>
22
- <script defer src="js/admin.embeddings.js?v=1.26.1-9badd8dd"></script>
23
- <script defer src="js/admin.messaging.js?v=1.26.1-9badd8dd"></script>
24
- <script defer src="js/admin.sqlite.js?v=1.26.1-9badd8dd"></script>
25
- <script defer src="js/admin.boot.js?v=1.26.1-9badd8dd"></script>
26
- <script defer src="js/admin.feedback.js?v=1.26.1-9badd8dd"></script>
16
+ <script defer src="js/admin.instructions.js?v=1.26.4-9badd8dd"></script>
17
+ <script defer src="js/admin.logs.js?v=1.26.4-9badd8dd"></script>
18
+ <script defer src="js/admin.maintenance.js?v=1.26.4-9badd8dd"></script>
19
+ <script defer src="js/admin.config.js?v=1.26.4-9badd8dd"></script>
20
+ <script defer src="js/admin.performance.js?v=1.26.4-9badd8dd"></script>
21
+ <script defer src="js/admin.instances.js?v=1.26.4-9badd8dd"></script>
22
+ <script defer src="js/admin.embeddings.js?v=1.26.4-9badd8dd"></script>
23
+ <script defer src="js/admin.messaging.js?v=1.26.4-9badd8dd"></script>
24
+ <script defer src="js/admin.sqlite.js?v=1.26.4-9badd8dd"></script>
25
+ <script defer src="js/admin.boot.js?v=1.26.4-9badd8dd"></script>
26
+ <script defer src="js/admin.feedback.js?v=1.26.4-9badd8dd"></script>
27
27
  </head>
28
28
  <body>
29
29
  <div class="admin-container admin-root">
@@ -879,10 +879,10 @@
879
879
  }
880
880
  }
881
881
 
882
- // Graph logic was extracted to js/admin.graph.js?v=1.26.1-9badd8dd
882
+ // Graph logic was extracted to js/admin.graph.js?v=1.26.4-9badd8dd
883
883
  // Functions available globally: reloadGraphMermaid, initGraphScopeDefaults, copyMermaidSource, toggleGraphEdit, applyGraphEdit, cancelGraphEdit, refreshDrillCategories, loadDrillInstructions, clearSelections
884
884
 
885
- <!-- overview functions moved to js/admin.overview.js?v=1.26.1-9badd8dd -->
885
+ <!-- overview functions moved to js/admin.overview.js?v=1.26.4-9badd8dd -->
886
886
 
887
887
  // Lightweight overview-level maintenance display (optional)
888
888
  // Intentionally minimal to avoid blocking overview rendering.
@@ -1067,7 +1067,7 @@
1067
1067
  }
1068
1068
 
1069
1069
  // --- Backup / Restore ---
1070
- // Extracted to js/admin.maintenance.js?v=1.26.1-9badd8dd
1070
+ // Extracted to js/admin.maintenance.js?v=1.26.4-9badd8dd
1071
1071
 
1072
1072
  async function performBackup() {
1073
1073
  try {
@@ -1133,7 +1133,7 @@
1133
1133
  }
1134
1134
 
1135
1135
  async function loadConfiguration() {
1136
- // Primary implementation in js/admin.config.js?v=1.26.1-9badd8dd (loaded via defer).
1136
+ // Primary implementation in js/admin.config.js?v=1.26.4-9badd8dd (loaded via defer).
1137
1137
  // This inline fallback only fires if the external script failed to load.
1138
1138
  if (window.__configExternalLoaded) return;
1139
1139
  try {
@@ -1193,10 +1193,10 @@
1193
1193
  return false;
1194
1194
  }
1195
1195
 
1196
- // Monitoring functions moved to js/admin.monitor.js?v=1.26.1-9badd8dd
1196
+ // Monitoring functions moved to js/admin.monitor.js?v=1.26.4-9badd8dd
1197
1197
 
1198
1198
  // ===== Log Viewer =====
1199
- // Extracted to js/admin.logs.js?v=1.26.1-9badd8dd
1199
+ // Extracted to js/admin.logs.js?v=1.26.4-9badd8dd
1200
1200
 
1201
1201
  // ===== Instruction Management =====
1202
1202
  let instructionEditing = null;
@@ -1693,7 +1693,7 @@
1693
1693
  setInterval(fetchResourceTrends, 10000);
1694
1694
  })();
1695
1695
 
1696
- // Instruction management logic extracted to js/admin.instructions.js?v=1.26.1-9badd8dd
1696
+ // Instruction management logic extracted to js/admin.instructions.js?v=1.26.4-9badd8dd
1697
1697
  // Functions exposed globally: loadInstructions, renderInstructionList, editInstruction, saveInstruction, deleteInstruction, etc.
1698
1698
 
1699
1699
  function startAutoRefresh() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jagilber-org/index-server",
3
- "version": "1.26.1",
3
+ "version": "1.26.4",
4
4
  "mcpName": "io.github.jagilber-org/index-server",
5
5
  "description": "MCP instruction indexing server for AI assistant governance — search, CRUD, schema validation, usage tracking, and cross-repo knowledge promotion.",
6
6
  "publishConfig": {
@@ -18,6 +18,7 @@
18
18
  "templates/",
19
19
  "scripts/copy-dashboard-assets.mjs",
20
20
  "scripts/setup-hooks.cjs",
21
+ "scripts/generate-certs.mjs",
21
22
  "scripts/setup-wizard.mjs",
22
23
  "server.json",
23
24
  "README.md",
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate-certs.mjs — Generate self-signed TLS certificates for Index Server.
4
+ *
5
+ * Creates a CA + server certificate pair in ./certs/ for HTTPS dashboard access.
6
+ * For production, replace with certificates from a real CA.
7
+ *
8
+ * Usage:
9
+ * node scripts/generate-certs.mjs [--hostname <name>] [--days <n>] [--output <dir>]
10
+ */
11
+ import { execFileSync } from 'child_process';
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import { fileURLToPath } from 'url';
15
+
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+ const ROOT = path.resolve(__dirname, '..');
18
+
19
+ function parseArgs() {
20
+ const args = process.argv.slice(2);
21
+ const config = {
22
+ hostname: 'localhost',
23
+ days: 365,
24
+ outputDir: path.join(ROOT, 'certs'),
25
+ keySize: 4096,
26
+ };
27
+ for (let i = 0; i < args.length; i++) {
28
+ if (args[i] === '--hostname' && args[i + 1]) config.hostname = args[++i];
29
+ else if (args[i] === '--days' && args[i + 1]) config.days = parseInt(args[++i], 10);
30
+ else if (args[i] === '--output' && args[i + 1]) config.outputDir = path.resolve(args[++i]);
31
+ else if (args[i] === '--key-size' && args[i + 1]) config.keySize = parseInt(args[++i], 10);
32
+ else if (args[i] === '--help') {
33
+ console.log(`Usage: generate-certs.mjs [options]
34
+ --hostname <name> Server hostname (default: localhost)
35
+ --days <n> Certificate validity in days (default: 365)
36
+ --output <dir> Output directory (default: ./certs)
37
+ --key-size <bits> RSA key size (default: 4096)`);
38
+ process.exit(0);
39
+ }
40
+ }
41
+ return config;
42
+ }
43
+
44
+ const WELL_KNOWN_OPENSSL_DIRS = [
45
+ 'C:\\Program Files\\Git\\usr\\bin',
46
+ 'C:\\Program Files (x86)\\Git\\usr\\bin',
47
+ 'C:\\Program Files\\OpenSSL-Win64\\bin',
48
+ 'C:\\Program Files\\OpenSSL\\bin',
49
+ ];
50
+
51
+ function checkOpenssl() {
52
+ try {
53
+ execFileSync('openssl', ['version'], { stdio: 'pipe' });
54
+ return true;
55
+ } catch {
56
+ // Try well-known paths on Windows
57
+ for (const dir of WELL_KNOWN_OPENSSL_DIRS) {
58
+ const exe = path.join(dir, 'openssl.exe');
59
+ if (fs.existsSync(exe)) {
60
+ console.log(`ℹ️ Found OpenSSL at: ${dir}`);
61
+ process.env.PATH = `${dir}${path.delimiter}${process.env.PATH}`;
62
+ return true;
63
+ }
64
+ }
65
+ return false;
66
+ }
67
+ }
68
+
69
+ function runOpenSsl(args, options = {}) {
70
+ execFileSync('openssl', args, { stdio: 'pipe', ...options });
71
+ }
72
+
73
+ function generateCerts(config) {
74
+ const { hostname, days, outputDir, keySize } = config;
75
+
76
+ // Validate hostname to prevent command injection via -subj parameter
77
+ if (!/^[a-zA-Z0-9._-]+$/.test(hostname)) {
78
+ console.error(`❌ Invalid hostname: "${hostname}". Only alphanumeric, dots, hyphens, and underscores allowed.`);
79
+ process.exit(1);
80
+ }
81
+ if (!Number.isInteger(days) || days < 1 || days > 3650) {
82
+ console.error(`❌ Invalid days value: "${days}". Expected an integer between 1 and 3650.`);
83
+ process.exit(1);
84
+ }
85
+ if (!Number.isInteger(keySize) || ![2048, 3072, 4096].includes(keySize)) {
86
+ console.error(`❌ Invalid key size: "${keySize}". Allowed values: 2048, 3072, 4096.`);
87
+ process.exit(1);
88
+ }
89
+
90
+ // Ensure output directory exists
91
+ fs.mkdirSync(outputDir, { recursive: true });
92
+
93
+ const caKeyPath = path.join(outputDir, 'ca.key');
94
+ const caCertPath = path.join(outputDir, 'ca.crt');
95
+ const serverKeyPath = path.join(outputDir, 'server.key');
96
+ const serverCsrPath = path.join(outputDir, 'server.csr');
97
+ const serverCertPath = path.join(outputDir, 'server.crt');
98
+ const extPath = path.join(outputDir, 'server.ext');
99
+ const cnfPath = path.join(outputDir, 'openssl.cnf');
100
+
101
+ console.log(`\n🔐 Generating TLS certificates for: ${hostname}`);
102
+ console.log(` Output: ${outputDir}`);
103
+ console.log(` Validity: ${days} days`);
104
+ console.log(` Key size: ${keySize} bits\n`);
105
+
106
+ // Create a minimal openssl config to avoid system config issues (Windows compat)
107
+ const cnfContent = `[req]
108
+ distinguished_name = req_dn
109
+ prompt = no
110
+
111
+ [req_dn]
112
+ C = US
113
+ ST = Dev
114
+ L = Local
115
+ O = IndexServer
116
+ `;
117
+ fs.writeFileSync(cnfPath, cnfContent, 'utf8');
118
+ const cnfEnv = { ...process.env, OPENSSL_CONF: cnfPath };
119
+
120
+ // Step 1: Generate CA private key
121
+ console.log('1/5 Generating CA private key...');
122
+ runOpenSsl(['genrsa', '-out', caKeyPath, String(keySize)], { env: cnfEnv });
123
+
124
+ // Step 2: Generate CA certificate
125
+ console.log('2/5 Generating CA certificate...');
126
+ runOpenSsl([
127
+ 'req', '-x509', '-new', '-nodes', '-key', caKeyPath, '-sha256', '-days', String(days),
128
+ '-subj', '/C=US/ST=Dev/L=Local/O=IndexServer/OU=Dev/CN=IndexServerCA',
129
+ '-config', cnfPath, '-out', caCertPath,
130
+ ], { env: cnfEnv });
131
+
132
+ // Step 3: Generate server private key
133
+ console.log('3/5 Generating server private key...');
134
+ runOpenSsl(['genrsa', '-out', serverKeyPath, String(keySize)], { env: cnfEnv });
135
+
136
+ // Step 4: Generate server CSR
137
+ console.log('4/5 Generating server CSR...');
138
+ runOpenSsl([
139
+ 'req', '-new', '-key', serverKeyPath,
140
+ '-subj', `/C=US/ST=Dev/L=Local/O=IndexServer/OU=Server/CN=${hostname}`,
141
+ '-config', cnfPath, '-out', serverCsrPath,
142
+ ], { env: cnfEnv });
143
+
144
+ // Step 5: Create extensions file and sign server cert
145
+ console.log('5/5 Signing server certificate...');
146
+ const extContent = `authorityKeyIdentifier=keyid,issuer
147
+ basicConstraints=CA:FALSE
148
+ keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
149
+ subjectAltName=@alt_names
150
+
151
+ [alt_names]
152
+ DNS.1=${hostname}
153
+ DNS.2=*.${hostname}
154
+ IP.1=127.0.0.1
155
+ IP.2=::1`;
156
+
157
+ fs.writeFileSync(extPath, extContent, 'utf8');
158
+
159
+ runOpenSsl([
160
+ 'x509', '-req', '-in', serverCsrPath, '-CA', caCertPath, '-CAkey', caKeyPath,
161
+ '-CAcreateserial', '-out', serverCertPath, '-days', String(days), '-sha256', '-extfile', extPath,
162
+ ], { env: cnfEnv });
163
+
164
+ // Cleanup intermediate files
165
+ try { fs.unlinkSync(serverCsrPath); } catch { /* ok */ }
166
+ try { fs.unlinkSync(extPath); } catch { /* ok */ }
167
+ try { fs.unlinkSync(cnfPath); } catch { /* ok */ }
168
+ try { fs.unlinkSync(path.join(outputDir, 'ca.srl')); } catch { /* ok */ }
169
+
170
+ // Set restrictive permissions on private keys
171
+ try {
172
+ fs.chmodSync(caKeyPath, 0o600);
173
+ fs.chmodSync(serverKeyPath, 0o600);
174
+ } catch { /* Windows doesn't support chmod */ }
175
+
176
+ console.log('\n✅ TLS certificates generated successfully:');
177
+ console.log(` CA cert: ${caCertPath}`);
178
+ console.log(` Server cert: ${serverCertPath}`);
179
+ console.log(` Server key: ${serverKeyPath}`);
180
+ console.log(` CA key: ${caKeyPath}`);
181
+ console.log('\nTo use with Docker:');
182
+ console.log(' docker compose --profile tls up -d');
183
+ console.log('\nTo use standalone:');
184
+ console.log(` INDEX_SERVER_DASHBOARD_TLS=1 \\`);
185
+ console.log(` INDEX_SERVER_DASHBOARD_TLS_CERT=${serverCertPath} \\`);
186
+ console.log(` INDEX_SERVER_DASHBOARD_TLS_KEY=${serverKeyPath} \\`);
187
+ console.log(' node dist/server/index-server.js --dashboard');
188
+ }
189
+
190
+ // Main
191
+ const config = parseArgs();
192
+ if (!checkOpenssl()) {
193
+ console.error('❌ OpenSSL is not installed or not in PATH.');
194
+ console.error(' Install OpenSSL and try again.');
195
+ console.error(' Options:');
196
+ console.error(' - Install Git for Windows (includes OpenSSL): https://git-scm.com/download/win');
197
+ console.error(' - Install OpenSSL directly: https://slproweb.com/products/Win32OpenSSL.html');
198
+ console.error(' - On Linux/macOS: sudo apt install openssl / brew install openssl');
199
+ process.exit(1);
200
+ }
201
+ generateCerts(config);
package/server.json CHANGED
@@ -1 +1,20 @@
1
- { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.jagilber-org/index-server", "description": "MCP instruction indexing server for AI assistant governance — search, CRUD, schema validation, usage tracking, and cross-repo knowledge promotion.", "repository": { "url": "https://github.com/jagilber-org/index-server", "source": "github" }, "version": "1.26.1", "packages": [ { "registryType": "npm", "identifier": "@jagilber-org/index-server", "version": "1.26.1", "transport": { "type": "stdio" } } ]}
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.jagilber-org/index-server",
4
+ "description": "MCP instruction indexing server for AI assistant governance — search, CRUD, schema validation, usage tracking, and cross-repo knowledge promotion.",
5
+ "repository": {
6
+ "url": "https://github.com/jagilber-org/index-server",
7
+ "source": "github"
8
+ },
9
+ "version": "1.26.4",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "@jagilber-org/index-server",
14
+ "version": "1.26.4",
15
+ "transport": {
16
+ "type": "stdio"
17
+ }
18
+ }
19
+ ]
20
+ }