- Fix `import.meta.env.DEV` crash in graphSceneState.ts that broke the
entire test:graph-workspace suite (module load fails in Node.js/tsx)
- Export `resolveGroupedDisplayNodeId` from graphSceneState.ts and
remove the identical copy in GraphWorkspace.tsx
- Add `checkGroupedViewAvailability` helper (Louvain only, no centrality)
so grouped view availability can be checked cheaply on every graph change
- Gate full community graph build (`groupedDisplayCandidate`) on
`viewMode === 'grouped'` to avoid running Louvain + centrality on every
graph version tick when the user is not in grouped view
- Remove dead ternary in `focusNode` where both branches returned `nodeId`
- Add 7 new tests covering resolveGroupedDisplayNodeId,
resolveGroupedDisplayStateSnapshot, and checkGroupedViewAvailability
Co-Authored-By: ZohaibHassan16 <109234410+ZohaibHassan16@users.noreply.github.com>
Co-Authored-By: KaifAhmad1 <mohammadk78600@gmail.com>
Merge conflict resolution:
- Kept fix/graph-motion's conditional layout-stop (only in focused mode)
to preserve live layout motion for derived graphs — the core intent of
this PR.
Must-fix items resolved:
1. plugin.json — removed "hooks": "./hooks/hooks.json" (re-added by this
branch, already removed in PR #489 on main as it is auto-loaded).
Kept "agents": "./agents".
2. Double Louvain per render — added groupedViewAvailable useMemo in
GraphWorkspace (deps: [graphVersion]) that runs community detection
once. Passed result into resolveDisplayGraph and resolveDisplayStateSnapshot
via new groupedViewAvailable option; both functions skip their internal
computeGraphAnalyticsBase call when the value is pre-supplied.
3. graphVersion in displayState deps — removed graphVersion from the
displayState memo dep array. displayState now depends on the stable
boolean groupedViewAvailable, not on every ADD_NODE/ADD_EDGE tick,
so Louvain no longer re-fires on every WebSocket update.
4. hideLabelsOnMove / hideEdgesOnMove flipped to true — intentional:
suppressing labels and edges during pan reduces visual noise and is
part of the flicker-reduction fix described in the PR.
Co-authored-by: ZohaibHassan16 <zohaibhassan1696@gmail.com>
Co-authored-by: KaifAhmad1 <kaifahmad087@gmail.com>
1. Prevent active-but-disabled Focused button by only disabling when
viewMode is not already "focused" (viewMode !== "focused" && !canActivateFocusedMode).
2. Generalize inspector fallback copy — stale/invalid node IDs are not
necessarily grouped items, so remove the misleading "Activate Focused
mode" hint.
3. Move pluginRuntimeRef.current read out of render by converting
canActivateFocusedMode from useMemo to useState + useEffect, resolving
two ESLint "cannot access refs during render" errors and the missing
toolbar-memo dependency warning.
Co-authored-by: Sameer6305 <sskadam6305@gmail.com>
Co-authored-by: KaifAhmad1 <kaifahmad087@gmail.com>
Claude Code auto-loads hooks/hooks.json. Declaring it explicitly in
manifest.hooks causes: 'Duplicate hooks file detected ... already-loaded'.
Same pattern as agents: manifest should only reference *additional* hook
files beyond the default.
Two separate schema issues blocked `/plugin marketplace add ./plugins`
followed by `/plugin install semantica@semantica-local`:
1. `marketplace.json` was missing the required top-level `owner` object.
Claude Code rejects with: `owner: Invalid input: expected object,
received undefined`.
2. `plugin.json` declared `"agents": "./agents"` (string), but Claude
Code's manifest schema rejects non-array `agents` with:
`Validation errors: agents: Invalid input`. Auto-discovery from
the default `agents/` directory works when the field is omitted,
provided agents are flat `<name>.md` files with frontmatter (Claude
Code's subagent convention) rather than `<name>/AGENT.md`
subdirectories.
Changes:
- add `owner` object to `marketplace.json`
- drop `agents` field from `plugin.json` (falls back to auto-discovery)
- rename `agents/<name>/AGENT.md` -> `agents/<name>.md` (frontmatter
content is unchanged, just the path)
After this, the documented local-install flow succeeds end-to-end.
- Replace deepseek.Client with openai.OpenAI(base_url="https://api.deepseek.com/v1")
in DeepSeekProvider._init_client(); the deepseek PyPI package has no Client class
- Add self.base_url = "https://api.deepseek.com/v1" to DeepSeekProvider.__init__()
(missing from original PR; caused AttributeError on every instantiation)
- Fix verbose_mode NameError in BaseProvider.generate_typed() instructor path
- Update pyproject.toml: llm-deepseek extra now declares openai>=1.0.0
- Update _init_client warning message to reference openai library
- Add 19 tests in tests/semantic_extract/test_pr482_deepseek_openai.py
- Update CHANGELOG.md
Co-authored-by: liling <liling@users.noreply.github.com>
Co-authored-by: KaifAhmad1 <mohammadk78600@gmail.com>
- Replace list.sort() on every upsert with bisect.insort() — O(log n) per
insert instead of O(n log n); bulk rebuild still sorts once at the end
- Replace list.remove() in remove() with bisect.bisect_left + pop() — O(log n)
find instead of O(n) scan
- Wrap handle_graph_mutation() index mutations in self._lock — mutation bridge
fires from a background thread and was racing concurrent search/rebuild calls
- Drop source/target upserts in add_edge() — edges don't change node text so
the index documents are identical; removes unnecessary cache invalidation
- Sort tag values in _cache_key() — ["a","b"] and ["b","a"] now share a cache
entry since _passes_filters() uses set intersection (order-independent)
- Restore @app.get("/") root handler missing from this branch vs main
Co-authored-by: ZohaibHassan16 <zohaibhassan16@users.noreply.github.com>
Co-authored-by: KaifAhmad1 <mohammadk78600@gmail.com>
- Resolve all merge conflict markers in provenance.py, app.py, .gitignore
- Revert broken session.get_nodes()/get_edges() to session.graph.nodes/edges
- Keep undirected=True ego_graph fix for upstream ancestor traversal
- Add direction field to ProvenanceEdge (upstream/downstream/lateral)
- Group lineage edges in _render_markdown by direction section
- Move ProvenanceNode/ProvenanceEdge/ProvenanceResponse to schemas.py
- Restore complete router import set in app.py (sparql, vocabulary, etc.)
Co-authored-by: Sameer6305 <sameer6305@users.noreply.github.com>
Co-authored-by: KaifAhmad1 <mohammadk78600@gmail.com>
- Add _ttl_block() helper to accumulate all predicate-object pairs before
writing, producing a single valid Turtle subject block terminated by one
period — eliminates the bug where rdfs:subClassOf / domain / range were
appended after a closed '.' block
- Add missing data_properties loop to _export_owl_turtle so
owl:DatatypeProperty declarations are no longer silently dropped
- Add _escape_ttl_str() to escape quotes, backslashes, newlines, carriage
returns, and tabs inside Turtle string literals (rdfs:label, rdfs:comment,
owl:versionInfo)
- Unify optional-field null checks to consistent x = prop.get(); if x: pattern
- Add 43 tests in tests/export/test_owl_exporter.py covering syntax validity,
data properties, string escaping, null handling, and header output
- Update CHANGELOG.md with [Unreleased] entry
Closes#478
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extend PathResponse with hop_count (len(path)-1) and distance_band
("direct"|"near"|"mid-range"|"distant") as first-class API fields
- Add classify_path_distance() to semantica/utils/helpers.py as the
single source of truth for hop-count thresholds; both the route and
the visualizer import from it, eliminating duplicate threshold logic
- Populate hop_count and distance_band in find_path route via
classify_path_distance(); remove local _classify_distance() copy
- Add highlight_path: list[str] param to KGVisualizer.visualize_network;
path edges rendered as a distance-aware orange trace (opacity and
stroke width scale from direct→distant: 1.0/4px to 0.35/1.5px)
- Fix bidirectional edge lookup: only forward pairs (A→B) along the
path are added to path_edge_set; reverse back-edges in directed
graphs are no longer incorrectly highlighted
- Add logger.warning when highlight_path contains node IDs absent from
the layout position map, surfacing silent no-op mismatches
- Extend frontend PathResponse type in GraphInspectorPanel.tsx and
GraphWorkspaceShell.tsx with hop_count: number and distance_band
literal union to match the updated API contract
- Add 10 new tests: 2 API-level and 8 unit tests covering all four
band boundaries (0, 1, 2, 3, 4, 6, 7, 20 hops); 104 explorer tests
pass, 0 failures introduced
- Update CHANGELOG.md