interlinked-mapper 0.3.4__tar.gz → 0.3.6__tar.gz
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.
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/PKG-INFO +1 -1
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/analyzer/parser.py +15 -1
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/mcp_server.py +178 -49
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/PKG-INFO +1 -1
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/pyproject.toml +1 -1
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/__init__.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/analyzer/__init__.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/analyzer/dead_code.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/analyzer/embeddings.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/analyzer/graph.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/analyzer/similarity.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/cli.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/commander/__init__.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/commander/llm.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/commander/query.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/commander/repl.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/models.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/__init__.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/dist/assets/index-CyhrxsQU.css +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/dist/assets/index-Dh01aXoE.js +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/dist/index.html +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/index.html +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/index.html.d3-legacy +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/package-lock.json +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/package.json +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/App.tsx +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/graph/GraphCanvas.tsx +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/graph/nodePrograms.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/index.css +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/main.tsx +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/state/graphStore.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/state/sseClient.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/theme.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/types.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/vite-env.d.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/tsconfig.json +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/vite.config.ts +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/layouts.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/server.py +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/SOURCES.txt +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/dependency_links.txt +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/entry_points.txt +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/requires.txt +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/top_level.txt +0 -0
- {interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/setup.cfg +0 -0
|
@@ -187,7 +187,21 @@ def parse_project(root: str | Path) -> tuple[list[NodeData], list[EdgeData]]:
|
|
|
187
187
|
nodes: list[NodeData] = []
|
|
188
188
|
edges: list[EdgeData] = []
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
# Skip directories that contain third-party or non-project Python files.
|
|
191
|
+
# External references are resolved via import/AST analysis, not by parsing venv.
|
|
192
|
+
_SKIP_DIRS = frozenset({
|
|
193
|
+
".venv", "venv", "env", ".env",
|
|
194
|
+
"node_modules",
|
|
195
|
+
".git",
|
|
196
|
+
"__pycache__",
|
|
197
|
+
".tox", ".nox", ".eggs",
|
|
198
|
+
".mypy_cache", ".ruff_cache", ".pytest_cache",
|
|
199
|
+
"build", "dist", ".build",
|
|
200
|
+
})
|
|
201
|
+
py_files = sorted(
|
|
202
|
+
p for p in root.rglob("*.py")
|
|
203
|
+
if not any(part in _SKIP_DIRS for part in p.relative_to(root).parts)
|
|
204
|
+
)
|
|
191
205
|
|
|
192
206
|
# Pass 1: extract all symbols and raw (unresolved) edges
|
|
193
207
|
trees: list[tuple[ast.Module, str, str]] = []
|
|
@@ -41,47 +41,46 @@ from interlinked.analyzer.dead_code import detect_dead_code
|
|
|
41
41
|
from interlinked.commander.query import QueryEngine
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
def _deferred_background_work(graph: CodeGraph, engine: QueryEngine, project_path: str) -> None:
|
|
45
|
+
"""Run similarity + embeddings in a SINGLE background thread (non-blocking).
|
|
46
|
+
|
|
47
|
+
Mirrors the REST API pattern: never spawn competing CPU threads that
|
|
48
|
+
fight over the GIL with the main event loop. Everything heavy runs
|
|
49
|
+
sequentially in one thread.
|
|
50
|
+
"""
|
|
51
|
+
import threading
|
|
52
|
+
|
|
53
|
+
def _work():
|
|
54
|
+
# 1. Similarity fingerprinting (CPU-bound)
|
|
55
|
+
try:
|
|
56
|
+
from interlinked.analyzer.similarity import analyze_similarity
|
|
57
|
+
analyze_similarity(graph)
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
# 2. Embedding build (spawns its own single thread internally via build_async)
|
|
62
|
+
try:
|
|
63
|
+
from interlinked.visualizer.server import _start_embedding_build
|
|
64
|
+
_start_embedding_build(graph, project_path, engine)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
threading.Thread(target=_work, daemon=True, name="mcp-background").start()
|
|
69
|
+
|
|
70
|
+
|
|
44
71
|
def build_graph(project_path: str) -> tuple[CodeGraph, QueryEngine]:
|
|
45
|
-
"""Parse a project and build the graph + query engine.
|
|
72
|
+
"""Parse a project and build the graph + query engine.
|
|
73
|
+
|
|
74
|
+
Returns immediately after parsing + dead code detection.
|
|
75
|
+
Similarity and embeddings are NOT started here — they are deferred
|
|
76
|
+
to avoid GIL contention with the caller.
|
|
77
|
+
"""
|
|
46
78
|
nodes, edges = parse_project(project_path)
|
|
47
79
|
graph = CodeGraph()
|
|
48
80
|
graph.build_from(nodes, edges)
|
|
49
81
|
detect_dead_code(graph)
|
|
50
82
|
|
|
51
|
-
# Run similarity analysis if available
|
|
52
|
-
try:
|
|
53
|
-
from interlinked.analyzer.similarity import analyze_similarity
|
|
54
|
-
analyze_similarity(graph)
|
|
55
|
-
except Exception:
|
|
56
|
-
pass
|
|
57
|
-
|
|
58
83
|
engine = QueryEngine(graph)
|
|
59
|
-
|
|
60
|
-
# Start embedding build in background (if torch/transformers installed)
|
|
61
|
-
try:
|
|
62
|
-
from interlinked.analyzer.embeddings import EmbeddingIndex, is_available
|
|
63
|
-
if is_available():
|
|
64
|
-
from pathlib import Path
|
|
65
|
-
emb_index = EmbeddingIndex(project_path)
|
|
66
|
-
engine._embedding_index = emb_index
|
|
67
|
-
# Collect function sources
|
|
68
|
-
from interlinked.models import SymbolType
|
|
69
|
-
functions = []
|
|
70
|
-
for node in graph.all_nodes(include_proposed=False):
|
|
71
|
-
if node.symbol_type not in (SymbolType.FUNCTION, SymbolType.METHOD):
|
|
72
|
-
continue
|
|
73
|
-
if node.file_path and node.line_start and node.line_end:
|
|
74
|
-
try:
|
|
75
|
-
lines = Path(node.file_path).read_text(encoding="utf-8", errors="replace").splitlines()
|
|
76
|
-
source = "\n".join(lines[max(0, node.line_start - 1):min(len(lines), node.line_end)])
|
|
77
|
-
if source:
|
|
78
|
-
functions.append({"id": node.id, "source": source})
|
|
79
|
-
except Exception:
|
|
80
|
-
pass
|
|
81
|
-
emb_index.build_async(functions)
|
|
82
|
-
except Exception:
|
|
83
|
-
pass
|
|
84
|
-
|
|
85
84
|
return graph, engine
|
|
86
85
|
|
|
87
86
|
|
|
@@ -95,24 +94,30 @@ def create_mcp_server(project_path: str) -> Server:
|
|
|
95
94
|
# Lazy state — built on first tool call (only if no web server is running)
|
|
96
95
|
_state: dict[str, Any] = {"graph": None, "engine": None, "ready": False}
|
|
97
96
|
|
|
98
|
-
def _check_server(port: int = 8420) -> str | None:
|
|
97
|
+
async def _check_server(port: int = 8420) -> str | None:
|
|
99
98
|
"""Check if the web visualizer is running right now. Returns base URL or None."""
|
|
100
99
|
url = f"http://127.0.0.1:{port}"
|
|
101
100
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
async with httpx.AsyncClient() as client:
|
|
102
|
+
r = await client.get(f"{url}/api/stats", timeout=1.0)
|
|
103
|
+
if r.status_code == 200:
|
|
104
|
+
return url
|
|
105
105
|
except Exception:
|
|
106
106
|
pass
|
|
107
107
|
return None
|
|
108
108
|
|
|
109
|
-
def _ensure_ready() -> tuple[CodeGraph, QueryEngine]:
|
|
109
|
+
async def _ensure_ready() -> tuple[CodeGraph, QueryEngine]:
|
|
110
110
|
if not _state["ready"]:
|
|
111
|
+
import asyncio
|
|
111
112
|
print(f"Analyzing {project_path} ...", file=sys.stderr)
|
|
112
|
-
|
|
113
|
+
loop = asyncio.get_running_loop()
|
|
114
|
+
graph, engine = await loop.run_in_executor(None, build_graph, project_path)
|
|
113
115
|
_state["graph"] = graph
|
|
114
116
|
_state["engine"] = engine
|
|
115
117
|
_state["ready"] = True
|
|
118
|
+
# Deferred: similarity + embeddings in single background thread
|
|
119
|
+
# Scheduled AFTER build returns so the tool response goes out first
|
|
120
|
+
_deferred_background_work(graph, engine, project_path)
|
|
116
121
|
return _state["graph"], _state["engine"]
|
|
117
122
|
|
|
118
123
|
# Pick up API key from env if available
|
|
@@ -341,7 +346,7 @@ def create_mcp_server(project_path: str) -> Server:
|
|
|
341
346
|
try:
|
|
342
347
|
# Handle ui_status first — it doesn't need graph or server proxy
|
|
343
348
|
if name == "interlinked_ui_status":
|
|
344
|
-
server_url = _check_server()
|
|
349
|
+
server_url = await _check_server()
|
|
345
350
|
if server_url:
|
|
346
351
|
result = json.dumps({
|
|
347
352
|
"running": True,
|
|
@@ -358,20 +363,49 @@ def create_mcp_server(project_path: str) -> Server:
|
|
|
358
363
|
|
|
359
364
|
# Handle start_ui — needs to spawn the server process
|
|
360
365
|
if name == "interlinked_start_ui":
|
|
366
|
+
import asyncio
|
|
361
367
|
port = arguments.get("port", 8420)
|
|
362
|
-
|
|
368
|
+
loop = asyncio.get_running_loop()
|
|
369
|
+
result = await loop.run_in_executor(None, _start_ui, project_path, port)
|
|
363
370
|
return [TextContent(type="text", text=result)]
|
|
364
371
|
|
|
365
372
|
# Try proxying through the running web server first
|
|
366
|
-
server_url = _check_server()
|
|
373
|
+
server_url = await _check_server()
|
|
367
374
|
if server_url:
|
|
368
|
-
result =
|
|
375
|
+
result = await _async_dispatch_via_server(name, arguments, server_url)
|
|
369
376
|
if result is not None:
|
|
370
377
|
return [TextContent(type="text", text=str(result))]
|
|
371
378
|
|
|
372
|
-
#
|
|
373
|
-
|
|
374
|
-
|
|
379
|
+
# switch_project: skip _ensure_ready (would double-parse), rebuild directly
|
|
380
|
+
import asyncio
|
|
381
|
+
loop = asyncio.get_running_loop()
|
|
382
|
+
|
|
383
|
+
if name == "interlinked_switch_project":
|
|
384
|
+
from interlinked.visualizer.server import _rebuild_graph
|
|
385
|
+
|
|
386
|
+
def _do_switch():
|
|
387
|
+
g = _state.get("graph")
|
|
388
|
+
if g is None:
|
|
389
|
+
g = CodeGraph()
|
|
390
|
+
return _rebuild_graph(arguments["path"], g, run_similarity=False), g
|
|
391
|
+
|
|
392
|
+
result_dict, graph = await loop.run_in_executor(None, _do_switch)
|
|
393
|
+
engine = _state.get("engine")
|
|
394
|
+
if engine is None:
|
|
395
|
+
engine = QueryEngine(graph)
|
|
396
|
+
engine.reset_filter()
|
|
397
|
+
_state["graph"] = graph
|
|
398
|
+
_state["engine"] = engine
|
|
399
|
+
_state["ready"] = True
|
|
400
|
+
# Deferred: single background thread AFTER response sent
|
|
401
|
+
_deferred_background_work(graph, engine, arguments["path"])
|
|
402
|
+
return [TextContent(type="text", text=json.dumps(result_dict, indent=2))]
|
|
403
|
+
|
|
404
|
+
# All other tools: ensure graph is built first
|
|
405
|
+
graph, engine = await _ensure_ready()
|
|
406
|
+
result = await loop.run_in_executor(
|
|
407
|
+
None, _dispatch_tool, name, arguments, engine, graph, api_key
|
|
408
|
+
)
|
|
375
409
|
if name == "interlinked_set_api_key":
|
|
376
410
|
api_key = arguments.get("api_key", "")
|
|
377
411
|
os.environ["ANTHROPIC_API_KEY"] = api_key
|
|
@@ -520,7 +554,8 @@ def _dispatch_via_server(name: str, args: dict[str, Any], server_url: str) -> st
|
|
|
520
554
|
if method == "GET":
|
|
521
555
|
r = httpx.get(url, timeout=30.0)
|
|
522
556
|
else:
|
|
523
|
-
|
|
557
|
+
timeout = 120.0 if "switch_project" in path else 30.0
|
|
558
|
+
r = httpx.post(url, json=body, timeout=timeout)
|
|
524
559
|
data = r.json()
|
|
525
560
|
|
|
526
561
|
# Extract the most useful part of the response for the LLM
|
|
@@ -542,6 +577,97 @@ def _dispatch_via_server(name: str, args: dict[str, Any], server_url: str) -> st
|
|
|
542
577
|
return None
|
|
543
578
|
|
|
544
579
|
|
|
580
|
+
async def _async_dispatch_via_server(name: str, args: dict[str, Any], server_url: str) -> str | None:
|
|
581
|
+
"""Async proxy — uses httpx.AsyncClient so the MCP event loop isn't blocked."""
|
|
582
|
+
# Reuse the same endpoint mapping
|
|
583
|
+
_TOOL_TO_ENDPOINT: dict[str, tuple[str, str, dict]] = {
|
|
584
|
+
"interlinked_stats": ("GET", "/api/stats", {}),
|
|
585
|
+
"interlinked_isolate": ("POST", "/api/isolate", {
|
|
586
|
+
"target": args.get("target", ""),
|
|
587
|
+
"level": args.get("level", "function"),
|
|
588
|
+
"depth": args.get("depth", 3),
|
|
589
|
+
"edge_types": args.get("edge_types"),
|
|
590
|
+
}),
|
|
591
|
+
"interlinked_zoom": ("POST", "/api/zoom", {"level": args.get("level", "module")}),
|
|
592
|
+
"interlinked_focus": ("POST", "/api/focus", {
|
|
593
|
+
"node_id": args.get("node_id", ""),
|
|
594
|
+
"depth": args.get("depth", 2),
|
|
595
|
+
}),
|
|
596
|
+
"interlinked_query": ("POST", "/api/query", {"expression": args.get("expression", "")}),
|
|
597
|
+
"interlinked_trace_variable": ("POST", "/api/trace_variable", {
|
|
598
|
+
"variable": args.get("variable", ""),
|
|
599
|
+
"origin": args.get("origin"),
|
|
600
|
+
}),
|
|
601
|
+
"interlinked_propose_function": ("POST", "/api/propose", {
|
|
602
|
+
"name": args.get("name", ""),
|
|
603
|
+
"module": args.get("module", ""),
|
|
604
|
+
"calls": args.get("calls"),
|
|
605
|
+
"called_by": args.get("called_by"),
|
|
606
|
+
}),
|
|
607
|
+
"interlinked_find_duplicates": ("POST", "/api/find_duplicates", {
|
|
608
|
+
"threshold": args.get("threshold", 0.6),
|
|
609
|
+
"scope": args.get("scope"),
|
|
610
|
+
"kind": args.get("kind"),
|
|
611
|
+
}),
|
|
612
|
+
"interlinked_similar_to": ("POST", "/api/similar_to", {
|
|
613
|
+
"target": args.get("target", ""),
|
|
614
|
+
"threshold": args.get("threshold", 0.5),
|
|
615
|
+
}),
|
|
616
|
+
"interlinked_get_context": ("POST", "/api/get_context", {"target": args.get("target", "")}),
|
|
617
|
+
"interlinked_command": ("POST", "/api/command", {"command": args.get("command", "")}),
|
|
618
|
+
"interlinked_switch_project": ("POST", "/api/switch_project", {"path": args.get("path", "")}),
|
|
619
|
+
"interlinked_edges_between": ("POST", "/api/edges_between", {
|
|
620
|
+
"source_scope": args.get("source_scope", ""),
|
|
621
|
+
"target_scope": args.get("target_scope"),
|
|
622
|
+
"edge_types": args.get("edge_types"),
|
|
623
|
+
}),
|
|
624
|
+
"interlinked_reachable": ("POST", "/api/reachable", {
|
|
625
|
+
"source": args.get("source", ""),
|
|
626
|
+
"target": args.get("target", ""),
|
|
627
|
+
"edge_types": args.get("edge_types"),
|
|
628
|
+
"max_depth": args.get("max_depth", 20),
|
|
629
|
+
}),
|
|
630
|
+
"interlinked_reset": ("POST", "/api/reset", {}),
|
|
631
|
+
"interlinked_set_context": ("POST", "/api/set_context", {
|
|
632
|
+
"what": args.get("what", ""),
|
|
633
|
+
"why": args.get("why", ""),
|
|
634
|
+
"where": args.get("where", ""),
|
|
635
|
+
}),
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if name not in _TOOL_TO_ENDPOINT:
|
|
639
|
+
return None
|
|
640
|
+
|
|
641
|
+
method, path, body = _TOOL_TO_ENDPOINT[name]
|
|
642
|
+
url = f"{server_url}{path}"
|
|
643
|
+
|
|
644
|
+
try:
|
|
645
|
+
async with httpx.AsyncClient() as client:
|
|
646
|
+
timeout = 120.0 if "switch_project" in path else 30.0
|
|
647
|
+
if method == "GET":
|
|
648
|
+
r = await client.get(url, timeout=timeout)
|
|
649
|
+
else:
|
|
650
|
+
r = await client.post(url, json=body, timeout=timeout)
|
|
651
|
+
data = r.json()
|
|
652
|
+
|
|
653
|
+
if "result" in data:
|
|
654
|
+
result = data["result"]
|
|
655
|
+
if isinstance(result, (dict, list)):
|
|
656
|
+
return json.dumps(result, indent=2)
|
|
657
|
+
return str(result)
|
|
658
|
+
if "results" in data:
|
|
659
|
+
results = data["results"]
|
|
660
|
+
if len(results) > 20:
|
|
661
|
+
return f"Found {len(results)} results. Showing first 20:\n" + json.dumps(results[:20], indent=2)
|
|
662
|
+
return json.dumps(results, indent=2)
|
|
663
|
+
if "error" in data:
|
|
664
|
+
return f"Error: {data['error']}"
|
|
665
|
+
return json.dumps(data, indent=2)
|
|
666
|
+
except Exception as e:
|
|
667
|
+
print(f"Async server proxy failed for {name}: {e}", file=sys.stderr)
|
|
668
|
+
return None
|
|
669
|
+
|
|
670
|
+
|
|
545
671
|
def _dispatch_tool(
|
|
546
672
|
name: str, args: dict[str, Any],
|
|
547
673
|
engine: QueryEngine, graph: CodeGraph, api_key: str,
|
|
@@ -621,8 +747,11 @@ def _dispatch_tool(
|
|
|
621
747
|
|
|
622
748
|
elif name == "interlinked_switch_project":
|
|
623
749
|
from interlinked.visualizer.server import _rebuild_graph
|
|
624
|
-
result = _rebuild_graph(args["path"], graph)
|
|
750
|
+
result = _rebuild_graph(args["path"], graph, run_similarity=False)
|
|
625
751
|
engine.reset_filter()
|
|
752
|
+
# Deferred: similarity + embeddings in a single background thread
|
|
753
|
+
# (matches REST API: never run competing CPU threads)
|
|
754
|
+
_deferred_background_work(graph, engine, args["path"])
|
|
626
755
|
return json.dumps(result, indent=2)
|
|
627
756
|
|
|
628
757
|
elif name == "interlinked_edges_between":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/index.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/package.json
RENAMED
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/App.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/index.css
RENAMED
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/main.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/theme.ts
RENAMED
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/src/types.ts
RENAMED
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/tsconfig.json
RENAMED
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked/visualizer/frontend/vite.config.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/requires.txt
RENAMED
|
File without changes
|
{interlinked_mapper-0.3.4 → interlinked_mapper-0.3.6}/interlinked_mapper.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|