mcp-stata 1.18.0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
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.
- mcp_stata/__init__.py +4 -0
- mcp_stata/_native_ops.cpython-313-x86_64-linux-gnu.so +0 -0
- mcp_stata/config.py +20 -0
- mcp_stata/discovery.py +550 -0
- mcp_stata/graph_detector.py +401 -0
- mcp_stata/models.py +62 -0
- mcp_stata/native_ops.py +87 -0
- mcp_stata/server.py +1130 -0
- mcp_stata/smcl/smcl2html.py +88 -0
- mcp_stata/stata_client.py +3692 -0
- mcp_stata/streaming_io.py +263 -0
- mcp_stata/test_stata.py +54 -0
- mcp_stata/ui_http.py +998 -0
- mcp_stata-1.18.0.dist-info/METADATA +471 -0
- mcp_stata-1.18.0.dist-info/RECORD +18 -0
- mcp_stata-1.18.0.dist-info/WHEEL +5 -0
- mcp_stata-1.18.0.dist-info/entry_points.txt +2 -0
- mcp_stata-1.18.0.dist-info/licenses/LICENSE +661 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Convert a SMCL file into Markdown.
|
|
2
|
+
|
|
3
|
+
Adapted from https://github.com/sergiocorreia/parse-smcl (MIT). Simplified into
|
|
4
|
+
a single module geared toward MCP, emitting Markdown by default.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from mcp_stata.native_ops import smcl_to_markdown as rust_smcl_to_markdown
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def expand_includes(lines, adopath):
|
|
13
|
+
"""Expand INCLUDE directives if ado path is available."""
|
|
14
|
+
if not adopath:
|
|
15
|
+
return lines
|
|
16
|
+
includes = [(i, line[13:].strip()) for (i, line) in enumerate(lines) if line.startswith("INCLUDE help ")]
|
|
17
|
+
if os.path.exists(adopath):
|
|
18
|
+
for i, cmd in reversed(includes):
|
|
19
|
+
fn = os.path.join(adopath, cmd[0], cmd if cmd.endswith(".ihlp") else cmd + ".ihlp")
|
|
20
|
+
try:
|
|
21
|
+
with open(fn, "r", encoding="utf-8") as f:
|
|
22
|
+
content = f.readlines()
|
|
23
|
+
except FileNotFoundError:
|
|
24
|
+
continue
|
|
25
|
+
if content and content[0].startswith("{* *! version"):
|
|
26
|
+
content.pop(0)
|
|
27
|
+
lines[i:i+1] = content
|
|
28
|
+
return lines
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _inline_to_markdown(text: str) -> str:
|
|
32
|
+
"""Convert common inline SMCL directives to Markdown."""
|
|
33
|
+
|
|
34
|
+
def repl(match: re.Match) -> str:
|
|
35
|
+
tag = match.group(1).lower()
|
|
36
|
+
content = match.group(2) or ""
|
|
37
|
+
if tag in ("bf", "strong"):
|
|
38
|
+
return f"**{content}**"
|
|
39
|
+
if tag in ("it", "em"):
|
|
40
|
+
return f"*{content}*"
|
|
41
|
+
if tag in ("cmd", "cmdab", "code", "inp", "input", "res", "err", "txt"):
|
|
42
|
+
return f"`{content}`"
|
|
43
|
+
return content
|
|
44
|
+
|
|
45
|
+
text = re.sub(r"\{([a-zA-Z0-9_]+):([^}]*)\}", repl, text)
|
|
46
|
+
text = re.sub(r"\{[^}]*\}", "", text)
|
|
47
|
+
return text
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def smcl_to_markdown(smcl_text: str, adopath: str = None, current_file: str = "help") -> str:
|
|
51
|
+
"""Convert SMCL text to lightweight Markdown suitable for LLM consumption."""
|
|
52
|
+
if not smcl_text:
|
|
53
|
+
return ""
|
|
54
|
+
|
|
55
|
+
# Try Rust optimization first if no complicated includes are needed
|
|
56
|
+
if not adopath or "INCLUDE help" not in smcl_text:
|
|
57
|
+
res = rust_smcl_to_markdown(smcl_text)
|
|
58
|
+
if res:
|
|
59
|
+
# Add header to match existing Python behavior
|
|
60
|
+
return f"# Help for {current_file}\n" + res
|
|
61
|
+
|
|
62
|
+
lines = smcl_text.splitlines()
|
|
63
|
+
if lines and lines[0].strip() == "{smcl}":
|
|
64
|
+
lines = lines[1:]
|
|
65
|
+
|
|
66
|
+
lines = expand_includes(lines, adopath)
|
|
67
|
+
|
|
68
|
+
title = None
|
|
69
|
+
body_parts = []
|
|
70
|
+
|
|
71
|
+
for raw in lines:
|
|
72
|
+
line = raw.strip()
|
|
73
|
+
if not line:
|
|
74
|
+
continue
|
|
75
|
+
if line.startswith("{title:"):
|
|
76
|
+
title = line[len("{title:") :].rstrip("}")
|
|
77
|
+
continue
|
|
78
|
+
# Paragraph markers
|
|
79
|
+
line = line.replace("{p_end}", "")
|
|
80
|
+
line = re.sub(r"\{p[^}]*\}", "", line)
|
|
81
|
+
body_parts.append(_inline_to_markdown(line))
|
|
82
|
+
|
|
83
|
+
md_parts = [f"# Help for {current_file}"]
|
|
84
|
+
if title:
|
|
85
|
+
md_parts.append(f"\n## {title}\n")
|
|
86
|
+
md_parts.append("\n".join(part for part in body_parts if part).strip())
|
|
87
|
+
|
|
88
|
+
return "\n\n".join(part for part in md_parts if part).strip() + "\n"
|