ht32-code-mcp 0.2.4__tar.gz → 0.2.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ht32-code-mcp
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: HT32 Code MCP Server - 为 AI Agent 提供 HT32 函数库/例程/模板检索与工程导出
5
5
  License-Expression: MIT
6
6
  Keywords: firmware,holtek,ht32,mcp,mcu
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ht32-code-mcp"
7
- version = "0.2.4"
7
+ version = "0.2.5"
8
8
  description = "HT32 Code MCP Server - 为 AI Agent 提供 HT32 函数库/例程/模板检索与工程导出"
9
9
  requires-python = ">=3.11"
10
10
  license = "MIT"
@@ -142,7 +142,8 @@ def _series_matches(pkg: dict, series: str) -> bool:
142
142
  want = normalize_series(series)
143
143
  if any(normalize_series(s) == want for s in pkg.get("series", [])):
144
144
  return True
145
- return pkg.get("family", "").lower() == series.strip().lower().rstrip("+")
145
+ fam = pkg.get("family", "").lower().rstrip("+")
146
+ return bool(fam) and fam == series.strip().lower().rstrip("+")
146
147
 
147
148
 
148
149
  def _filter_by_series(pool: list[dict], series: str) -> list[dict]:
@@ -838,12 +838,14 @@ def test_normalize_series_keeps_f_l_distinction():
838
838
  def test_find_example_series_filter_multi_family():
839
839
  """series 过滤支持短写/全称/内核家族,且各家族命中数不同。"""
840
840
  counts = {}
841
- for s in ("f5", "l5", "M3", "M4", "F493x5"):
841
+ for s in ("f5", "l5", "M0+", "M3", "M4", "F493x5"):
842
842
  out = srv.find_example("gpio", series=s, limit=50)
843
843
  assert "未找到" not in out and "不在覆盖范围" not in out, s
844
844
  counts[s] = int(re.search(r"找到 (\d+) 个", out).group(1))
845
845
  assert counts["M4"] > counts["F493x5"] # M4 家族含三个包
846
846
  assert counts["f5"] and counts["l5"] and counts["M3"]
847
+ # M0+ 家族 = F5 + L5(回归:此前 rstrip("+") 只作用于入参,family="M0+" 永不匹配)
848
+ assert counts["M0+"] == counts["f5"] + counts["l5"]
847
849
 
848
850
 
849
851
  def test_find_example_labels_and_main_path():
@@ -942,6 +944,26 @@ def test_knowledge_pages_raw_refs_exist():
942
944
  assert not bad, "引用了不存在的 raw/ 路径:\n" + "\n".join(bad)
943
945
 
944
946
 
947
+ def test_knowledge_wikilink_targets_exist():
948
+ """仓库铁律:所有 [[wikilink]] 目标必须存在(断链为 0)。"""
949
+ pages: dict[str, Path] = {}
950
+ for root in (srv.CODE_ROOT / "entities", srv.CODE_ROOT / "comparisons"):
951
+ if root.is_dir():
952
+ for md in sorted(root.rglob("*.md")):
953
+ pages[md.stem] = md
954
+ scan = list(pages.values())
955
+ index_md = srv.CODE_ROOT / "index.md"
956
+ if index_md.is_file():
957
+ scan.append(index_md)
958
+ bad: list[str] = []
959
+ for md in scan:
960
+ for raw in re.findall(r"\[\[([^\]]+)\]\]", md.read_text(encoding="utf-8")):
961
+ target = raw.split("|")[0].split("#")[0].strip()
962
+ if target and target not in pages:
963
+ bad.append(f"{md.name} -> [[{target}]]")
964
+ assert not bad, "断链(目标页不存在):\n" + "\n".join(sorted(set(bad)))
965
+
966
+
945
967
  def test_knowledge_page_covers_ckcu_crm_naming():
946
968
  """ckcu 页须写明 M0+/M3 用 ckcu、M4 用 crm 的命名差异(跨内核关键差异)。"""
947
969
  text = (srv.CODE_ROOT / "entities" / "libraries" / "ckcu.md").read_text(encoding="utf-8")