@maptec/cli 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +284 -0
- package/bin/maptec.js +2 -0
- package/dist/chunk-K574OFFK.js +122 -0
- package/dist/chunk-K574OFFK.js.map +1 -0
- package/dist/cli.js +899 -0
- package/dist/cli.js.map +1 -0
- package/dist/store-ZU7HLXCV.js +18 -0
- package/dist/store-ZU7HLXCV.js.map +1 -0
- package/package.json +47 -0
- package/skills/README.md +30 -0
- package/skills/jsapi-skills/README.md +60 -0
- package/skills/jsapi-skills/SKILL.md +145 -0
- package/skills/jsapi-skills/package.json +31 -0
- package/skills/jsapi-skills/references/controls.md +195 -0
- package/skills/jsapi-skills/references/events.md +222 -0
- package/skills/jsapi-skills/references/geocoding.md +184 -0
- package/skills/jsapi-skills/references/map-style.md +123 -0
- package/skills/jsapi-skills/references/map.md +154 -0
- package/skills/jsapi-skills/references/marker.md +136 -0
- package/skills/jsapi-skills/references/operate.md +138 -0
- package/skills/jsapi-skills/references/overlay.md +311 -0
- package/skills/jsapi-skills/references/place-search.md +411 -0
- package/skills/jsapi-skills/references/poi-categories.md +123 -0
- package/skills/jsapi-skills/references/popup.md +146 -0
- package/skills/jsapi-skills/references/re-geocoding.md +183 -0
- package/skills/jsapi-skills/references/routing.md +347 -0
- package/skills/jsapi-skills/references/track.md +240 -0
- package/skills/jsapi-skills/scripts/validate_jsapi_skill.py +160 -0
- package/skills/webapi-skills/README.md +73 -0
- package/skills/webapi-skills/SKILL.md +63 -0
- package/skills/webapi-skills/package.json +32 -0
- package/skills/webapi-skills/references/direction-api.md +175 -0
- package/skills/webapi-skills/references/geocoding.md +195 -0
- package/skills/webapi-skills/references/ip-location.md +87 -0
- package/skills/webapi-skills/references/matrix-api.md +149 -0
- package/skills/webapi-skills/references/nearby-search.md +223 -0
- package/skills/webapi-skills/references/places.md +239 -0
- package/skills/webapi-skills/references/quick-start-cn.md +219 -0
- package/skills/webapi-skills/references/reverse-geocoding.md +157 -0
- package/skills/webapi-skills/references/suggest.md +111 -0
- package/skills/webapi-skills/references/text-search.md +282 -0
- package/skills/webapi-skills/scripts/validate_webapi_skill.py +158 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate webapi-skills structure and public-facing guardrails."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
REQUIRED_SKILL_SECTIONS = [
|
|
12
|
+
"Workflow",
|
|
13
|
+
"API Key Setup",
|
|
14
|
+
"References",
|
|
15
|
+
"Response Guidance",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
REQUIRED_README_SECTIONS = [
|
|
19
|
+
"简介",
|
|
20
|
+
"功能列表",
|
|
21
|
+
"安装 Skill",
|
|
22
|
+
"Maptec Web Services API 接入",
|
|
23
|
+
"如何被 Agent 使用",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
REAL_KEY_PATTERNS = [
|
|
27
|
+
re.compile(r"export\s+MAPTEC_API_KEY\s*=\s*[\"'](?!YOUR_API_KEY|<你的)[A-Za-z0-9_-]{16,}[\"']"),
|
|
28
|
+
re.compile(r"Authorization:\s*Bearer\s+(?!<YOUR_API_KEY|\$MAPTEC_API_KEY)[A-Za-z0-9._-]{20,}"),
|
|
29
|
+
re.compile(r"X-API-KEY:\s*(?!your_api_key|\$MAPTEC_API_KEY)[A-Za-z0-9._-]{20,}"),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def line_of(text: str, index: int) -> int:
|
|
34
|
+
return text.count("\n", 0, index) + 1
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def check_frontmatter(skill_md: Path, text: str) -> list[str]:
|
|
38
|
+
findings: list[str] = []
|
|
39
|
+
if not text.startswith("---\n"):
|
|
40
|
+
return [f"{skill_md}:1: missing YAML frontmatter"]
|
|
41
|
+
|
|
42
|
+
end = text.find("\n---", 4)
|
|
43
|
+
if end == -1:
|
|
44
|
+
return [f"{skill_md}:1: malformed YAML frontmatter"]
|
|
45
|
+
|
|
46
|
+
frontmatter = text[4:end]
|
|
47
|
+
if not re.search(r"^name:\s*webapi-skills$", frontmatter, re.M):
|
|
48
|
+
findings.append(f"{skill_md}:1: missing or invalid name")
|
|
49
|
+
if not re.search(r"^description:\s*.{40,}$", frontmatter, re.M):
|
|
50
|
+
findings.append(f"{skill_md}:1: missing or too-short description")
|
|
51
|
+
return findings
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def find_reference_links(text: str) -> set[str]:
|
|
55
|
+
return set(re.findall(r"references/[A-Za-z0-9_.-]+\.md", text))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def check_skill_md(skill_dir: Path) -> list[str]:
|
|
59
|
+
findings: list[str] = []
|
|
60
|
+
skill_md = skill_dir / "SKILL.md"
|
|
61
|
+
if not skill_md.exists():
|
|
62
|
+
return [f"{skill_md}: missing SKILL.md"]
|
|
63
|
+
|
|
64
|
+
text = skill_md.read_text(encoding="utf-8", errors="ignore")
|
|
65
|
+
findings.extend(check_frontmatter(skill_md, text))
|
|
66
|
+
|
|
67
|
+
for section in REQUIRED_SKILL_SECTIONS:
|
|
68
|
+
if f"## {section}" not in text:
|
|
69
|
+
findings.append(f"{skill_md}:1: missing section '## {section}'")
|
|
70
|
+
|
|
71
|
+
for required in ["MAPTEC_API_KEY", "Do not invent"]:
|
|
72
|
+
if required not in text:
|
|
73
|
+
findings.append(f"{skill_md}:1: missing required guardrail '{required}'")
|
|
74
|
+
|
|
75
|
+
for ref in find_reference_links(text):
|
|
76
|
+
if not (skill_dir / ref).exists():
|
|
77
|
+
findings.append(f"{skill_md}:1: missing referenced file {ref}")
|
|
78
|
+
|
|
79
|
+
return findings
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def check_readme(skill_dir: Path) -> list[str]:
|
|
83
|
+
findings: list[str] = []
|
|
84
|
+
readme = skill_dir / "README.md"
|
|
85
|
+
if not readme.exists():
|
|
86
|
+
return [f"{readme}: missing README.md"]
|
|
87
|
+
|
|
88
|
+
text = readme.read_text(encoding="utf-8", errors="ignore")
|
|
89
|
+
for section in REQUIRED_README_SECTIONS:
|
|
90
|
+
if f"## {section}" not in text:
|
|
91
|
+
findings.append(f"{readme}:1: missing section '## {section}'")
|
|
92
|
+
|
|
93
|
+
for ref in find_reference_links(text):
|
|
94
|
+
if not (skill_dir / ref).exists():
|
|
95
|
+
findings.append(f"{readme}:1: missing referenced file {ref}")
|
|
96
|
+
|
|
97
|
+
return findings
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def check_references(skill_dir: Path) -> list[str]:
|
|
101
|
+
findings: list[str] = []
|
|
102
|
+
refs_dir = skill_dir / "references"
|
|
103
|
+
if not refs_dir.exists():
|
|
104
|
+
return [f"{refs_dir}: missing references directory"]
|
|
105
|
+
|
|
106
|
+
refs = sorted(refs_dir.glob("*.md"))
|
|
107
|
+
if not refs:
|
|
108
|
+
return [f"{refs_dir}: no reference files"]
|
|
109
|
+
|
|
110
|
+
for ref in refs:
|
|
111
|
+
text = ref.read_text(encoding="utf-8", errors="ignore")
|
|
112
|
+
if "TODO" in text:
|
|
113
|
+
findings.append(f"{ref}:1: unresolved TODO")
|
|
114
|
+
for linked_ref in find_reference_links(text):
|
|
115
|
+
if not (skill_dir / linked_ref).exists():
|
|
116
|
+
findings.append(f"{ref}:1: missing referenced file {linked_ref}")
|
|
117
|
+
|
|
118
|
+
return findings
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def check_key_leaks(skill_dir: Path) -> list[str]:
|
|
122
|
+
findings: list[str] = []
|
|
123
|
+
for path in sorted(skill_dir.rglob("*")):
|
|
124
|
+
if ".git" in path.parts or "node_modules" in path.parts or not path.is_file():
|
|
125
|
+
continue
|
|
126
|
+
if path.suffix not in {".md", ".yaml", ".yml", ".py", ".js", ".ts", ".html"}:
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
text = path.read_text(encoding="utf-8", errors="ignore")
|
|
130
|
+
for pattern in REAL_KEY_PATTERNS:
|
|
131
|
+
for match in pattern.finditer(text):
|
|
132
|
+
findings.append(f"{path}:{line_of(text, match.start())}: possible real key or bearer token")
|
|
133
|
+
return findings
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def main(argv: list[str]) -> int:
|
|
137
|
+
skill_dir = Path(argv[1]) if len(argv) > 1 else Path.cwd()
|
|
138
|
+
if not skill_dir.exists():
|
|
139
|
+
print(f"ERROR: {skill_dir} does not exist")
|
|
140
|
+
return 2
|
|
141
|
+
|
|
142
|
+
findings: list[str] = []
|
|
143
|
+
findings.extend(check_skill_md(skill_dir))
|
|
144
|
+
findings.extend(check_readme(skill_dir))
|
|
145
|
+
findings.extend(check_references(skill_dir))
|
|
146
|
+
findings.extend(check_key_leaks(skill_dir))
|
|
147
|
+
|
|
148
|
+
if findings:
|
|
149
|
+
for finding in findings:
|
|
150
|
+
print(finding)
|
|
151
|
+
return 1
|
|
152
|
+
|
|
153
|
+
print("OK: webapi-skills passes validation")
|
|
154
|
+
return 0
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
raise SystemExit(main(sys.argv))
|