@jagilber-org/index-server 1.26.11 → 1.27.2
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 +53 -1
- package/dist/config/dashboardConfig.d.ts +11 -4
- package/dist/config/dashboardConfig.js +1 -4
- package/dist/dashboard/client/admin.html +57 -27
- package/dist/dashboard/client/css/admin.css +54 -0
- package/dist/dashboard/client/js/admin.config.js +3 -6
- package/dist/dashboard/client/js/admin.embeddings.js +63 -4
- package/dist/dashboard/client/js/admin.events.js +256 -0
- package/dist/dashboard/client/js/admin.maintenance.js +75 -32
- package/dist/dashboard/client/js/admin.sessions.js +1 -1
- package/dist/dashboard/server/AdminPanel.js +83 -6
- package/dist/dashboard/server/AdminPanelConfig.d.ts +12 -2
- package/dist/dashboard/server/AdminPanelConfig.js +48 -19
- package/dist/dashboard/server/ApiRoutes.d.ts +5 -4
- package/dist/dashboard/server/ApiRoutes.js +40 -35
- package/dist/dashboard/server/DashboardServer.js +13 -0
- package/dist/dashboard/server/routes/admin.routes.js +143 -17
- package/dist/dashboard/server/routes/embeddings.routes.js +91 -1
- package/dist/dashboard/server/routes/index.js +11 -9
- package/dist/server/sdkServer.js +12 -4
- package/dist/services/embeddingService.d.ts +2 -0
- package/dist/services/embeddingService.js +16 -4
- package/dist/services/embeddingTrigger.d.ts +33 -0
- package/dist/services/embeddingTrigger.js +86 -0
- package/dist/services/eventBuffer.d.ts +45 -0
- package/dist/services/eventBuffer.js +110 -0
- package/dist/services/handlers/instructions.import.js +71 -13
- package/dist/services/handlers.dashboardConfig.js +82 -2
- package/dist/services/indexContext.d.ts +18 -0
- package/dist/services/indexContext.js +138 -30
- package/dist/services/logger.js +9 -0
- package/dist/services/manifestManager.js +11 -1
- package/dist/services/seedBootstrap.js +5 -1
- package/dist/services/storage/factory.d.ts +2 -0
- package/dist/services/storage/factory.js +12 -1
- package/dist/services/tracing.js +3 -1
- package/package.json +12 -2
- package/schemas/index-server.code-schema.json +7424 -1588
- package/schemas/manifest.json +3 -3
- package/server.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,59 @@ The format is based on Keep a Changelog and this project adheres to Semantic Ver
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
## [1.
|
|
9
|
+
## [1.27.2] - 2026-05-01
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Release workflow** (`.github/workflows/release.yml`): trim `description` in `package.json` and `server.json` from 146 to 98 chars to satisfy the MCP Registry validator (`expected length <= 100` on `body.description`). The MCP Registry publish step had been failing on every release since v1.26.3 with HTTP 422.
|
|
14
|
+
- **Release workflow** (`scripts/Invoke-ReleaseWorkflow.ps1`): add a fail-fast parity guard that aborts before tagging when `package.json.version` does not match the `-Tag` argument (sans `v` prefix). The v1.27.1 release shipped a tag whose `package.json` still said `1.27.0`, which caused the `Check npmjs version status` step to skip publish (it found `1.27.0` already on npmjs and set `already_published=true`). This guard prevents the same class of mismatch from reaching the public mirror again.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Release workflow** (`.github/workflows/release.yml`): publish to the GitHub Packages npm registry (`https://npm.pkg.github.com`) in addition to npmjs, so `https://github.com/jagilber-org/index-server/pkgs/npm/index-server` populates on each release. Auth uses the workflow-scoped `GITHUB_TOKEN` (no extra secret needed).
|
|
19
|
+
|
|
20
|
+
### Notes
|
|
21
|
+
|
|
22
|
+
- v1.27.1 was tagged on the public mirror but is **incomplete**: the npmjs publish step was skipped (stale version in tag), the GitHub Packages registry was never wired (now fixed), and the MCP Registry rejected the description (now fixed). v1.27.2 is the corrected release. v1.27.1 will not be retroactively republished.
|
|
23
|
+
|
|
24
|
+
## [1.27.1] - 2026-05-01
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **Security**: pin `mermaid` and `@mermaid-js/layout-elk` transitive `uuid` to `^14.0.0` via npm overrides to clear GHSA-w5hq-g745-h8pq. Server-side bundle has no mermaid imports; dashboard remains lazy-loaded.
|
|
29
|
+
- **Build**: pin `@types/express-serve-static-core` to `5.0.7` to keep dashboard route handler signatures stable after lockfile regen pulled `5.1.1` (which changed `req.params` typing).
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **Deploy** (`scripts/deploy-local.ps1`): runtime `package.json` written to the deploy target now preserves the `overrides` block from the source manifest. Without it, `npm ci --omit=dev` failed with `EUSAGE Missing: uuid@11.1.1 from lock file` because the override-resolved lockfile didn't match the unstripped manifest.
|
|
34
|
+
- **CodeQL pre-push gate** (`scripts/run-codeql-pre-push.ps1`): now sources `scripts/Load-RepoEnv.ps1` and honors absolute paths from `.env` (`CODEQL_DB_PATH`, `CODEQL_LOG_DIR`, `CODEQL_OUTPUT_PATH`, `CODEQL_LANGUAGE`, `CODEQL_THREADS`, `CODEQL_RAM`). Reuses pre-built databases instead of always rebuilding in-repo.
|
|
35
|
+
- **Publish workflow** (`scripts/Publish-ToMirror.ps1`): after opening a publish PR via `-CreatePR`, now prints a copy-pasteable next-steps block (`gh api …/git/refs` + `gh release create --generate-notes`) so the operator can tag the merge commit and kick off the GitHub release in one shot. The `-WaitForMerge` success path also surfaces the `gh release create` command.
|
|
36
|
+
|
|
37
|
+
## [1.27.0] - 2026-04-30
|
|
38
|
+
|
|
39
|
+
### Changed (BREAKING)
|
|
40
|
+
|
|
41
|
+
- **Rate limiting is now opt-in** and consolidated behind a single environment variable, `INDEX_SERVER_RATE_LIMIT` (#270).
|
|
42
|
+
- `INDEX_SERVER_RATE_LIMIT=0` (default, or unset) — rate limiting is **disabled**.
|
|
43
|
+
- `INDEX_SERVER_RATE_LIMIT=N` (positive integer) — enforces **N requests per minute** with a fixed 60-second window.
|
|
44
|
+
- Bulk import/export/backup/restore routes (`/api/admin/maintenance/normalize`, `/api/admin/maintenance/backup`, `/api/admin/maintenance/backups`, `/api/admin/maintenance/restore`, `/api/charts/export`, `/api/sqlite/backup`, `/api/sqlite/restore`, `/api/sqlite/export`) are **unconditionally exempt**, so dashboard bulk operations no longer trigger 429 responses.
|
|
45
|
+
- The 429 response body shape simplifies to `{ error, message, retryAfterSeconds, timestamp }`. The previous `tier` field (global vs. mutation) has been removed; there is now a single tier.
|
|
46
|
+
|
|
47
|
+
### Removed (BREAKING)
|
|
48
|
+
|
|
49
|
+
The following environment variables have been **removed with no back-compat aliases**. Replace them with `INDEX_SERVER_RATE_LIMIT`:
|
|
50
|
+
|
|
51
|
+
| Removed variable | Replacement |
|
|
52
|
+
|------------------|-------------|
|
|
53
|
+
| `INDEX_SERVER_DISABLE_RATE_LIMIT` | unset / `INDEX_SERVER_RATE_LIMIT=0` (default) |
|
|
54
|
+
| `INDEX_SERVER_DISABLE_USAGE_RATE_LIMIT` | unset / `INDEX_SERVER_RATE_LIMIT=0` (default) |
|
|
55
|
+
| `INDEX_SERVER_RATE_LIMIT_MAX` | `INDEX_SERVER_RATE_LIMIT=<N>` |
|
|
56
|
+
| `INDEX_SERVER_RATE_LIMIT_WINDOW_MS` | _removed; window is fixed at 60 seconds_ |
|
|
57
|
+
| `INDEX_SERVER_RATE_LIMIT_MUTATION_MAX` | _removed; single tier only_ |
|
|
58
|
+
|
|
59
|
+
Also removed: `DashboardHttpConfig.rateLimitEnabled / rateLimitWindowMs / rateLimitMax / rateLimitMutationMax` (replaced by `rateLimitPerMinute: number`); `ApiRoutesOptions.rateLimit` (replaced by `rateLimitPerMinute?: number`); `AdminConfig.serverSettings.rateLimit` reduced to `{ perMinute: number }`.
|
|
60
|
+
|
|
61
|
+
|
|
10
62
|
|
|
11
63
|
### Fixed
|
|
12
64
|
|
|
@@ -15,10 +15,17 @@ interface DashboardHttpConfig {
|
|
|
15
15
|
verboseLogging: boolean;
|
|
16
16
|
mutationEnabled: boolean;
|
|
17
17
|
adminApiKey?: string;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Dashboard HTTP API rate limit, in requests per minute.
|
|
20
|
+
*
|
|
21
|
+
* - `0` (default) disables rate limiting entirely (HTTP API + usage tracking).
|
|
22
|
+
* - Any positive integer N enforces N requests/min globally with a fixed
|
|
23
|
+
* 60-second window. Bulk import/export/backup/restore routes are
|
|
24
|
+
* unconditionally exempt regardless of this value.
|
|
25
|
+
*
|
|
26
|
+
* Configured via the `INDEX_SERVER_RATE_LIMIT` environment variable.
|
|
27
|
+
*/
|
|
28
|
+
rateLimitPerMinute: number;
|
|
22
29
|
tls: DashboardTlsConfig;
|
|
23
30
|
}
|
|
24
31
|
interface DashboardAdminConfig {
|
|
@@ -36,10 +36,7 @@ function parseDashboardConfig(mutationEnabled, instructionsBaseDir) {
|
|
|
36
36
|
verboseLogging: (0, envUtils_1.getBooleanEnv)('INDEX_SERVER_VERBOSE_LOGGING'),
|
|
37
37
|
mutationEnabled,
|
|
38
38
|
adminApiKey: process.env.INDEX_SERVER_ADMIN_API_KEY || undefined,
|
|
39
|
-
|
|
40
|
-
rateLimitWindowMs: Math.max(1, (0, configUtils_1.numberFromEnv)('INDEX_SERVER_RATE_LIMIT_WINDOW_MS', 60_000)),
|
|
41
|
-
rateLimitMax: Math.max(0, (0, configUtils_1.numberFromEnv)('INDEX_SERVER_RATE_LIMIT_MAX', 100)),
|
|
42
|
-
rateLimitMutationMax: Math.max(0, (0, configUtils_1.numberFromEnv)('INDEX_SERVER_RATE_LIMIT_MUTATION_MAX', 20)),
|
|
39
|
+
rateLimitPerMinute: Math.max(0, (0, configUtils_1.numberFromEnv)('INDEX_SERVER_RATE_LIMIT', 0)),
|
|
43
40
|
tls: {
|
|
44
41
|
enabled: (0, envUtils_1.getBooleanEnv)('INDEX_SERVER_DASHBOARD_TLS'),
|
|
45
42
|
certPath: process.env.INDEX_SERVER_DASHBOARD_TLS_CERT || undefined,
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
<meta name="dashboard-build-version" content="1.
|
|
4
|
+
<meta name="dashboard-build-version" content="1.27.2-d7f5ec0e">
|
|
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.
|
|
9
|
-
<script defer src="js/admin.utils.js?v=1.
|
|
10
|
-
<script defer src="js/admin.auth.js?v=1.
|
|
11
|
-
<script defer src="js/admin.overview.js?v=1.
|
|
12
|
-
<script defer src="js/admin.sessions.js?v=1.
|
|
13
|
-
<script defer src="js/admin.monitor.js?v=1.
|
|
14
|
-
<script defer src="js/admin.
|
|
8
|
+
<link rel="stylesheet" href="css/admin.css?v=1.27.2-d7f5ec0e">
|
|
9
|
+
<script defer src="js/admin.utils.js?v=1.27.2-d7f5ec0e"></script>
|
|
10
|
+
<script defer src="js/admin.auth.js?v=1.27.2-d7f5ec0e"></script>
|
|
11
|
+
<script defer src="js/admin.overview.js?v=1.27.2-d7f5ec0e"></script>
|
|
12
|
+
<script defer src="js/admin.sessions.js?v=1.27.2-d7f5ec0e"></script>
|
|
13
|
+
<script defer src="js/admin.monitor.js?v=1.27.2-d7f5ec0e"></script>
|
|
14
|
+
<script defer src="js/admin.events.js?v=1.27.2-d7f5ec0e"></script>
|
|
15
|
+
<script defer src="js/admin.graph.js?v=1.27.2-d7f5ec0e"></script>
|
|
15
16
|
<script defer src="js/marked.umd.js"></script>
|
|
16
|
-
<script defer src="js/admin.instructions.js?v=1.
|
|
17
|
-
<script defer src="js/admin.logs.js?v=1.
|
|
18
|
-
<script defer src="js/admin.maintenance.js?v=1.
|
|
19
|
-
<script defer src="js/admin.config.js?v=1.
|
|
20
|
-
<script defer src="js/admin.performance.js?v=1.
|
|
21
|
-
<script defer src="js/admin.instances.js?v=1.
|
|
22
|
-
<script defer src="js/admin.embeddings.js?v=1.
|
|
23
|
-
<script defer src="js/admin.messaging.js?v=1.
|
|
24
|
-
<script defer src="js/admin.sqlite.js?v=1.
|
|
25
|
-
<script defer src="js/admin.boot.js?v=1.
|
|
26
|
-
<script defer src="js/admin.feedback.js?v=1.
|
|
17
|
+
<script defer src="js/admin.instructions.js?v=1.27.2-d7f5ec0e"></script>
|
|
18
|
+
<script defer src="js/admin.logs.js?v=1.27.2-d7f5ec0e"></script>
|
|
19
|
+
<script defer src="js/admin.maintenance.js?v=1.27.2-d7f5ec0e"></script>
|
|
20
|
+
<script defer src="js/admin.config.js?v=1.27.2-d7f5ec0e"></script>
|
|
21
|
+
<script defer src="js/admin.performance.js?v=1.27.2-d7f5ec0e"></script>
|
|
22
|
+
<script defer src="js/admin.instances.js?v=1.27.2-d7f5ec0e"></script>
|
|
23
|
+
<script defer src="js/admin.embeddings.js?v=1.27.2-d7f5ec0e"></script>
|
|
24
|
+
<script defer src="js/admin.messaging.js?v=1.27.2-d7f5ec0e"></script>
|
|
25
|
+
<script defer src="js/admin.sqlite.js?v=1.27.2-d7f5ec0e"></script>
|
|
26
|
+
<script defer src="js/admin.boot.js?v=1.27.2-d7f5ec0e"></script>
|
|
27
|
+
<script defer src="js/admin.feedback.js?v=1.27.2-d7f5ec0e"></script>
|
|
27
28
|
</head>
|
|
28
29
|
<body>
|
|
29
30
|
<div class="admin-container admin-root">
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
<button class="nav-btn" data-section="config" onclick="window.showSection && window.showSection('config')">Configuration</button>
|
|
49
50
|
<button id="nav-sessions" class="nav-btn" data-section="sessions" onclick="window.showSection && window.showSection('sessions')">Sessions</button>
|
|
50
51
|
<button class="nav-btn" data-section="maintenance" onclick="window.showSection && window.showSection('maintenance')">Maintenance</button>
|
|
51
|
-
<button class="nav-btn" data-section="monitoring" onclick="window.showSection && window.showSection('monitoring')">Monitoring
|
|
52
|
+
<button class="nav-btn" data-section="monitoring" onclick="window.showSection && window.showSection('monitoring')">Monitoring<span id="nav-events-bubble" class="nav-bubble" hidden></span></button>
|
|
52
53
|
<button class="nav-btn" data-section="instructions" onclick="window.showSection && window.showSection('instructions')">Instructions</button>
|
|
53
54
|
<button class="nav-btn" data-section="graph" onclick="window.showSection && window.showSection('graph')">Graph</button>
|
|
54
55
|
<button class="nav-btn" data-section="embeddings" onclick="window.showSection && window.showSection('embeddings')">Embeddings</button>
|
|
@@ -328,6 +329,34 @@
|
|
|
328
329
|
<!-- Monitoring Section -->
|
|
329
330
|
<div id="monitoring-section" class="admin-section hidden">
|
|
330
331
|
<div class="admin-card">
|
|
332
|
+
<div class="card-header">
|
|
333
|
+
<div class="card-icon">⚠️</div>
|
|
334
|
+
<div class="card-title">Recent Events <span id="events-counts-summary" class="muted small"></span></div>
|
|
335
|
+
<div class="card-actions">
|
|
336
|
+
<input id="events-search" class="form-input form-input-sm events-search" type="search" placeholder="Search msg/detail…" />
|
|
337
|
+
<select id="events-level-filter" class="form-input form-input-sm">
|
|
338
|
+
<option value="">All severities</option>
|
|
339
|
+
<option value="WARN">WARN only</option>
|
|
340
|
+
<option value="ERROR">ERROR only</option>
|
|
341
|
+
</select>
|
|
342
|
+
<select id="events-page-size" class="form-input form-input-sm" title="Page size">
|
|
343
|
+
<option value="25">25 / page</option>
|
|
344
|
+
<option value="50" selected>50 / page</option>
|
|
345
|
+
<option value="100">100 / page</option>
|
|
346
|
+
<option value="200">200 / page</option>
|
|
347
|
+
</select>
|
|
348
|
+
<button id="events-refresh-btn" class="action-btn-sm" onclick="window.loadEvents && window.loadEvents()">Refresh</button>
|
|
349
|
+
<button id="events-clear-btn" class="action-btn-sm" onclick="window.clearEvents && window.clearEvents()">Mark All Read</button>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
352
|
+
<div id="events-panel" class="loading">Loading events…</div>
|
|
353
|
+
<div id="events-pager" class="events-pager hidden">
|
|
354
|
+
<button id="events-prev" class="action-btn-sm" type="button">‹ Newer</button>
|
|
355
|
+
<span id="events-page-info" class="muted small"></span>
|
|
356
|
+
<button id="events-next" class="action-btn-sm" type="button">Older ›</button>
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
<div class="admin-card mt-xxl">
|
|
331
360
|
<div class="card-header">
|
|
332
361
|
<div class="card-icon"><svg viewBox="0 0 24 24" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 14 10 14 12 10 16 20 18 14 22 14"/><circle cx="6" cy="6" r="2"/></svg></div>
|
|
333
362
|
<div class="card-title">Real-time Monitoring <a class="doc-link" href="/api/docs/monitoring" target="_blank" title="Panel documentation">?</a></div>
|
|
@@ -404,6 +433,7 @@
|
|
|
404
433
|
|
|
405
434
|
<!-- Embeddings Visualization Section -->
|
|
406
435
|
<div id="embeddings-section" class="admin-section hidden">
|
|
436
|
+
<div id="emb-status-banner" class="emb-status-banner hidden" role="status" aria-live="polite"></div>
|
|
407
437
|
<div class="admin-card" style="padding:0;overflow:hidden">
|
|
408
438
|
<div class="emb-layout">
|
|
409
439
|
<!-- Sidebar -->
|
|
@@ -879,10 +909,10 @@
|
|
|
879
909
|
}
|
|
880
910
|
}
|
|
881
911
|
|
|
882
|
-
// Graph logic was extracted to js/admin.graph.js?v=1.
|
|
912
|
+
// Graph logic was extracted to js/admin.graph.js?v=1.27.2-d7f5ec0e
|
|
883
913
|
// Functions available globally: reloadGraphMermaid, initGraphScopeDefaults, copyMermaidSource, toggleGraphEdit, applyGraphEdit, cancelGraphEdit, refreshDrillCategories, loadDrillInstructions, clearSelections
|
|
884
914
|
|
|
885
|
-
<!-- overview functions moved to js/admin.overview.js?v=1.
|
|
915
|
+
<!-- overview functions moved to js/admin.overview.js?v=1.27.2-d7f5ec0e -->
|
|
886
916
|
|
|
887
917
|
// Lightweight overview-level maintenance display (optional)
|
|
888
918
|
// Intentionally minimal to avoid blocking overview rendering.
|
|
@@ -1067,7 +1097,7 @@
|
|
|
1067
1097
|
}
|
|
1068
1098
|
|
|
1069
1099
|
// --- Backup / Restore ---
|
|
1070
|
-
// Extracted to js/admin.maintenance.js?v=1.
|
|
1100
|
+
// Extracted to js/admin.maintenance.js?v=1.27.2-d7f5ec0e
|
|
1071
1101
|
|
|
1072
1102
|
async function performBackup() {
|
|
1073
1103
|
try {
|
|
@@ -1133,7 +1163,7 @@
|
|
|
1133
1163
|
}
|
|
1134
1164
|
|
|
1135
1165
|
async function loadConfiguration() {
|
|
1136
|
-
// Primary implementation in js/admin.config.js?v=1.
|
|
1166
|
+
// Primary implementation in js/admin.config.js?v=1.27.2-d7f5ec0e (loaded via defer).
|
|
1137
1167
|
// This inline fallback only fires if the external script failed to load.
|
|
1138
1168
|
if (window.__configExternalLoaded) return;
|
|
1139
1169
|
try {
|
|
@@ -1193,10 +1223,10 @@
|
|
|
1193
1223
|
return false;
|
|
1194
1224
|
}
|
|
1195
1225
|
|
|
1196
|
-
// Monitoring functions moved to js/admin.monitor.js?v=1.
|
|
1226
|
+
// Monitoring functions moved to js/admin.monitor.js?v=1.27.2-d7f5ec0e
|
|
1197
1227
|
|
|
1198
1228
|
// ===== Log Viewer =====
|
|
1199
|
-
// Extracted to js/admin.logs.js?v=1.
|
|
1229
|
+
// Extracted to js/admin.logs.js?v=1.27.2-d7f5ec0e
|
|
1200
1230
|
|
|
1201
1231
|
// ===== Instruction Management =====
|
|
1202
1232
|
let instructionEditing = null;
|
|
@@ -1693,7 +1723,7 @@
|
|
|
1693
1723
|
setInterval(fetchResourceTrends, 10000);
|
|
1694
1724
|
})();
|
|
1695
1725
|
|
|
1696
|
-
// Instruction management logic extracted to js/admin.instructions.js?v=1.
|
|
1726
|
+
// Instruction management logic extracted to js/admin.instructions.js?v=1.27.2-d7f5ec0e
|
|
1697
1727
|
// Functions exposed globally: loadInstructions, renderInstructionList, editInstruction, saveInstruction, deleteInstruction, etc.
|
|
1698
1728
|
|
|
1699
1729
|
function startAutoRefresh() {
|
|
@@ -1159,6 +1159,36 @@ a.mermaid-link { color: var(--admin-accent); }
|
|
|
1159
1159
|
font-size: 12px;
|
|
1160
1160
|
color: var(--admin-text-dim);
|
|
1161
1161
|
}
|
|
1162
|
+
.emb-status-banner {
|
|
1163
|
+
margin: 0 0 12px 0;
|
|
1164
|
+
padding: 12px 16px;
|
|
1165
|
+
border-radius: 6px;
|
|
1166
|
+
border-left: 4px solid var(--admin-text-dim);
|
|
1167
|
+
background: rgba(255,255,255,0.04);
|
|
1168
|
+
font-size: 13px;
|
|
1169
|
+
line-height: 1.45;
|
|
1170
|
+
color: var(--admin-text);
|
|
1171
|
+
}
|
|
1172
|
+
.emb-status-banner.hidden { display: none; }
|
|
1173
|
+
.emb-status-banner .title {
|
|
1174
|
+
font-weight: 600;
|
|
1175
|
+
margin-bottom: 4px;
|
|
1176
|
+
display: flex;
|
|
1177
|
+
align-items: center;
|
|
1178
|
+
gap: 8px;
|
|
1179
|
+
}
|
|
1180
|
+
.emb-status-banner .meta {
|
|
1181
|
+
color: var(--admin-text-dim);
|
|
1182
|
+
font-size: 12px;
|
|
1183
|
+
margin-top: 6px;
|
|
1184
|
+
font-family: var(--mcp-font-mono);
|
|
1185
|
+
word-break: break-all;
|
|
1186
|
+
}
|
|
1187
|
+
.emb-status-banner.state-ready { border-left-color: var(--admin-success); }
|
|
1188
|
+
.emb-status-banner.state-will-download { border-left-color: var(--admin-accent); }
|
|
1189
|
+
.emb-status-banner.state-no-embeddings { border-left-color: var(--admin-warn); }
|
|
1190
|
+
.emb-status-banner.state-missing,
|
|
1191
|
+
.emb-status-banner.state-disabled { border-left-color: var(--admin-danger); }
|
|
1162
1192
|
.emb-stat {
|
|
1163
1193
|
margin-bottom: 4px;
|
|
1164
1194
|
font-size: 13px;
|
|
@@ -1736,3 +1766,27 @@ a.mermaid-link { color: var(--admin-accent); }
|
|
|
1736
1766
|
#backup-warning-banner {
|
|
1737
1767
|
animation: rl-fade-in 0.3s ease-out;
|
|
1738
1768
|
}
|
|
1769
|
+
|
|
1770
|
+
|
|
1771
|
+
/* Events panel + nav bubble (added for issue #282 events buffer) */
|
|
1772
|
+
.nav-bubble { display:inline-block; min-width:18px; padding:0 6px; margin-left:6px; border-radius:9px; background:var(--admin-warn); color:var(--admin-white); font-size:11px; line-height:18px; text-align:center; vertical-align:middle; }
|
|
1773
|
+
.nav-bubble.has-error { background:var(--admin-danger-dark); }
|
|
1774
|
+
.events-table { width:100%; border-collapse:collapse; }
|
|
1775
|
+
.events-table th, .events-table td { padding:6px 8px; text-align:left; border-bottom:1px solid var(--admin-border); font-size:13px; vertical-align:top; }
|
|
1776
|
+
.events-table th { color:var(--admin-text-dim); font-weight:500; }
|
|
1777
|
+
.event-badge { display:inline-block; padding:1px 6px; border-radius:3px; font-size:11px; font-weight:600; }
|
|
1778
|
+
.event-badge.level-warn { background:var(--admin-warn-dark); color:var(--admin-drill-gold); }
|
|
1779
|
+
.event-badge.level-error { background:var(--admin-danger-darker); color:var(--admin-red-bright); }
|
|
1780
|
+
.event-row.level-error { background:rgba(220,38,38,0.06); }
|
|
1781
|
+
.event-row.level-warn { background:rgba(245,158,11,0.04); }
|
|
1782
|
+
.event-detail { font-family:var(--mcp-font-mono); font-size:11px; white-space:pre-wrap; margin-top:3px; }
|
|
1783
|
+
.event-ts { white-space:nowrap; color:var(--admin-text-dim); font-family:var(--mcp-font-mono); font-size:12px; }
|
|
1784
|
+
.event-row .event-msg { cursor: pointer; }
|
|
1785
|
+
.event-row .event-detail { display: none; max-height: 240px; overflow: auto; }
|
|
1786
|
+
.event-row.expanded .event-detail { display: block; }
|
|
1787
|
+
.event-row .toggle-caret { display:inline-block; width:14px; color:var(--admin-text-dim); transition: transform 0.15s; }
|
|
1788
|
+
.event-row.expanded .toggle-caret { transform: rotate(90deg); }
|
|
1789
|
+
.events-pager { display:flex; align-items:center; gap:12px; padding:8px 4px; }
|
|
1790
|
+
.events-pager.hidden { display:none; }
|
|
1791
|
+
.events-search { min-width: 180px; }
|
|
1792
|
+
.events-table tr.event-row mark { background: var(--admin-drill-gold); color: var(--admin-text); padding: 0 1px; border-radius: 2px; }
|
|
@@ -90,10 +90,8 @@
|
|
|
90
90
|
+ '<div class="form-group"><label class="form-label">Enable Mutation</label>'
|
|
91
91
|
+ '<select class="form-input" id="cfg-mutation"><option value="1"' + (cfg.serverSettings.enableMutation ? ' selected' : '') + '>Enabled</option>'
|
|
92
92
|
+ '<option value="0"' + (!cfg.serverSettings.enableMutation ? ' selected' : '') + '>Disabled</option></select></div>'
|
|
93
|
-
+ '<div class="form-group"><label class="form-label">Rate Limit
|
|
94
|
-
+ '<input class="form-input" type="number" id="cfg-
|
|
95
|
-
+ '<div class="form-group"><label class="form-label">Rate Limit Max Requests</label>'
|
|
96
|
-
+ '<input class="form-input" type="number" id="cfg-maxRequests" value="' + cfg.serverSettings.rateLimit.maxRequests + '" /></div>'
|
|
93
|
+
+ '<div class="form-group"><label class="form-label">Rate Limit (req/min, 0 = off)</label>'
|
|
94
|
+
+ '<input class="form-input" type="number" min="0" id="cfg-rateLimitPerMinute" value="' + (cfg.serverSettings.rateLimit && cfg.serverSettings.rateLimit.perMinute != null ? cfg.serverSettings.rateLimit.perMinute : 0) + '" /></div>'
|
|
97
95
|
+ '</div>'
|
|
98
96
|
+ '<div class="cfg-save-row"><button class="action-btn" type="submit">💾 Save Config</button></div>'
|
|
99
97
|
+ '</form>'
|
|
@@ -173,8 +171,7 @@
|
|
|
173
171
|
enableVerboseLogging: document.getElementById('cfg-verbose').value === '1',
|
|
174
172
|
enableMutation: document.getElementById('cfg-mutation').value === '1',
|
|
175
173
|
rateLimit: {
|
|
176
|
-
|
|
177
|
-
maxRequests: parseInt(document.getElementById('cfg-maxRequests').value)
|
|
174
|
+
perMinute: parseInt(document.getElementById('cfg-rateLimitPerMinute').value) || 0
|
|
178
175
|
}
|
|
179
176
|
},
|
|
180
177
|
featureFlags: featureFlags
|
|
@@ -378,8 +378,61 @@
|
|
|
378
378
|
var origShowSection = window.showSection;
|
|
379
379
|
window.showSection = function (name) {
|
|
380
380
|
if (origShowSection) origShowSection(name);
|
|
381
|
-
if (name === 'embeddings'
|
|
382
|
-
|
|
381
|
+
if (name === 'embeddings') {
|
|
382
|
+
window.loadEmbeddingsStatus();
|
|
383
|
+
if (!embData) setTimeout(init, 50);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
function escapeHtml(s) {
|
|
388
|
+
if (s == null) return '';
|
|
389
|
+
return String(s)
|
|
390
|
+
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
391
|
+
.replace(/"/g, '"').replace(/'/g, ''');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function renderStatusBanner(status) {
|
|
395
|
+
var banner = document.getElementById('emb-status-banner');
|
|
396
|
+
if (!banner) return;
|
|
397
|
+
banner.className = 'emb-status-banner';
|
|
398
|
+
if (!status || status.success === false) {
|
|
399
|
+
banner.classList.add('hidden');
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
var state = status.state || 'unknown';
|
|
403
|
+
var titleText = '', icon = '';
|
|
404
|
+
if (state === 'disabled') { icon = '🚫'; titleText = 'Semantic embeddings are disabled'; }
|
|
405
|
+
else if (state === 'missing') { icon = '⛔'; titleText = 'Model not available — compute will fail'; }
|
|
406
|
+
else if (state === 'will-download') { icon = '⬇️'; titleText = 'Model will download on first compute'; }
|
|
407
|
+
else if (state === 'no-embeddings') { icon = '⚠️'; titleText = 'No embeddings computed yet'; }
|
|
408
|
+
else if (state === 'ready') { icon = '✅'; titleText = 'Embeddings ready'; }
|
|
409
|
+
else { icon = 'ℹ️'; titleText = 'Embeddings status'; }
|
|
410
|
+
banner.classList.add('state-' + state);
|
|
411
|
+
var parts = [];
|
|
412
|
+
parts.push('<div class="title">' + icon + ' <span>' + escapeHtml(titleText) + '</span></div>');
|
|
413
|
+
if (status.message) parts.push('<div>' + escapeHtml(status.message) + '</div>');
|
|
414
|
+
var meta = [];
|
|
415
|
+
if (status.model) meta.push('model=' + status.model);
|
|
416
|
+
if (status.device) meta.push('device=' + status.device);
|
|
417
|
+
if (typeof status.localOnly === 'boolean') meta.push('localOnly=' + status.localOnly);
|
|
418
|
+
if (typeof status.modelCached === 'boolean') meta.push('modelCached=' + status.modelCached);
|
|
419
|
+
if (typeof status.embeddingsCount === 'number') meta.push('embeddings=' + status.embeddingsCount);
|
|
420
|
+
if (status.cacheDir) meta.push('cacheDir=' + status.cacheDir);
|
|
421
|
+
if (status.embeddingPath) meta.push('embeddingPath=' + status.embeddingPath);
|
|
422
|
+
if (meta.length) parts.push('<div class="meta">' + escapeHtml(meta.join(' · ')) + '</div>');
|
|
423
|
+
banner.innerHTML = parts.join('');
|
|
424
|
+
banner.classList.remove('hidden');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
window.loadEmbeddingsStatus = async function loadEmbeddingsStatus() {
|
|
428
|
+
try {
|
|
429
|
+
var res = await adminAuth.adminFetch('/api/embeddings/status');
|
|
430
|
+
if (!res.ok) { renderStatusBanner(null); return; }
|
|
431
|
+
var data = await res.json();
|
|
432
|
+
renderStatusBanner(data);
|
|
433
|
+
} catch (_err) {
|
|
434
|
+
void _err;
|
|
435
|
+
renderStatusBanner(null);
|
|
383
436
|
}
|
|
384
437
|
};
|
|
385
438
|
|
|
@@ -391,12 +444,18 @@
|
|
|
391
444
|
var res = await adminAuth.adminFetch('/api/embeddings/compute', { method: 'POST', headers: { 'Content-Type': 'application/json' } });
|
|
392
445
|
if (!res.ok) {
|
|
393
446
|
var err = await res.json().catch(function () { return {}; });
|
|
394
|
-
|
|
447
|
+
var detail = err.error || res.statusText;
|
|
448
|
+
if (err.hint) detail += ' — ' + err.hint;
|
|
449
|
+
else if (err.message) detail += ' — ' + err.message;
|
|
450
|
+
if (statusEl) statusEl.textContent = 'Error: ' + detail;
|
|
451
|
+
// Refresh banner so user sees the actionable state machine.
|
|
452
|
+
window.loadEmbeddingsStatus();
|
|
395
453
|
return;
|
|
396
454
|
}
|
|
397
455
|
var result = await res.json();
|
|
398
456
|
if (statusEl) statusEl.textContent = 'Computed ' + result.count + ' embeddings (' + result.model + ', ' + result.elapsedMs + 'ms). Loading visualization…';
|
|
399
|
-
// Auto-load the projection
|
|
457
|
+
// Auto-load the projection + refresh banner
|
|
458
|
+
window.loadEmbeddingsStatus();
|
|
400
459
|
await window.loadEmbeddings();
|
|
401
460
|
} catch (e) {
|
|
402
461
|
if (statusEl) statusEl.textContent = 'Compute failed: ' + e.message;
|