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.
Files changed (36) hide show
  1. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/PKG-INFO +5 -5
  2. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/README.md +3 -3
  3. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/pyproject.toml +3 -3
  4. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/__init__.py +1 -1
  5. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/analysis.py +94 -2
  6. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/LICENSE +0 -0
  7. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/__main__.py +0 -0
  8. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/app.py +0 -0
  9. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/bridge.py +0 -0
  10. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/centrality.py +0 -0
  11. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/__init__.py +0 -0
  12. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_analyze.py +0 -0
  13. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_bridges.py +0 -0
  14. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_build.py +0 -0
  15. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_centrality.py +0 -0
  16. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_explain.py +0 -0
  17. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_framework_nodes.py +0 -0
  18. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_hooks.py +0 -0
  19. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_init.py +0 -0
  20. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_mcp.py +0 -0
  21. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_model.py +0 -0
  22. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_query.py +0 -0
  23. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_snapshot.py +0 -0
  24. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/cmd_viz.py +0 -0
  25. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/cli/main.py +0 -0
  26. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/coderank.py +0 -0
  27. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/config.py +0 -0
  28. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/explain.py +0 -0
  29. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/extractor.py +0 -0
  30. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/framework_detector.py +0 -0
  31. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/kg.py +0 -0
  32. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/layout3d.py +0 -0
  33. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/mcp_server.py +0 -0
  34. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/snapshots.py +0 -0
  35. {tscode_kg-0.5.0 → tscode_kg-0.5.1}/src/tscode_kg/viz3d.py +0 -0
  36. {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.0
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.20.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
  [![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](https://www.python.org/)
43
43
  [![License: Elastic-2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](https://www.elastic.co/licensing/elastic-license)
44
44
  [![PyPI](https://img.shields.io/pypi/v/tscode-kg.svg)](https://pypi.org/project/tscode-kg/)
45
- [![Version](https://img.shields.io/badge/version-0.5.0-blue.svg)](https://github.com/Flux-Frontiers/tscode_kg/releases)
45
+ [![Version](https://img.shields.io/badge/version-0.5.1-blue.svg)](https://github.com/Flux-Frontiers/tscode_kg/releases)
46
46
  [![CI](https://github.com/Flux-Frontiers/tscode_kg/actions/workflows/ci.yml/badge.svg)](https://github.com/Flux-Frontiers/tscode_kg/actions/workflows/ci.yml)
47
47
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
48
48
  [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.22559450-blue.svg)](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
  [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.22559450-blue.svg)](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.0) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.22559450
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.0},
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
  [![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](https://www.python.org/)
4
4
  [![License: Elastic-2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](https://www.elastic.co/licensing/elastic-license)
5
5
  [![PyPI](https://img.shields.io/pypi/v/tscode-kg.svg)](https://pypi.org/project/tscode-kg/)
6
- [![Version](https://img.shields.io/badge/version-0.5.0-blue.svg)](https://github.com/Flux-Frontiers/tscode_kg/releases)
6
+ [![Version](https://img.shields.io/badge/version-0.5.1-blue.svg)](https://github.com/Flux-Frontiers/tscode_kg/releases)
7
7
  [![CI](https://github.com/Flux-Frontiers/tscode_kg/actions/workflows/ci.yml/badge.svg)](https://github.com/Flux-Frontiers/tscode_kg/actions/workflows/ci.yml)
8
8
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
9
9
  [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.22559450-blue.svg)](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
  [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.22559450-blue.svg)](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.0) [Software]. Flux-Frontiers. https://doi.org/10.5281/zenodo.22559450
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.0},
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.0"
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.20.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.0"
162
+ pycode-kg = ">=0.27.1"
163
163
 
164
164
  [project.urls]
165
165
  Homepage = "https://github.com/Flux-Frontiers/tscode_kg"
@@ -18,7 +18,7 @@ KGExtractor SDK::
18
18
  from tscode_kg import TSCodeExtractor
19
19
  """
20
20
 
21
- __version__ = "0.5.0"
21
+ __version__ = "0.5.1"
22
22
  __author__ = "Eric G. Suchanek, PhD"
23
23
 
24
24
  from tscode_kg.extractor import TSCodeExtractor
@@ -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
- fn()
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 = f" {self._phase_result}" if self._phase_result else ""
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