Record repository UI status in the scanner and tolerate older jsonschema.
Adds the repo-ui-metadata extractor (ui_status yes/candidate/not_detected plus ui_evidence), falls back to the legacy validator when jsonschema does not accept a referencing registry, and covers unknown edge endpoints in the graph explorer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 7458@bnt-lap001 Assistant-Session: 62534cdf-8348-48a7-9c0d-46e0f74c8eae
This commit is contained in:
parent
c65b9eddfe
commit
564dc59c4f
5 changed files with 138 additions and 4 deletions
|
|
@ -395,6 +395,7 @@ def _deterministic_extractors() -> list:
|
|||
return [
|
||||
_extract_repo_metadata,
|
||||
_extract_text_metadata,
|
||||
_extract_ui_metadata,
|
||||
_extract_fabric_declarations,
|
||||
_extract_python_package,
|
||||
_extract_node_package,
|
||||
|
|
@ -478,6 +479,100 @@ def _extract_text_metadata(context: ScanContext) -> None:
|
|||
)
|
||||
|
||||
|
||||
def _extract_ui_metadata(context: ScanContext) -> None:
|
||||
"""Record first-level evidence about whether a repository provides a UI."""
|
||||
|
||||
scope = context.accumulator.add_scope(
|
||||
extractor_id="repo-ui-metadata",
|
||||
source_kind="file",
|
||||
source_path=".",
|
||||
description="Repository-level user-interface indicators.",
|
||||
)
|
||||
evidence: list[str] = []
|
||||
declared = False
|
||||
|
||||
for path in declaration_files(context.repo_path):
|
||||
try:
|
||||
data = load_yaml(path)
|
||||
except Exception:
|
||||
continue
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
spec = data.get("spec") if isinstance(data.get("spec"), dict) else {}
|
||||
if spec.get("interface_type") == "web-ui":
|
||||
declared = True
|
||||
evidence.append(context.relpath(path))
|
||||
|
||||
marker_paths = (
|
||||
"index.html",
|
||||
"src/main.ts",
|
||||
"src/main.tsx",
|
||||
"src/main.js",
|
||||
"src/main.jsx",
|
||||
"src/App.tsx",
|
||||
"src/App.jsx",
|
||||
"vite.config.ts",
|
||||
"vite.config.js",
|
||||
"next.config.js",
|
||||
"next.config.mjs",
|
||||
"angular.json",
|
||||
)
|
||||
for marker in marker_paths:
|
||||
if (context.repo_path / marker).is_file():
|
||||
evidence.append(marker)
|
||||
|
||||
for package_name in ("package.json",):
|
||||
package_path = context.repo_path / package_name
|
||||
if not package_path.is_file():
|
||||
continue
|
||||
try:
|
||||
package = json.loads(package_path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
continue
|
||||
scripts = package.get("scripts") if isinstance(package, dict) else {}
|
||||
dependencies = {}
|
||||
if isinstance(package, dict):
|
||||
dependencies.update(package.get("dependencies") or {})
|
||||
dependencies.update(package.get("devDependencies") or {})
|
||||
ui_packages = {"react", "react-dom", "vue", "@angular/core", "svelte", "next", "nuxt"}
|
||||
if isinstance(scripts, dict) and any("dev" in str(value).lower() or "vite" in str(value).lower() for value in scripts.values()):
|
||||
evidence.append(package_name)
|
||||
if ui_packages.intersection(dependencies):
|
||||
evidence.append(package_name)
|
||||
|
||||
evidence = sorted(set(evidence))
|
||||
if declared:
|
||||
status = "yes"
|
||||
confidence = 1.0
|
||||
elif evidence:
|
||||
status = "candidate"
|
||||
confidence = 0.65
|
||||
else:
|
||||
status = "not_detected"
|
||||
confidence = 0.4
|
||||
|
||||
anchor = _source_anchor("file", evidence[0] if evidence else ".")
|
||||
provenance = _provenance("repo-ui-metadata")
|
||||
context.accumulator.add_attribute(
|
||||
entity_key=context.repository_key,
|
||||
name="ui_status",
|
||||
value=status,
|
||||
replacement_scope=scope,
|
||||
provenance=provenance,
|
||||
source_anchor=anchor,
|
||||
confidence=confidence,
|
||||
)
|
||||
context.accumulator.add_attribute(
|
||||
entity_key=context.repository_key,
|
||||
name="ui_evidence",
|
||||
value=evidence,
|
||||
replacement_scope=scope,
|
||||
provenance=provenance,
|
||||
source_anchor=anchor,
|
||||
confidence=confidence,
|
||||
)
|
||||
|
||||
|
||||
def _extract_fabric_declarations(context: ScanContext) -> None:
|
||||
declarations: list[tuple[Path, dict[str, Any]]] = []
|
||||
for path in declaration_files(context.repo_path):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue