Skip to content

Commit bee202e

Browse files
committed
fix(ui): handle indexing errors in frontend and enable dev mode API hosting
- Fixed frontend to render an error banner instead of silently dismissing when a job fails or OOMs (status === 'error'). - Allowed the backend HTTP server to start API endpoints in development even if no frontend files are embedded. Signed-off-by: sahil-mangla <manglasahil2017@gmail.com>
1 parent 1519f86 commit bee202e

3 files changed

Lines changed: 53 additions & 12 deletions

File tree

graph-ui/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

graph-ui/src/components/StatsTab.tsx

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,19 +274,35 @@ function CreateIndexModal({ onClose, onCreated }: { onClose: () => void; onCreat
274274
/* ── Index Progress ─────────────────────────────────────── */
275275

276276
function IndexProgress({ onDone }: { onDone: () => void }) {
277-
const [jobs, setJobs] = useState<{ slot: number; status: string; path: string }[]>([]);
277+
const [jobs, setJobs] = useState<{ slot: number; status: string; path: string; error?: string }[]>([]);
278+
const [hasActive, setHasActive] = useState(true);
279+
278280
useEffect(() => {
281+
if (!hasActive) return;
279282
const poll = setInterval(async () => {
280283
try {
281284
const data = await (await fetch("/api/index-status")).json();
282285
setJobs(data);
283-
if (data.length > 0 && data.every((j: { status: string }) => j.status !== "indexing")) onDone();
284-
} catch { /* */ }
286+
const stillIndexing = data.some((j: { status: string }) => j.status === "indexing");
287+
if (!stillIndexing) {
288+
setHasActive(false);
289+
const hasErrors = data.some((j: { status: string }) => j.status === "error");
290+
if (!hasErrors) {
291+
onDone();
292+
}
293+
}
294+
} catch (error) {
295+
console.error("[IndexProgress] Poll failed:", error);
296+
}
285297
}, 2000);
286298
return () => clearInterval(poll);
287-
}, [onDone]);
299+
}, [onDone, hasActive]);
300+
288301
const active = jobs.filter((j) => j.status === "indexing");
289-
if (active.length === 0) return null;
302+
const errors = jobs.filter((j) => j.status === "error");
303+
304+
if (active.length === 0 && errors.length === 0) return null;
305+
290306
return (
291307
<div className="rounded-xl border border-primary/20 bg-primary/5 p-4 mb-6">
292308
{active.map((j) => (
@@ -298,6 +314,26 @@ function IndexProgress({ onDone }: { onDone: () => void }) {
298314
</div>
299315
</div>
300316
))}
317+
{errors.map((j) => (
318+
<div key={j.slot} className="flex items-start gap-3 mt-3 first:mt-0 p-3 rounded-lg border border-destructive/20 bg-destructive/5 text-destructive">
319+
<span className="text-[14px]">⚠️</span>
320+
<div className="flex-1 min-w-0">
321+
<p className="text-[12px] font-semibold">Indexing Failed</p>
322+
<p className="text-[11px] font-mono truncate">{j.path}</p>
323+
{j.error && <p className="text-[10px] opacity-75 mt-1 font-mono">{j.error}</p>}
324+
</div>
325+
</div>
326+
))}
327+
{errors.length > 0 && (
328+
<div className="flex justify-end mt-3">
329+
<button
330+
onClick={onDone}
331+
className="px-3 py-1 rounded bg-destructive/10 hover:bg-destructive/20 text-destructive text-[11px] font-medium transition-all"
332+
>
333+
Dismiss
334+
</button>
335+
</div>
336+
)}
301337
</div>
302338
);
303339
}

src/main.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,11 @@ int main(int argc, char **argv) {
447447
* and which build to use (#350). */
448448
if (explicit_ui_enable && CBM_EMBEDDED_FILE_COUNT == 0) {
449449
(void)fprintf(stderr,
450-
"codebase-memory-mcp: --ui requested, but this binary was built without the "
451-
"embedded UI, so the HTTP server will not start.\n"
452-
"Use the UI release asset (codebase-memory-mcp-ui) or rebuild with: "
453-
"make -f Makefile.cbm cbm-with-ui\n");
450+
"codebase-memory-mcp: Running with --ui=true but "
451+
"without embedded assets. "
452+
"API endpoints will be active on port %d "
453+
"(useful for proxying from frontend dev server).\n",
454+
ui_cfg.ui_port);
454455
}
455456

456457
setup_signal_handlers();
@@ -501,15 +502,13 @@ int main(int argc, char **argv) {
501502
cbm_thread_t http_tid;
502503
bool http_started = false;
503504

504-
if (ui_cfg.ui_enabled && CBM_EMBEDDED_FILE_COUNT > 0) {
505+
if (ui_cfg.ui_enabled) {
505506
g_http_server = cbm_http_server_new(ui_cfg.ui_port);
506507
if (g_http_server) {
507508
if (cbm_thread_create(&http_tid, 0, http_thread, g_http_server) == 0) {
508509
http_started = true;
509510
}
510511
}
511-
} else if (ui_cfg.ui_enabled && CBM_EMBEDDED_FILE_COUNT == 0) {
512-
cbm_log_warn("ui.no_assets", "hint", "rebuild with: make -f Makefile.cbm cbm-with-ui");
513512
}
514513

515514
/* Run MCP event loop (blocks until EOF or signal) */

0 commit comments

Comments
 (0)