agent-wiki-cli 0.6.1__tar.gz → 0.6.2__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 (119) hide show
  1. {agent_wiki_cli-0.6.1/src/agent_wiki_cli.egg-info → agent_wiki_cli-0.6.2}/PKG-INFO +1 -1
  2. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/pyproject.toml +1 -1
  3. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2/src/agent_wiki_cli.egg-info}/PKG-INFO +1 -1
  4. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/sync_cmd.py +110 -6
  5. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_sync.py +77 -0
  6. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/LICENSE +0 -0
  7. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/README.md +0 -0
  8. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/setup.cfg +0 -0
  9. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/agent_wiki_cli.egg-info/SOURCES.txt +0 -0
  10. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/agent_wiki_cli.egg-info/dependency_links.txt +0 -0
  11. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/agent_wiki_cli.egg-info/entry_points.txt +0 -0
  12. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/agent_wiki_cli.egg-info/requires.txt +0 -0
  13. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/agent_wiki_cli.egg-info/top_level.txt +0 -0
  14. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/__init__.py +0 -0
  15. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/api.py +0 -0
  16. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/cli.py +0 -0
  17. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/__init__.py +0 -0
  18. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/bootstrap_cmd.py +0 -0
  19. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/bump_cmd.py +0 -0
  20. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/ci_check_cmd.py +0 -0
  21. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/context_cmd.py +0 -0
  22. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/extract_cmd.py +0 -0
  23. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/generate_prompt_cmd.py +0 -0
  24. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/hook_cmd.py +0 -0
  25. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/init_cmd.py +0 -0
  26. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/install_cmd.py +0 -0
  27. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/lint_cmd.py +0 -0
  28. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/mcp_cmd.py +0 -0
  29. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/metrics_cmd.py +0 -0
  30. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/migrate_cmd.py +0 -0
  31. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/obsidian_cmd.py +0 -0
  32. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/plugins_cmd.py +0 -0
  33. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/prepare_extractors_cmd.py +0 -0
  34. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/release_cmd.py +0 -0
  35. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/review_cmd.py +0 -0
  36. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/status_cmd.py +0 -0
  37. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/team_cmd.py +0 -0
  38. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/trigger_cmd.py +0 -0
  39. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/uninstall_cmd.py +0 -0
  40. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/commands/upgrade_cmd.py +0 -0
  41. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/config.py +0 -0
  42. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/__init__.py +0 -0
  43. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/common.py +0 -0
  44. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/go_extractor.py +0 -0
  45. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/go_scripts/go.mod +0 -0
  46. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/go_scripts/main.go +0 -0
  47. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/python_extractor.py +0 -0
  48. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/rust_extractor.py +0 -0
  49. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/rust_scripts/Cargo.lock +0 -0
  50. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/rust_scripts/Cargo.toml +0 -0
  51. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/rust_scripts/src/main.rs +0 -0
  52. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/ts_extractor.py +0 -0
  53. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/ts_scripts/extract.js +0 -0
  54. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/extractors/ts_scripts/package.json +0 -0
  55. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/__init__.py +0 -0
  56. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/circuit_breaker.py +0 -0
  57. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/contracts.py +0 -0
  58. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/extractor_helpers.py +0 -0
  59. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/imports.py +0 -0
  60. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/inventory_cache.py +0 -0
  61. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/io.py +0 -0
  62. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/lockfile.py +0 -0
  63. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/mcp_server.py +0 -0
  64. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/metrics.py +0 -0
  65. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/obsidian.py +0 -0
  66. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/packages.py +0 -0
  67. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/paths.py +0 -0
  68. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/plugins.py +0 -0
  69. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/schema.py +0 -0
  70. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/secure_file.py +0 -0
  71. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/source_snapshot.py +0 -0
  72. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/team.py +0 -0
  73. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/src/llm_wiki_cli/services/versioning.py +0 -0
  74. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_api.py +0 -0
  75. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_bootstrap.py +0 -0
  76. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_bump.py +0 -0
  77. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_ci_check.py +0 -0
  78. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_circuit_breaker.py +0 -0
  79. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_cli.py +0 -0
  80. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_config.py +0 -0
  81. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_context.py +0 -0
  82. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_docker_bootstrap.py +0 -0
  83. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_docker_extract.py +0 -0
  84. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_docker_lint.py +0 -0
  85. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_e2e.py +0 -0
  86. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_extract.py +0 -0
  87. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_extractor_helpers.py +0 -0
  88. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_extractor_inventory_contracts.py +0 -0
  89. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_generate_prompt.py +0 -0
  90. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_go_extract.py +0 -0
  91. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_hook.py +0 -0
  92. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_imports.py +0 -0
  93. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_init.py +0 -0
  94. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_inventory_cache.py +0 -0
  95. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_io.py +0 -0
  96. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_lint.py +0 -0
  97. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_lockfile.py +0 -0
  98. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_mcp.py +0 -0
  99. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_metrics.py +0 -0
  100. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_migrate.py +0 -0
  101. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_multilanguage_wiki.py +0 -0
  102. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_obsidian.py +0 -0
  103. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_package_metadata.py +0 -0
  104. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_packages.py +0 -0
  105. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_paths.py +0 -0
  106. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_phase4_quality.py +0 -0
  107. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_plugins.py +0 -0
  108. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_release.py +0 -0
  109. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_rust_extract.py +0 -0
  110. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_schema.py +0 -0
  111. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_secure_file.py +0 -0
  112. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_source_snapshot.py +0 -0
  113. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_status.py +0 -0
  114. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_team.py +0 -0
  115. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_trigger.py +0 -0
  116. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_ts_extract.py +0 -0
  117. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_uninstall.py +0 -0
  118. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_upgrade.py +0 -0
  119. {agent_wiki_cli-0.6.1 → agent_wiki_cli-0.6.2}/tests/test_versioning.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-wiki-cli
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: CLI tool to maintain hybrid LLM Wikis for multi-language projects.
5
5
  Author-email: Denis Sivagin <denissvgn@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agent-wiki-cli"
7
- version = "0.6.1"
7
+ version = "0.6.2"
8
8
  description = "CLI tool to maintain hybrid LLM Wikis for multi-language projects."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-wiki-cli
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: CLI tool to maintain hybrid LLM Wikis for multi-language projects.
5
5
  Author-email: Denis Sivagin <denissvgn@gmail.com>
6
6
  License: MIT
@@ -1430,6 +1430,7 @@ def _apply_sync_changes(
1430
1430
  options.src_dir,
1431
1431
  entity_page_cache=page_maps.entity_page_cache,
1432
1432
  module_page_map=page_maps.module_page_map,
1433
+ preserve_semantic=options.preserve_semantic,
1433
1434
  )
1434
1435
 
1435
1436
  _append_log(options.wiki_dir, options.src_dir, diff, result)
@@ -1502,6 +1503,105 @@ def run(args) -> None:
1502
1503
  # ── Index + log helpers ───────────────────────────────────────────────────────
1503
1504
 
1504
1505
 
1506
+ _INDEX_GENERATED_HEADINGS = frozenset(
1507
+ heading.casefold()
1508
+ for heading in (
1509
+ "Entities",
1510
+ "Modules",
1511
+ "Workflows",
1512
+ "Infrastructure",
1513
+ )
1514
+ )
1515
+ _INDEX_GENERATED_INTROS = {
1516
+ ("Catalog of project modules and entities.",),
1517
+ }
1518
+
1519
+
1520
+ def _heading_title(line: str) -> str | None:
1521
+ match = _HEADING_RE.match(line.strip())
1522
+ if not match:
1523
+ return None
1524
+ return match.group(2).strip()
1525
+
1526
+
1527
+ def _iter_level_two_sections(lines: list[str]) -> list[tuple[str, list[str]]]:
1528
+ sections: list[tuple[str, list[str]]] = []
1529
+ for i, line in enumerate(lines):
1530
+ match = _HEADING_RE.match(line.strip())
1531
+ if not match or len(match.group(1)) != 2:
1532
+ continue
1533
+ end = len(lines)
1534
+ for j in range(i + 1, len(lines)):
1535
+ next_match = _HEADING_RE.match(lines[j].strip())
1536
+ if next_match and len(next_match.group(1)) <= 2:
1537
+ end = j
1538
+ break
1539
+ sections.append((line.strip(), _trim_blank_lines(lines[i + 1 : end])))
1540
+ return sections
1541
+
1542
+
1543
+ def _index_intro_lines(lines: list[str]) -> list[str]:
1544
+ start = 0
1545
+ if lines and lines[0].startswith("# "):
1546
+ start = 1
1547
+ first_section = len(lines)
1548
+ for i, line in enumerate(lines[start:], start=start):
1549
+ match = _HEADING_RE.match(line.strip())
1550
+ if match and len(match.group(1)) == 2:
1551
+ first_section = i
1552
+ break
1553
+ return _trim_blank_lines(lines[start:first_section])
1554
+
1555
+
1556
+ def _merge_intro_into_notes(
1557
+ sections: list[tuple[str, list[str]]], intro: list[str]
1558
+ ) -> list[tuple[str, list[str]]]:
1559
+ if not intro:
1560
+ return sections
1561
+ merged: list[tuple[str, list[str]]] = []
1562
+ inserted = False
1563
+ for heading, body in sections:
1564
+ title = _heading_title(heading)
1565
+ if title and title.casefold() == "notes" and not inserted:
1566
+ new_body = intro + ([""] if body else []) + body
1567
+ merged.append((heading, new_body))
1568
+ inserted = True
1569
+ else:
1570
+ merged.append((heading, body))
1571
+ if not inserted:
1572
+ merged.insert(0, ("## Notes", intro))
1573
+ return merged
1574
+
1575
+
1576
+ def _preserved_index_sections(old_md: str) -> list[tuple[str, list[str]]]:
1577
+ lines = _normalize_md(old_md).splitlines()
1578
+ custom_sections = [
1579
+ (heading, body)
1580
+ for heading, body in _iter_level_two_sections(lines)
1581
+ if (_heading_title(heading) or "").casefold() not in _INDEX_GENERATED_HEADINGS
1582
+ ]
1583
+ intro = _index_intro_lines(lines)
1584
+ if tuple(intro) in _INDEX_GENERATED_INTROS:
1585
+ intro = []
1586
+ return _merge_intro_into_notes(custom_sections, intro)
1587
+
1588
+
1589
+ def _preserve_index_custom_sections(old_md: str, new_md: str) -> str:
1590
+ preserved = _preserved_index_sections(old_md)
1591
+ if not preserved:
1592
+ return new_md
1593
+ lines = _normalize_md(new_md).splitlines()
1594
+ while lines and lines[-1].strip() == "":
1595
+ lines.pop()
1596
+ lines.append("")
1597
+ for heading, body in preserved:
1598
+ lines.append(heading)
1599
+ lines.append("")
1600
+ lines.extend(body)
1601
+ lines.append("")
1602
+ return "\n".join(lines)
1603
+
1604
+
1505
1605
  def _rebuild_index(
1506
1606
  wiki_dir: Path,
1507
1607
  inventory: dict,
@@ -1509,6 +1609,7 @@ def _rebuild_index(
1509
1609
  *,
1510
1610
  entity_page_cache: dict[tuple[str, str], str] | None = None,
1511
1611
  module_page_map: dict[str, str] | None = None,
1612
+ preserve_semantic: bool = True,
1512
1613
  ) -> None:
1513
1614
  """Regenerate index.md from the live inventory."""
1514
1615
  if entity_page_cache is None:
@@ -1539,14 +1640,17 @@ def _rebuild_index(
1539
1640
  infra_entries = _list_existing_pages(wiki_dir / "infrastructure", "type")
1540
1641
 
1541
1642
  index_path = wiki_dir / "index.md"
1643
+ new_index = _generate_index_md(
1644
+ all_entity_names,
1645
+ module_entries,
1646
+ workflow_entries or None,
1647
+ infra_entries or None,
1648
+ )
1649
+ if preserve_semantic and index_path.exists():
1650
+ new_index = _preserve_index_custom_sections(read_md(index_path), new_index)
1542
1651
  write_state = _write_md_if_changed(
1543
1652
  index_path,
1544
- _generate_index_md(
1545
- all_entity_names,
1546
- module_entries,
1547
- workflow_entries or None,
1548
- infra_entries or None,
1549
- ),
1653
+ new_index,
1550
1654
  )
1551
1655
  if write_state == "unchanged":
1552
1656
  print(" SKIP index.md (unchanged)")
@@ -1240,6 +1240,83 @@ class TestSemanticPreservation:
1240
1240
  assert "Human-curated display name." not in entity_content
1241
1241
 
1242
1242
 
1243
+ class TestSyncIndexCustomSections:
1244
+ def _inventory(self):
1245
+ return {
1246
+ "api.py": {
1247
+ "language": "python",
1248
+ "classes": [],
1249
+ "functions": [{"name": "run", "line": 1}],
1250
+ }
1251
+ }
1252
+
1253
+ def test_rebuild_index_preserves_custom_section_links_for_strict_lint(
1254
+ self, tmp_path
1255
+ ):
1256
+ wiki = tmp_path / "wiki"
1257
+ config_docs = wiki / "config_docs"
1258
+ config_docs.mkdir(parents=True)
1259
+ (config_docs / "recording_rules_yml.md").write_text(
1260
+ "# Recording rules\n", encoding="utf-8"
1261
+ )
1262
+ (config_docs / "grafana_dashboards.md").write_text(
1263
+ "# Grafana dashboards\n", encoding="utf-8"
1264
+ )
1265
+ (wiki / "index.md").write_text(
1266
+ textwrap.dedent("""\
1267
+ # Old Index
1268
+
1269
+ ## Configuration Docs
1270
+
1271
+ - [Recording rules](config_docs/recording_rules_yml.md)
1272
+ - [Grafana dashboards](config_docs/grafana_dashboards.md)
1273
+ """),
1274
+ encoding="utf-8",
1275
+ )
1276
+
1277
+ sync_cmd._rebuild_index(
1278
+ wiki, self._inventory(), str(tmp_path), preserve_semantic=True
1279
+ )
1280
+
1281
+ index = (wiki / "index.md").read_text(encoding="utf-8")
1282
+ assert "## Configuration Docs" in index
1283
+ assert "config_docs/recording_rules_yml.md" in index
1284
+ assert "config_docs/grafana_dashboards.md" in index
1285
+
1286
+ page_index = lint_cmd._build_page_index(wiki)
1287
+ report = lint_cmd.LintReport(wiki_dir=str(wiki), src_dir=str(tmp_path))
1288
+ lint_cmd._check_orphan_pages(report, wiki, page_index)
1289
+ assert report.count("orphan_pages") == 0
1290
+
1291
+ def test_rebuild_index_no_preserve_semantic_drops_custom_section_links(
1292
+ self, tmp_path
1293
+ ):
1294
+ wiki = tmp_path / "wiki"
1295
+ config_docs = wiki / "config_docs"
1296
+ config_docs.mkdir(parents=True)
1297
+ (config_docs / "recording_rules_yml.md").write_text(
1298
+ "# Recording rules\n", encoding="utf-8"
1299
+ )
1300
+ (wiki / "index.md").write_text(
1301
+ textwrap.dedent("""\
1302
+ # Old Index
1303
+
1304
+ ## Configuration Docs
1305
+
1306
+ - [Recording rules](config_docs/recording_rules_yml.md)
1307
+ """),
1308
+ encoding="utf-8",
1309
+ )
1310
+
1311
+ sync_cmd._rebuild_index(
1312
+ wiki, self._inventory(), str(tmp_path), preserve_semantic=False
1313
+ )
1314
+
1315
+ index = (wiki / "index.md").read_text(encoding="utf-8")
1316
+ assert "## Configuration Docs" not in index
1317
+ assert "config_docs/recording_rules_yml.md" not in index
1318
+
1319
+
1243
1320
  class TestNewFile:
1244
1321
  """When a new source file is added, new pages are created and manifest updated."""
1245
1322
 
File without changes
File without changes
File without changes