Add source preview to AI structure package
This commit is contained in:
@@ -62,9 +62,11 @@ def prepare_ai_structure(
|
|||||||
diagnostics,
|
diagnostics,
|
||||||
binaries,
|
binaries,
|
||||||
_source_layout_summary(input_path),
|
_source_layout_summary(input_path),
|
||||||
|
_source_preview_summary(input_path),
|
||||||
)
|
)
|
||||||
_write_json(output_path / "manifest.json", manifest)
|
_write_json(output_path / "manifest.json", manifest)
|
||||||
_write_json(output_path / "source_inventory.json", {"files": files})
|
_write_json(output_path / "source_inventory.json", {"files": files})
|
||||||
|
_write_json(output_path / "source_preview.json", manifest.get("source_preview") or [])
|
||||||
if snapshot is not None:
|
if snapshot is not None:
|
||||||
(output_path / "sir_snapshot.json").write_bytes(snapshot_to_json(snapshot))
|
(output_path / "sir_snapshot.json").write_bytes(snapshot_to_json(snapshot))
|
||||||
_write_json(output_path / "ai_objects.json", _ai_objects(snapshot))
|
_write_json(output_path / "ai_objects.json", _ai_objects(snapshot))
|
||||||
@@ -104,6 +106,7 @@ def _manifest(
|
|||||||
diagnostics: list[str],
|
diagnostics: list[str],
|
||||||
binaries: list[dict[str, Any]],
|
binaries: list[dict[str, Any]],
|
||||||
source_layout: dict[str, Any],
|
source_layout: dict[str, Any],
|
||||||
|
source_preview: list[dict[str, Any]],
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"version": AI_STRUCTURE_VERSION,
|
"version": AI_STRUCTURE_VERSION,
|
||||||
@@ -116,6 +119,7 @@ def _manifest(
|
|||||||
"files_count": len(files),
|
"files_count": len(files),
|
||||||
"binary_1c_files": binaries,
|
"binary_1c_files": binaries,
|
||||||
"source_layout": source_layout,
|
"source_layout": source_layout,
|
||||||
|
"source_preview": source_preview,
|
||||||
"artifacts": _artifacts(snapshot, normalized),
|
"artifacts": _artifacts(snapshot, normalized),
|
||||||
"snapshot": None
|
"snapshot": None
|
||||||
if snapshot is None
|
if snapshot is None
|
||||||
@@ -148,6 +152,7 @@ def _artifacts(snapshot: SirSnapshot | None, normalized: NormalizedProject | Non
|
|||||||
"export_plan.md",
|
"export_plan.md",
|
||||||
"codex_package",
|
"codex_package",
|
||||||
"project_layout.json",
|
"project_layout.json",
|
||||||
|
"source_preview.json",
|
||||||
"compact_objects.json",
|
"compact_objects.json",
|
||||||
"compact_modules.json",
|
"compact_modules.json",
|
||||||
]
|
]
|
||||||
@@ -201,6 +206,7 @@ def _write_codex_package(
|
|||||||
_write_json(root / "indexes" / "source-inventory.json", {"files": files})
|
_write_json(root / "indexes" / "source-inventory.json", {"files": files})
|
||||||
_write_json(root / "indexes" / "source-map.json", {"files": source_map})
|
_write_json(root / "indexes" / "source-map.json", {"files": source_map})
|
||||||
_write_json(root / "indexes" / "project-layout.json", manifest.get("source_layout") or {})
|
_write_json(root / "indexes" / "project-layout.json", manifest.get("source_layout") or {})
|
||||||
|
_write_json(root / "indexes" / "source-preview.json", manifest.get("source_preview") or [])
|
||||||
_write_json(root / "indexes" / "objects-compact.json", compact_objects)
|
_write_json(root / "indexes" / "objects-compact.json", compact_objects)
|
||||||
_write_json(root / "indexes" / "modules-compact.json", compact_modules)
|
_write_json(root / "indexes" / "modules-compact.json", compact_modules)
|
||||||
_write_json(root / "compact" / "objects.json", compact_objects)
|
_write_json(root / "compact" / "objects.json", compact_objects)
|
||||||
@@ -592,6 +598,29 @@ def _source_layout_summary(root: Path) -> dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _source_preview_summary(root: Path) -> list[dict[str, Any]]:
|
||||||
|
files = [root] if root.is_file() else sorted(path for path in root.rglob("*") if path.is_file())
|
||||||
|
object_files = _preview_relative_paths(
|
||||||
|
root,
|
||||||
|
sorted(
|
||||||
|
[path for path in files if path.suffix.casefold() in {".xml", ".mdo"}],
|
||||||
|
key=lambda path: (
|
||||||
|
0 if any(part.casefold() in {"configuration", "конфигурация"} for part in path.parts) else 1,
|
||||||
|
str(path).casefold(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
limit=6,
|
||||||
|
)
|
||||||
|
module_files = _preview_relative_paths(root, [path for path in files if path.suffix.casefold() == ".bsl"], limit=6)
|
||||||
|
layout = _source_layout_summary(root)
|
||||||
|
return [
|
||||||
|
{"label": "Главная конфигурация", "items": [layout["main_configuration_root"]]},
|
||||||
|
{"label": "Папки расширений", "items": layout["extension_roots"] or ["нет"]},
|
||||||
|
{"label": "Первые файлы объектов", "items": object_files or ["не найдены"]},
|
||||||
|
{"label": "Первые файлы модулей", "items": module_files or ["не найдены"]},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _compact_objects(normalized: NormalizedProject | None) -> list[dict[str, Any]]:
|
def _compact_objects(normalized: NormalizedProject | None) -> list[dict[str, Any]]:
|
||||||
if normalized is None:
|
if normalized is None:
|
||||||
return []
|
return []
|
||||||
@@ -679,6 +708,16 @@ def _project_brief_markdown(manifest: dict[str, Any], compact_objects: list[dict
|
|||||||
return "\n".join(lines) + "\n"
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _preview_relative_paths(root: Path, files: list[Path], *, limit: int) -> list[str]:
|
||||||
|
preview: list[str] = []
|
||||||
|
for path in files[:limit]:
|
||||||
|
if root.is_file():
|
||||||
|
preview.append(path.name)
|
||||||
|
else:
|
||||||
|
preview.append(path.relative_to(root).as_posix())
|
||||||
|
return preview
|
||||||
|
|
||||||
|
|
||||||
def _export_plan_markdown(project_id: str, input_path: Path, output_path: Path, binaries: list[dict[str, Any]], parseable: bool) -> str:
|
def _export_plan_markdown(project_id: str, input_path: Path, output_path: Path, binaries: list[dict[str, Any]], parseable: bool) -> str:
|
||||||
lines = [
|
lines = [
|
||||||
f"# План выгрузки 1С для {project_id}",
|
f"# План выгрузки 1С для {project_id}",
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ def render_html5_ai_structure_result(result: dict | None) -> str:
|
|||||||
snapshot = result.get("snapshot") or {}
|
snapshot = result.get("snapshot") or {}
|
||||||
normalized = result.get("normalized") or {}
|
normalized = result.get("normalized") or {}
|
||||||
source_layout = result.get("source_layout") or {}
|
source_layout = result.get("source_layout") or {}
|
||||||
|
source_preview = list(result.get("source_preview") or [])
|
||||||
status = _status_text(result.get("status"))
|
status = _status_text(result.get("status"))
|
||||||
return f"""
|
return f"""
|
||||||
<section class="ai-structure-result" data-html5-ai-structure-status="{escape(str(result.get('status', '')))}">
|
<section class="ai-structure-result" data-html5-ai-structure-status="{escape(str(result.get('status', '')))}">
|
||||||
@@ -225,6 +226,7 @@ def render_html5_ai_structure_result(result: dict | None) -> str:
|
|||||||
<div><dt>Объекты</dt><dd>{escape(str(normalized.get("objects", 0)))}</dd></div>
|
<div><dt>Объекты</dt><dd>{escape(str(normalized.get("objects", 0)))}</dd></div>
|
||||||
</dl>
|
</dl>
|
||||||
{render_html5_ai_structure_result_summary(source_layout, normalized)}
|
{render_html5_ai_structure_result_summary(source_layout, normalized)}
|
||||||
|
{_render_ai_structure_preview_tree(source_preview)}
|
||||||
<div class="panel-title">Артефакты</div>
|
<div class="panel-title">Артефакты</div>
|
||||||
<div class="access-operations">{''.join(f'<article class="access-card"><strong>{escape(_artifact_text(item))}</strong><small>Файл пакета структуры</small></article>' for item in artifacts)}</div>
|
<div class="access-operations">{''.join(f'<article class="access-card"><strong>{escape(_artifact_text(item))}</strong><small>Файл пакета структуры</small></article>' for item in artifacts)}</div>
|
||||||
{_diagnostics(diagnostics)}
|
{_diagnostics(diagnostics)}
|
||||||
@@ -365,6 +367,7 @@ def _artifact_text(value: object) -> str:
|
|||||||
"export_plan.md": "План выгрузки",
|
"export_plan.md": "План выгрузки",
|
||||||
"codex_package": "Папка для Codex",
|
"codex_package": "Папка для Codex",
|
||||||
"project_layout.json": "Карта раскладки проекта",
|
"project_layout.json": "Карта раскладки проекта",
|
||||||
|
"source_preview.json": "Краткий предпросмотр структуры",
|
||||||
"compact_objects.json": "Компактный индекс объектов",
|
"compact_objects.json": "Компактный индекс объектов",
|
||||||
"compact_modules.json": "Компактный индекс модулей",
|
"compact_modules.json": "Компактный индекс модулей",
|
||||||
"sir_snapshot.json": "Снимок графа SIR",
|
"sir_snapshot.json": "Снимок графа SIR",
|
||||||
|
|||||||
@@ -1409,6 +1409,7 @@ class AiStructurePrepareResponse(BaseModel):
|
|||||||
files_count: int = 0
|
files_count: int = 0
|
||||||
binary_1c_files: list[dict] = Field(default_factory=list)
|
binary_1c_files: list[dict] = Field(default_factory=list)
|
||||||
source_layout: dict = Field(default_factory=dict)
|
source_layout: dict = Field(default_factory=dict)
|
||||||
|
source_preview: list[dict] = Field(default_factory=list)
|
||||||
artifacts: list[str] = Field(default_factory=list)
|
artifacts: list[str] = Field(default_factory=list)
|
||||||
snapshot: dict | None = None
|
snapshot: dict | None = None
|
||||||
normalized: dict | None = None
|
normalized: dict | None = None
|
||||||
|
|||||||
@@ -1731,6 +1731,7 @@ def test_ai_structure_prepare_writes_ai_ready_package(tmp_path: Path):
|
|||||||
assert (output / "normalized_project.json").exists()
|
assert (output / "normalized_project.json").exists()
|
||||||
assert (output / "sir_snapshot.json").exists()
|
assert (output / "sir_snapshot.json").exists()
|
||||||
assert (output / "project_layout.json").exists()
|
assert (output / "project_layout.json").exists()
|
||||||
|
assert (output / "source_preview.json").exists()
|
||||||
assert (output / "compact_objects.json").exists()
|
assert (output / "compact_objects.json").exists()
|
||||||
assert (output / "compact_modules.json").exists()
|
assert (output / "compact_modules.json").exists()
|
||||||
assert (codex_package / "AGENTS.md").exists()
|
assert (codex_package / "AGENTS.md").exists()
|
||||||
@@ -1740,6 +1741,7 @@ def test_ai_structure_prepare_writes_ai_ready_package(tmp_path: Path):
|
|||||||
assert (codex_package / "context" / "project-overview.md").exists()
|
assert (codex_package / "context" / "project-overview.md").exists()
|
||||||
assert (codex_package / "indexes" / "codex-navigation.json").exists()
|
assert (codex_package / "indexes" / "codex-navigation.json").exists()
|
||||||
assert (codex_package / "indexes" / "project-layout.json").exists()
|
assert (codex_package / "indexes" / "project-layout.json").exists()
|
||||||
|
assert (codex_package / "indexes" / "source-preview.json").exists()
|
||||||
assert (codex_package / "indexes" / "objects-compact.json").exists()
|
assert (codex_package / "indexes" / "objects-compact.json").exists()
|
||||||
assert (codex_package / "indexes" / "modules-compact.json").exists()
|
assert (codex_package / "indexes" / "modules-compact.json").exists()
|
||||||
assert (codex_package / "indexes" / "objects.json").exists()
|
assert (codex_package / "indexes" / "objects.json").exists()
|
||||||
@@ -1842,6 +1844,7 @@ def test_ai_structure_prepare_understands_configuration_and_extension_folders(tm
|
|||||||
assert payload["status"] == "ready"
|
assert payload["status"] == "ready"
|
||||||
assert payload["source_layout"]["main_configuration_root"] == "Конфигурация"
|
assert payload["source_layout"]["main_configuration_root"] == "Конфигурация"
|
||||||
assert payload["source_layout"]["extension_roots"] == ["CRM"]
|
assert payload["source_layout"]["extension_roots"] == ["CRM"]
|
||||||
|
assert any(item["label"] == "Папки расширений" for item in payload["source_preview"])
|
||||||
assert payload["normalized"]["extensions"] == 1
|
assert payload["normalized"]["extensions"] == 1
|
||||||
codex_package = output / payload["codex_package_folder"]
|
codex_package = output / payload["codex_package_folder"]
|
||||||
layout = json.loads((codex_package / "indexes" / "project-layout.json").read_text(encoding="utf-8"))
|
layout = json.loads((codex_package / "indexes" / "project-layout.json").read_text(encoding="utf-8"))
|
||||||
|
|||||||
Reference in New Issue
Block a user