* feat(web): add graph-load skip decision helper and node threshold (#2178)
* feat(web): skip graph download in connectToServer for chat-only mode (#2178)
* feat(web): add graphMode state and empty-graph chat-only handling (#2178)
* feat(web): read and thread ?skipGraph URL param through connect flow (#2178)
* feat(web): chat-only empty state with load-graph-anyway escape hatch (#2178)
* style(web): apply prettier formatting to graph-load files (#2178)
* fix(review): apply autofix feedback
- Fail-safe confirm + authoritative node count (P1: prevent re-triggering the hang via Load-graph-anyway when count unknown)
- In-flight guard on loadGraphAnyway (P1: double-fire)
- Honor explicit ?skipGraph in onAnalyzeComplete and DropZone (R6/U4)
- Extract buildGraphFromConnectResult shared helper (DRY across 3 connect sites)
- Add tests: switchRepo skip path, threshold config override, loadGraphAnyway error path, confirm fail-safe, in-flight guard
* fix(review): address tri-review findings
- P1 (correctness+adversarial+risk): stop the cross-repo / F5 chat-only leak.
loadGraphAnyway no longer persists ?skipGraph=0, and onAnalyzeComplete +
DropZone no longer inherit a stale ?skipGraph for a different repo — both
could bypass auto-detect and re-trigger the #2178 hang. ?skipGraph is now a
bookmark hint honored only by the initial auto-connect; in-session repo
changes auto-detect.
- P2 (performance): auto-detect now also skips on edge count (edge-driven
force-layout cliff), not just nodes; LARGE_GRAPH_EDGE_THRESHOLD default 50K.
- P2 (julik): reset graphMode/chatOnlyNodeCount at the top of switchRepo so a
failed switch can't leave a stale chat-only overlay.
- P2 (julik): set serverBaseUrl before awaiting handleServerConnect in
auto-connect so the Load-graph-anyway button isn't briefly a no-op.
- P2 (risk): hide the misleading '0 nodes / 0 edges' stats in chat-only mode
(Header + StatusBar).
- P2 (performance): guard the GraphCanvas layout effect against the empty
chat-only graph.
- Tests: edge-threshold decision + connectToServer edge-trigger; load-anyway
no longer asserts URL persistence.
* fix(web): make Load-graph-anyway cancellable, unmount-safe, fail-safe confirm (#2178)
- AbortController + mountedRef: cancel the in-flight download on unmount and
guard every post-await setState by the mounted ref (an abort surfaces as a
BackendError, not a DOMException AbortError, so name-checks would miss it)
- Stale-result guard: a load-anyway that resolves after a concurrent switchRepo
no longer clobbers the new repo's graph/mode/count
- GraphCanvas confirm fails SAFE (treat as declined) when window.confirm is
unavailable or throws, instead of silently proceeding into a large download
* fix(web): make the AI agent and chat surface aware of chat-only mode (#2178)
- buildDynamicSystemPrompt + createGraphRAGAgent take a chatOnly flag and append
a note (both prompt branches) that supersedes VISUAL GROUNDING: the graph isn't
loaded, [[Type:Name]] node citations won't highlight, prefer [[path:START-END]]
- initializeAgent resolves chatOnly = opts ?? graphModeRef.current==='chatOnly':
connect-flow callers (handleServerConnect, switchRepo, loadGraphAnyway re-init)
pass it explicitly; lazy/settings re-inits fall back to live mode via the ref
- loadGraphAnyway re-inits the agent (chatOnly:false) after a full load so the
prompt drops the note
- RightPanel shows a chat-only banner so the degradation is visible where AI
output renders (en + zh-CN)
* fix(web): streaming circuit breaker for graphs with missing size stats (#2178)
- GraphTooLargeError + a mid-stream breaker in parseNdjsonGraphResponse: count
nodes/relationships as they arrive and abort (cancel reader in try/finally,
then throw) the moment either crosses its limit — reusing the existing node/
edge thresholds, no new magic constant. Throwing right after the offending
push means a later error record in the same chunk can't pre-empt it.
- fetchGraph gains optional maxNodes/maxEdges (off by default → existing callers
unchanged). connectToServer arms them only for auto-detect downloads
(skipGraph !== false) and catches GraphTooLargeError → chat-only, re-throwing
every other error. This backstops the no-stats fail-open path that could
otherwise re-trigger the original hang.
* chore(autofix): apply prettier + eslint fixes via /autofix command
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>