tscode-kg 0.5.0__tar.gz → 0.5.1__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.
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/PKG-INFO +5 -5
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/README.md +3 -3
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/pyproject.toml +3 -3
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/__init__.py +1 -1
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/analysis.py +94 -2
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/LICENSE +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/__main__.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/app.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/bridge.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/centrality.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/__init__.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_analyze.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_bridges.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_build.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_centrality.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_explain.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_framework_nodes.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_hooks.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_init.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_mcp.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_model.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_query.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_snapshot.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_viz.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/main.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/coderank.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/config.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/explain.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/extractor.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/framework_detector.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/kg.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/layout3d.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/mcp_server.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/snapshots.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/viz3d.py +0 -0
- {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/viz3d_timeline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tscode-kg
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Knowledge graph for TypeScript/JavaScript codebases — AST extraction, hybrid semantic+structural search
|
|
5
5
|
License-Expression: Elastic-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -19,7 +19,7 @@ Provides-Extra: viz
|
|
|
19
19
|
Provides-Extra: viz3d
|
|
20
20
|
Requires-Dist: PyQt5 (>=5.15.11,<5.16) ; extra == "viz3d"
|
|
21
21
|
Requires-Dist: click (>=8.1.0,<9)
|
|
22
|
-
Requires-Dist: kgmodule-utils[semantic,sqlite-vec] (>=0.
|
|
22
|
+
Requires-Dist: kgmodule-utils[semantic,sqlite-vec] (>=0.22.0)
|
|
23
23
|
Requires-Dist: markdown (>=3.10,<3.11) ; extra == "viz3d"
|
|
24
24
|
Requires-Dist: mcp (>=1.0.0,<2)
|
|
25
25
|
Requires-Dist: networkx (>=3.0)
|
|
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
[](https://www.python.org/)
|
|
43
43
|
[](https://www.elastic.co/licensing/elastic-license)
|
|
44
44
|
[](https://pypi.org/project/tscode-kg/)
|
|
45
|
-
[](https://github.com/Flux-Frontiers/tscode_kg/releases)
|
|
46
46
|
[](https://github.com/Flux-Frontiers/tscode_kg/actions/workflows/ci.yml)
|
|
47
47
|
[](https://python-poetry.org/)
|
|
48
48
|
[](https://doi.org/10.5281/zenodo.22559450)
|
|
@@ -195,13 +195,13 @@ If you use TypeScriptKG in your research or project, please cite it:
|
|
|
195
195
|
|
|
196
196
|
[](https://doi.org/10.5281/zenodo.22559450)
|
|
197
197
|
|
|
198
|
-
> Suchanek, E. G. (2026). *TypeScriptKG: Semantic Knowledge Graph for TypeScript/JavaScript Codebases* (Version 0.5.
|
|
198
|
+
> Suchanek, E. G. (2026). *TypeScriptKG: Semantic Knowledge Graph for TypeScript/JavaScript Codebases* (Version 0.5.1) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.22559450
|
|
199
199
|
|
|
200
200
|
```bibtex
|
|
201
201
|
@software{suchanek_tscode_kg,
|
|
202
202
|
author = {Suchanek, Eric G.},
|
|
203
203
|
title = {{TypeScriptKG}: Semantic Knowledge Graph for TypeScript/JavaScript Codebases},
|
|
204
|
-
version = {0.5.
|
|
204
|
+
version = {0.5.1},
|
|
205
205
|
year = {2026},
|
|
206
206
|
publisher = {Flux-Frontiers},
|
|
207
207
|
doi = {10.5281/zenodo.22559450},
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.python.org/)
|
|
4
4
|
[](https://www.elastic.co/licensing/elastic-license)
|
|
5
5
|
[](https://pypi.org/project/tscode-kg/)
|
|
6
|
-
[](https://github.com/Flux-Frontiers/tscode_kg/releases)
|
|
7
7
|
[](https://github.com/Flux-Frontiers/tscode_kg/actions/workflows/ci.yml)
|
|
8
8
|
[](https://python-poetry.org/)
|
|
9
9
|
[](https://doi.org/10.5281/zenodo.22559450)
|
|
@@ -156,13 +156,13 @@ If you use TypeScriptKG in your research or project, please cite it:
|
|
|
156
156
|
|
|
157
157
|
[](https://doi.org/10.5281/zenodo.22559450)
|
|
158
158
|
|
|
159
|
-
> Suchanek, E. G. (2026). *TypeScriptKG: Semantic Knowledge Graph for TypeScript/JavaScript Codebases* (Version 0.5.
|
|
159
|
+
> Suchanek, E. G. (2026). *TypeScriptKG: Semantic Knowledge Graph for TypeScript/JavaScript Codebases* (Version 0.5.1) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.22559450
|
|
160
160
|
|
|
161
161
|
```bibtex
|
|
162
162
|
@software{suchanek_tscode_kg,
|
|
163
163
|
author = {Suchanek, Eric G.},
|
|
164
164
|
title = {{TypeScriptKG}: Semantic Knowledge Graph for TypeScript/JavaScript Codebases},
|
|
165
|
-
version = {0.5.
|
|
165
|
+
version = {0.5.1},
|
|
166
166
|
year = {2026},
|
|
167
167
|
publisher = {Flux-Frontiers},
|
|
168
168
|
doi = {10.5281/zenodo.22559450},
|
|
@@ -38,7 +38,7 @@ packages = [{ include = "tscode_kg", from = "src" }]
|
|
|
38
38
|
|
|
39
39
|
[project]
|
|
40
40
|
name = "tscode-kg"
|
|
41
|
-
version = "0.5.
|
|
41
|
+
version = "0.5.1"
|
|
42
42
|
description = "Knowledge graph for TypeScript/JavaScript codebases — AST extraction, hybrid semantic+structural search"
|
|
43
43
|
readme = "README.md"
|
|
44
44
|
license = "Elastic-2.0"
|
|
@@ -68,7 +68,7 @@ dependencies = [
|
|
|
68
68
|
# manager is now the package_name class attribute, where it used to be an
|
|
69
69
|
# __init__ that only forwarded to super(). Against 0.19.x the manager
|
|
70
70
|
# reports itself as "kg-utils" in every snapshot's tool field.
|
|
71
|
-
"kgmodule-utils[semantic,sqlite-vec]>=0.
|
|
71
|
+
"kgmodule-utils[semantic,sqlite-vec]>=0.22.0",
|
|
72
72
|
"click>=8.1.0,<9",
|
|
73
73
|
# Upper-bounded: mcp 2.0 removed the bundled `mcp.server.fastmcp` module
|
|
74
74
|
# (FastMCP was split out into the standalone `fastmcp` package) and rebuilt
|
|
@@ -159,7 +159,7 @@ optional = true
|
|
|
159
159
|
# or pycodekg predating the shared extension points into the same environment
|
|
160
160
|
# as a tscode_kg that depends on them.
|
|
161
161
|
doc-kg = ">=0.26.0"
|
|
162
|
-
pycode-kg = ">=0.27.
|
|
162
|
+
pycode-kg = ">=0.27.1"
|
|
163
163
|
|
|
164
164
|
[project.urls]
|
|
165
165
|
Homepage = "https://github.com/Flux-Frontiers/tscode_kg"
|
|
@@ -166,17 +166,60 @@ class TSCodeKGAnalyzer:
|
|
|
166
166
|
self.coderank_top_nodes: list[dict] = []
|
|
167
167
|
self.concern_analysis: list[dict] = []
|
|
168
168
|
self._phase_result: str = ""
|
|
169
|
+
#: Phases that could not run, with the reason. Rendered in the report
|
|
170
|
+
#: so a degraded run says what is missing rather than omitting it.
|
|
171
|
+
self.phase_failures: list[dict] = []
|
|
169
172
|
|
|
170
173
|
# ------------------------------------------------------------------
|
|
171
174
|
# Phase runner
|
|
172
175
|
# ------------------------------------------------------------------
|
|
173
176
|
|
|
177
|
+
def _take_phase_result(self) -> str:
|
|
178
|
+
"""Read and clear the one-line summary the phase just set.
|
|
179
|
+
|
|
180
|
+
Phases report through ``self._phase_result`` rather than a return
|
|
181
|
+
value, because they are called as bare ``Callable[[], None]``. Reading
|
|
182
|
+
it here rather than inline in :meth:`_run_phase` also keeps the read
|
|
183
|
+
away from that method's own ``= ""`` assignment, which a type checker
|
|
184
|
+
otherwise narrows to a literal it can never see ``fn()`` change.
|
|
185
|
+
"""
|
|
186
|
+
result = self._phase_result
|
|
187
|
+
self._phase_result = ""
|
|
188
|
+
return f" {result}" if result else ""
|
|
189
|
+
|
|
174
190
|
def _run_phase(self, num: int, name: str, fn: Callable[[], None]) -> None:
|
|
191
|
+
"""Run one analysis phase, reporting rather than propagating a failure.
|
|
192
|
+
|
|
193
|
+
A phase that cannot run must not take the other thirteen and the report
|
|
194
|
+
with it. The individual phases already guard the errors they expect
|
|
195
|
+
(``AttributeError``, ``ValueError``, ``RuntimeError``), but the ones
|
|
196
|
+
worth surviving are the ones nobody predicted -- the concrete case
|
|
197
|
+
being ``sqlite3.OperationalError: no such table: vec_nodes`` after
|
|
198
|
+
``tscodekg build-sqlite``, a supported command that deliberately builds
|
|
199
|
+
the graph without the vector index. Only phase 4 seeds on a semantic
|
|
200
|
+
query; the other thirteen are pure SQL and have everything they need.
|
|
201
|
+
Aborting the run gave the user no report at all, and an error naming
|
|
202
|
+
an internal table rather than the missing step.
|
|
203
|
+
|
|
204
|
+
The failure is recorded in :attr:`phase_failures` and rendered in the
|
|
205
|
+
report, so a degraded run says which sections are missing and why
|
|
206
|
+
instead of quietly omitting them.
|
|
207
|
+
"""
|
|
175
208
|
self._phase_result = ""
|
|
176
209
|
t0 = time.monotonic()
|
|
177
|
-
|
|
210
|
+
try:
|
|
211
|
+
fn()
|
|
212
|
+
except Exception as exc: # noqa: BLE001 -- see docstring
|
|
213
|
+
elapsed = time.monotonic() - t0
|
|
214
|
+
self.phase_failures.append({"phase": num, "name": name, "error": str(exc)})
|
|
215
|
+
logger.warning("Phase %d (%s) failed: %s", num, name, exc)
|
|
216
|
+
self.console.print(
|
|
217
|
+
f" [cyan]▶ Phase {num:2d}/{self._TOTAL_PHASES}:[/cyan]"
|
|
218
|
+
f" {name} [yellow]skipped: {exc}[/yellow] [green]({elapsed:.1f}s)[/green]"
|
|
219
|
+
)
|
|
220
|
+
return
|
|
178
221
|
elapsed = time.monotonic() - t0
|
|
179
|
-
result =
|
|
222
|
+
result = self._take_phase_result()
|
|
180
223
|
self.console.print(
|
|
181
224
|
f" [cyan]▶ Phase {num:2d}/{self._TOTAL_PHASES}:[/cyan]"
|
|
182
225
|
f" {name}{result} [green]({elapsed:.1f}s)[/green]"
|
|
@@ -1404,6 +1447,10 @@ Most-called functions and methods — potential bottlenecks or core APIs.
|
|
|
1404
1447
|
"""
|
|
1405
1448
|
)
|
|
1406
1449
|
|
|
1450
|
+
degraded = self._render_phase_failures()
|
|
1451
|
+
if degraded:
|
|
1452
|
+
report += "\n---\n\n" + degraded + "\n---\n"
|
|
1453
|
+
|
|
1407
1454
|
for i, metrics in enumerate(
|
|
1408
1455
|
sorted(self.function_metrics.values(), key=lambda m: m.fan_in, reverse=True)[:15], 1
|
|
1409
1456
|
):
|
|
@@ -1641,6 +1688,42 @@ Cohesion = incoming-callers / (incoming + outgoing + 1). Higher = more internall
|
|
|
1641
1688
|
Path(report_path).write_text(report, encoding="utf-8")
|
|
1642
1689
|
self.console.print(f"[green]✓[/green] Report written to {report_path}")
|
|
1643
1690
|
|
|
1691
|
+
def _render_phase_failures(self) -> str:
|
|
1692
|
+
"""Render the degraded-run notice, or an empty string when all phases ran.
|
|
1693
|
+
|
|
1694
|
+
A phase that could not run leaves its section of the report empty. Said
|
|
1695
|
+
plainly, that is a missing build step; left unsaid, it looks like a
|
|
1696
|
+
finding about the codebase.
|
|
1697
|
+
"""
|
|
1698
|
+
if not self.phase_failures:
|
|
1699
|
+
return ""
|
|
1700
|
+
|
|
1701
|
+
lines = ["## Incomplete Analysis\n"]
|
|
1702
|
+
lines.append(
|
|
1703
|
+
f"{len(self.phase_failures)} of {self._TOTAL_PHASES} phases could not run. "
|
|
1704
|
+
"The sections they produce are missing from this report — that is a gap in "
|
|
1705
|
+
"the analysis, not a finding about the code.\n"
|
|
1706
|
+
)
|
|
1707
|
+
lines.append("| Phase | Name | Reason |")
|
|
1708
|
+
lines.append("|---|---|---|")
|
|
1709
|
+
for failure in self.phase_failures:
|
|
1710
|
+
lines.append(f"| {failure['phase']} | {failure['name']} | `{failure['error']}` |")
|
|
1711
|
+
|
|
1712
|
+
if any(
|
|
1713
|
+
"vec_nodes" in f["error"]
|
|
1714
|
+
or "no such table" in f["error"]
|
|
1715
|
+
or "Vector store not found" in f["error"]
|
|
1716
|
+
for f in self.phase_failures
|
|
1717
|
+
):
|
|
1718
|
+
lines.append(
|
|
1719
|
+
"\n> The semantic index is missing. Only the fan-out phase needs it; "
|
|
1720
|
+
"every other phase reads the SQLite graph directly, which is why the "
|
|
1721
|
+
"rest of this report is complete. Run `tscodekg build --repo <path>` "
|
|
1722
|
+
"(or `tscodekg build-index`) to build it, then re-run the analysis."
|
|
1723
|
+
)
|
|
1724
|
+
lines.append("")
|
|
1725
|
+
return "\n".join(lines)
|
|
1726
|
+
|
|
1644
1727
|
def _compile_results(self) -> dict:
|
|
1645
1728
|
"""Compile all phase results into a serialisable dictionary."""
|
|
1646
1729
|
sorted_fn = sorted(self.function_metrics.items(), key=lambda kv: kv[1].fan_in, reverse=True)
|
|
@@ -1676,6 +1759,10 @@ Cohesion = incoming-callers / (incoming + outgoing + 1). Higher = more internall
|
|
|
1676
1759
|
],
|
|
1677
1760
|
"centrality_modules": self.centrality_modules,
|
|
1678
1761
|
"coderank_top_nodes": self.coderank_top_nodes,
|
|
1762
|
+
# A caller reading the dict rather than the Markdown needs the same
|
|
1763
|
+
# signal the report carries: an empty section here means a phase did
|
|
1764
|
+
# not run, not that the codebase has nothing to show.
|
|
1765
|
+
"phase_failures": self.phase_failures,
|
|
1679
1766
|
}
|
|
1680
1767
|
|
|
1681
1768
|
def to_markdown(self) -> str:
|
|
@@ -1693,6 +1780,11 @@ Cohesion = incoming-callers / (incoming + outgoing + 1). Higher = more internall
|
|
|
1693
1780
|
out.append(f"**Generated:** {datetime.datetime.now(datetime.UTC).isoformat()} \n")
|
|
1694
1781
|
out.append("\n---\n")
|
|
1695
1782
|
|
|
1783
|
+
degraded = self._render_phase_failures()
|
|
1784
|
+
if degraded:
|
|
1785
|
+
out.append(degraded)
|
|
1786
|
+
out.append("\n---\n")
|
|
1787
|
+
|
|
1696
1788
|
out.append("## Baseline Metrics\n")
|
|
1697
1789
|
out.append("| Metric | Value |")
|
|
1698
1790
|
out.append("|---|---|")
|
|
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
|
|
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
|