@topmindspace/tms-skills 0.1.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +102 -0
  4. package/bin/tms-skills.js +160 -0
  5. package/package.json +48 -0
  6. package/top-ppt-html/README.md +254 -0
  7. package/top-ppt-html/SKILL.md +111 -0
  8. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.html +3926 -0
  9. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.model.json +168 -0
  10. package/top-ppt-html/assets/examples/2026-09-09-architecture-spectrum.html +3926 -0
  11. package/top-ppt-html/assets/examples/2026-09-09-architecture-spectrum.model.json +168 -0
  12. package/top-ppt-html/assets/examples/2026-09-09-presentation-apple-mono.html +4325 -0
  13. package/top-ppt-html/assets/examples/2026-09-09-presentation-apple-mono.model.json +321 -0
  14. package/top-ppt-html/assets/examples/2026-09-09-presentation-brand-red.html +4325 -0
  15. package/top-ppt-html/assets/examples/2026-09-09-presentation-brand-red.model.json +321 -0
  16. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.html +4325 -0
  17. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.model.json +321 -0
  18. package/top-ppt-html/assets/examples/2026-09-09-research-deep-teal.html +5527 -0
  19. package/top-ppt-html/assets/examples/2026-09-09-research-deep-teal.model.json +914 -0
  20. package/top-ppt-html/assets/examples/2026-09-09-research-indigo-violet.html +5527 -0
  21. package/top-ppt-html/assets/examples/2026-09-09-research-indigo-violet.model.json +914 -0
  22. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.html +5527 -0
  23. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.model.json +914 -0
  24. package/top-ppt-html/assets/examples/2026-09-09-research-warm-sand.html +5527 -0
  25. package/top-ppt-html/assets/examples/2026-09-09-research-warm-sand.model.json +914 -0
  26. package/top-ppt-html/assets/pptx-export.js +1944 -0
  27. package/top-ppt-html/assets/style-gallery.html +589 -0
  28. package/top-ppt-html/assets/templates/architecture.html +3728 -0
  29. package/top-ppt-html/assets/templates/engine.css +840 -0
  30. package/top-ppt-html/assets/templates/presentation.html +3738 -0
  31. package/top-ppt-html/assets/templates/research.html +4017 -0
  32. package/top-ppt-html/assets/templates/ui.js +520 -0
  33. package/top-ppt-html/assets/theme-overview-architecture.png +0 -0
  34. package/top-ppt-html/assets/theme-overview-presentation.png +0 -0
  35. package/top-ppt-html/assets/theme-overview-research.png +0 -0
  36. package/top-ppt-html/assets/theme-overview.png +0 -0
  37. package/top-ppt-html/evals/prompts.csv +15 -0
  38. package/top-ppt-html/evals/rubric.schema.json +25 -0
  39. package/top-ppt-html/evals/run_evals.py +220 -0
  40. package/top-ppt-html/evals/trace.example.json +16 -0
  41. package/top-ppt-html/package.json +35 -0
  42. package/top-ppt-html/references/charts-basic.md +624 -0
  43. package/top-ppt-html/references/charts-discipline.md +108 -0
  44. package/top-ppt-html/references/charts-extended.md +482 -0
  45. package/top-ppt-html/references/charts.md +28 -0
  46. package/top-ppt-html/references/components-atoms.md +624 -0
  47. package/top-ppt-html/references/components.md +30 -0
  48. package/top-ppt-html/references/content-rules.md +490 -0
  49. package/top-ppt-html/references/design-system-engine.md +235 -0
  50. package/top-ppt-html/references/design-system.md +478 -0
  51. package/top-ppt-html/references/failure-modes.md +214 -0
  52. package/top-ppt-html/references/high-fidelity.md +127 -0
  53. package/top-ppt-html/references/icons.md +397 -0
  54. package/top-ppt-html/references/industry-benchmark.md +105 -0
  55. package/top-ppt-html/references/infographics-stats.md +308 -0
  56. package/top-ppt-html/references/infographics-structure.md +226 -0
  57. package/top-ppt-html/references/infographics.md +43 -0
  58. package/top-ppt-html/references/layout-grammar.md +315 -0
  59. package/top-ppt-html/references/layouts-architecture.md +108 -0
  60. package/top-ppt-html/references/layouts-combo.md +600 -0
  61. package/top-ppt-html/references/layouts-research.md +160 -0
  62. package/top-ppt-html/references/modes.md +254 -0
  63. package/top-ppt-html/references/outline-design.md +275 -0
  64. package/top-ppt-html/references/playbook.md +266 -0
  65. package/top-ppt-html/references/pptx-export.md +209 -0
  66. package/top-ppt-html/references/reform-plan.md +252 -0
  67. package/top-ppt-html/references/styles.md +370 -0
  68. package/top-ppt-html/references/tech-design.md +138 -0
  69. package/top-ppt-html/scripts/audit_css.py +109 -0
  70. package/top-ppt-html/scripts/audit_docs.py +176 -0
  71. package/top-ppt-html/scripts/audit_skill.py +220 -0
  72. package/top-ppt-html/scripts/audit_styles.py +351 -0
  73. package/top-ppt-html/scripts/build_examples.py +2276 -0
  74. package/top-ppt-html/scripts/build_pptx.js +2380 -0
  75. package/top-ppt-html/scripts/capture_theme_overview.js +78 -0
  76. package/top-ppt-html/scripts/checks_html.py +127 -0
  77. package/top-ppt-html/scripts/cross_verify.py +294 -0
  78. package/top-ppt-html/scripts/env_probe.py +158 -0
  79. package/top-ppt-html/scripts/extract_model.py +210 -0
  80. package/top-ppt-html/scripts/extract_snippet.py +374 -0
  81. package/top-ppt-html/scripts/gen_channel_a.js +214 -0
  82. package/top-ppt-html/scripts/layout-constants.json +3377 -0
  83. package/top-ppt-html/scripts/layout_slots.json +830 -0
  84. package/top-ppt-html/scripts/lib_layout_regions.js +412 -0
  85. package/top-ppt-html/scripts/measure_height.py +178 -0
  86. package/top-ppt-html/scripts/model-schema.json +547 -0
  87. package/top-ppt-html/scripts/negative_tests.py +307 -0
  88. package/top-ppt-html/scripts/package_skill.py +291 -0
  89. package/top-ppt-html/scripts/prepare_images.py +341 -0
  90. package/top-ppt-html/scripts/probe_image_export.py +188 -0
  91. package/top-ppt-html/scripts/quality_gate.py +301 -0
  92. package/top-ppt-html/scripts/regression.py +308 -0
  93. package/top-ppt-html/scripts/render_compare.py +275 -0
  94. package/top-ppt-html/scripts/render_from_model.py +698 -0
  95. package/top-ppt-html/scripts/scaffold_report.py +1054 -0
  96. package/top-ppt-html/scripts/section-file-map.json +105 -0
  97. package/top-ppt-html/scripts/sync_runtime.py +662 -0
  98. package/top-ppt-html/scripts/validate_pptx.py +1510 -0
  99. package/top-ppt-html/scripts/validate_report.py +1456 -0
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """TopPPT HTML · Evals 运行器(零依赖 · 确定性检查 + 效率度量 + rubric 落地)
4
+
5
+ 用法:
6
+ python evals/run_evals.py --list # 列出 prompt 集(显式/隐式/上下文/负对照)
7
+ python evals/run_evals.py --budget # 打印效率预算
8
+ python evals/run_evals.py --score <报告.html> [--trace <trace.json>] [--json]
9
+ python evals/run_evals.py --score <报告.html> --rubric <rubric.json> # 并入定性评分
10
+
11
+ 设计依据(OpenAI《Testing Agent Skills Systematically with Evals》):
12
+ 一个 prompt → 一次被捕获的运行(trace + artifacts)→ 一小组检查 → 一个可随时间比较的分数。
13
+ 四类目标分别对应:结果(strict 0/0)· 过程(Gate 0 / 轮次)· 风格(rubric)· 效率(轮次 / 工具调用 / 读取字节)。
14
+
15
+ trace.json 格式(由宿主智能体在跑完一条 prompt 后填写;字段都可选):
16
+ {
17
+ "turns": 3, # 交互轮次
18
+ "toolCalls": 22, # 工具调用次数(读文件 + 执行脚本)
19
+ "bytesRead": 41000, # 智能体读取的总字节数
20
+ "readFiles": ["references/playbook.md", ...],
21
+ "gate0ReferenceImage": true, # 首次交互是否先给出 theme-overview 参考图
22
+ "artifacts": ["2026-09-15-主题.html"]
23
+ }
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import csv
29
+ import json
30
+ import re
31
+ import subprocess
32
+ import sys
33
+ from pathlib import Path
34
+
35
+ try:
36
+ sys.stdout.reconfigure(encoding='utf-8', errors='replace')
37
+ except Exception:
38
+ pass
39
+
40
+ ROOT = Path(__file__).resolve().parent.parent
41
+ EVALS = Path(__file__).resolve().parent
42
+ sys.path.insert(0, str(ROOT / 'scripts'))
43
+ import checks_html # noqa: E402 承载/多样性/组合版式单源
44
+
45
+ LC = json.loads((ROOT / 'scripts' / 'layout-constants.json').read_text(encoding='utf-8'))
46
+
47
+ # ── 效率预算(与 SKILL.md 的"预算(硬)"一致;audit_skill.py 校验声明存在) ──────
48
+ BUDGET = {'turns': 3, 'toolCalls': 25, 'bytesRead': 40 * 1024}
49
+
50
+ # ── 结果/风格检查(确定性部分) ────────────────────────────────────────────────
51
+ CHECK_NAMES = {
52
+ 'artifact': '产物存在且单文件零外链',
53
+ 'strict': 'validate_report --strict 0/0',
54
+ 'model': 'REPORT_MODEL 存在、合法 JSON、mode 一致',
55
+ 'variety': '图表多样性达下限(charts.variety)',
56
+ 'composite': '组合版式比例达下限(research)',
57
+ 'structure': '结构图形/信息图页型被使用(含结构类内容时)',
58
+ 'gate0': '过程:Gate 0 先给参考图',
59
+ 'efficiency': '效率:轮次 / 工具调用 / 读取字节在预算内',
60
+ }
61
+
62
+
63
+ def run_validate(html: Path) -> tuple[bool, str]:
64
+ r = subprocess.run([sys.executable, str(ROOT / 'scripts' / 'validate_report.py'), str(html), '--strict'],
65
+ capture_output=True, text=True, encoding='utf-8')
66
+ out = (r.stdout or '') + (r.stderr or '')
67
+ tail = [ln for ln in out.splitlines() if ln.startswith('PASS ') or ln.startswith('结论')]
68
+ return r.returncode == 0, (tail[-1] if tail else out[-200:])
69
+
70
+
71
+ def score_artifact(html: Path) -> dict:
72
+ checks: list[dict] = []
73
+
74
+ def add(cid: str, ok: bool, note: str) -> None:
75
+ checks.append({'id': cid, 'name': CHECK_NAMES[cid], 'ok': ok, 'note': note})
76
+
77
+ if not html.exists():
78
+ add('artifact', False, '文件不存在')
79
+ return {'artifact': str(html), 'pass': False, 'checks': checks}
80
+
81
+ txt = html.read_text(encoding='utf-8')
82
+ ext = re.findall(r'<(?:link|script|img)[^>]+(?:href|src)=["\']https?://', txt)
83
+ add('artifact', not ext, f'{len(ext)} 处外链' if ext else f'{len(txt.encode("utf-8")) / 1024:.0f}KB 单文件')
84
+
85
+ ok, note = run_validate(html)
86
+ add('strict', ok, note)
87
+
88
+ m = re.search(r'window\.REPORT_MODEL\s*=\s*(\{[\s\S]*?\})\s*;', txt)
89
+ model = None
90
+ if m:
91
+ try:
92
+ model = json.loads(m.group(1))
93
+ except json.JSONDecodeError as e:
94
+ model = None
95
+ add('model', False, f'JSON 非法: {e}')
96
+ if m and model is not None:
97
+ dm = re.search(r'<html[^>]*data-mode="([^"]+)"', txt)
98
+ consistent = (not model.get('mode')) or (not dm) or model['mode'] == dm.group(1)
99
+ add('model', consistent, f"mode={model.get('mode')} / data-mode={dm.group(1) if dm else '?'}")
100
+ elif not m:
101
+ add('model', False, '未找到 window.REPORT_MODEL')
102
+
103
+ mode = (model or {}).get('mode') or 'presentation'
104
+ per_page = checks_html.chart_types_per_page(txt)
105
+ used = checks_html.distinct_chart_types(txt)
106
+ v = checks_html.chart_variety(LC)
107
+ n_chart_pages = len([1 for ts in per_page if ts])
108
+ if used:
109
+ floor = checks_html.variety_floor(mode, n_chart_pages, v)
110
+ add('variety', len(used) >= floor, f'{len(used)} 种 / 下限 {floor}: {used}')
111
+ else:
112
+ add('variety', True, '无图表页(不适用)')
113
+
114
+ composite_ratio = checks_html.composite_required(mode, v)
115
+ if composite_ratio > 0:
116
+ multi, n_content = checks_html.composite_pages(txt)
117
+ need = max(1, int(n_content * composite_ratio))
118
+ add('composite', multi >= need, f'{multi}/{n_content} 页(下限 {need})')
119
+
120
+ # 结构图形/信息图:**只在 architecture 模式硬判**(模式 C 契约 = 图为王,必须有结构主图);
121
+ # 其余模式为**信息项**(ok=None,不计入 pass)——信息图页型族对 research/architecture 是
122
+ # "可用"而非"必须",纯演示稿/纯数据页没有结构素材,硬判会制造假阴性(属 rubric 的 C3 风格项)。
123
+ struct_types = {'sankey', 'treemap', 'boxplot', 'network', 'marimekko', 'streamgraph',
124
+ 'flow', 'tree', 'sequence', 'loop'}
125
+ has_struct = bool(set(used) & struct_types) or ('class="arch' in txt) or ('class="lane' in txt)
126
+ if mode == 'architecture':
127
+ add('structure', has_struct, '架构模式图为王:'
128
+ + ('已用结构主图' if has_struct else '未用(架构模式必须有分层带/泳道/结构图形)'))
129
+ else:
130
+ add('structure', None, '信息图/结构图形:' + ('有' if has_struct else '未使用') + '(本模式为信息项,不计入通过判定)')
131
+
132
+ return {'artifact': str(html), 'mode': mode, 'checks': checks}
133
+
134
+
135
+ def score_trace(trace_path: Path) -> dict:
136
+ t = json.loads(trace_path.read_text(encoding='utf-8'))
137
+ out = []
138
+ for key, limit in (('turns', BUDGET['turns']), ('toolCalls', BUDGET['toolCalls']),
139
+ ('bytesRead', BUDGET['bytesRead'])):
140
+ v = t.get(key)
141
+ if v is None:
142
+ out.append({'id': key, 'ok': None, 'note': '未记录'})
143
+ continue
144
+ out.append({'id': key, 'ok': v <= limit, 'note': f'{v} / 上限 {limit}'})
145
+ g0 = t.get('gate0ReferenceImage')
146
+ out.append({'id': 'gate0', 'ok': g0 if g0 is not None else None,
147
+ 'note': '首次交互给出参考图' if g0 else ('未给出参考图' if g0 is False else '未记录')})
148
+ return {'trace': str(trace_path), 'checks': out}
149
+
150
+
151
+ def main() -> int:
152
+ ap = argparse.ArgumentParser(description='TopPPT HTML Evals 运行器')
153
+ ap.add_argument('--list', action='store_true', help='列出 prompt 集')
154
+ ap.add_argument('--budget', action='store_true', help='打印效率预算')
155
+ ap.add_argument('--score', help='对一份报告产物跑确定性检查')
156
+ ap.add_argument('--trace', help='过程/效率 trace JSON')
157
+ ap.add_argument('--rubric', help='已填好的 rubric JSON(定性评分,见 rubric.schema.json)')
158
+ ap.add_argument('--json', action='store_true', help='机器可读输出')
159
+ args = ap.parse_args()
160
+
161
+ if args.list:
162
+ rows = list(csv.DictReader((EVALS / 'prompts.csv').read_text(encoding='utf-8').splitlines()))
163
+ print(f'prompt 集 {len(rows)} 条(显式 / 隐式 / 上下文 / 负对照)\n')
164
+ for r in rows:
165
+ flag = '应触发' if r['should_trigger'] == 'true' else '不应触发'
166
+ print(f" {r['id']} [{r['kind']:<8}] {flag} · {r['prompt']}")
167
+ print(f" 期望:{r['expect']}")
168
+ n_neg = sum(1 for r in rows if r['should_trigger'] != 'true')
169
+ print(f'\n负对照 {n_neg} 条(捕捉"过于急切地触发技能"的假阳性)')
170
+ return 0
171
+
172
+ if args.budget:
173
+ print('效率预算(SKILL.md 的"预算(硬)"与 audit_skill.py 同源):')
174
+ print(f" 交互轮次 ≤ {BUDGET['turns']} · 工具调用 ≤ {BUDGET['toolCalls']} · "
175
+ f"读取字节 ≤ {BUDGET['bytesRead'] // 1024}KB")
176
+ print(' 必读文件 = SKILL.md + references/playbook.md(L1);L2 深度文件按需读、读完即停')
177
+ return 0
178
+
179
+ if not args.score:
180
+ ap.print_help()
181
+ return 2
182
+
183
+ result = score_artifact(Path(args.score))
184
+ if args.trace:
185
+ result['process'] = score_trace(Path(args.trace))
186
+ if args.rubric:
187
+ result['rubric'] = json.loads(Path(args.rubric).read_text(encoding='utf-8'))
188
+
189
+ def all_ok(checks):
190
+ return all(c['ok'] for c in checks if c.get('ok') is not None)
191
+
192
+ result['pass'] = all_ok(result['checks']) and (
193
+ all_ok(result['process']['checks']) if 'process' in result else True)
194
+
195
+ if args.json:
196
+ print(json.dumps(result, ensure_ascii=False, indent=2))
197
+ return 0 if result['pass'] else 1
198
+
199
+ print(f"Eval 计分 · {result['artifact']} (mode={result.get('mode', '?')})")
200
+ print('-' * 60)
201
+ for c in result['checks']:
202
+ mark = '✓' if c['ok'] else ('·' if c['ok'] is None else '✗')
203
+ print(f" {mark} [{c['id']}] {c['name']}:{c['note']}")
204
+ if 'process' in result:
205
+ print(' ── 过程与效率 ──')
206
+ for c in result['process']['checks']:
207
+ mark = '✓' if c['ok'] else ('·' if c['ok'] is None else '✗')
208
+ print(f" {mark} [{c['id']}] {c['note']}")
209
+ if 'rubric' in result:
210
+ r = result['rubric']
211
+ print(f" ── 定性 rubric ── 总分 {r.get('score')} · {'通过' if r.get('overall_pass') else '不通过'}")
212
+ for c in r.get('checks', []):
213
+ print(f" {c.get('score'):>3} [{c.get('id')}] {c.get('notes', '')[:60]}")
214
+ print('-' * 60)
215
+ print('结论:' + ('通过' if result['pass'] else '未通过(见上方 ✗ 项)'))
216
+ return 0 if result['pass'] else 1
217
+
218
+
219
+ if __name__ == '__main__':
220
+ sys.exit(main())
@@ -0,0 +1,16 @@
1
+ {
2
+ "$comment": "trace 示例:跑完一条 prompt 后由宿主智能体填写(字段都可选)。run_evals.py --score <报告.html> --trace evals/trace.example.json 会把过程与效率一并计分。预算单源:SKILL.md「预算(硬)」= 轮次 ≤3 / 工具调用 ≤25 / 读取 ≤40KB。",
3
+ "promptId": "t02",
4
+ "turns": 3,
5
+ "toolCalls": 19,
6
+ "bytesRead": 34500,
7
+ "readFiles": [
8
+ "SKILL.md",
9
+ "references/playbook.md",
10
+ "references/components.md",
11
+ "references/charts.md"
12
+ ],
13
+ "gate0ReferenceImage": true,
14
+ "artifacts": ["2026-09-15-主题.html"],
15
+ "notes": "轻量路径:1 轮六项问询 + 1 轮交付;只读 L1 + 两份 L2;未整份读取模式模板(用 scaffold_report.py)"
16
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "top-ppt-html",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "TopPPT HTML:报告 / 演示 / 信息架构图技能。单文件 HTML + 版式保真的可编辑 PPTX;布局骨架 P1–P12;模型单写;strict 0/0 交付。",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/topmindspace/tms-skills.git",
10
+ "directory": "top-ppt-html"
11
+ },
12
+ "type": "commonjs",
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "scripts": {
17
+ "scaffold": "python scripts/scaffold_report.py",
18
+ "sync": "python scripts/sync_runtime.py",
19
+ "audit": "python scripts/audit_styles.py && python scripts/audit_docs.py && python scripts/audit_skill.py && python scripts/audit_css.py",
20
+ "capture-themes": "node scripts/capture_theme_overview.js",
21
+ "measure": "python scripts/measure_height.py",
22
+ "eval": "python evals/run_evals.py",
23
+ "build-examples": "python scripts/build_examples.py",
24
+ "regression": "python scripts/regression.py",
25
+ "negative": "python scripts/negative_tests.py",
26
+ "package": "python scripts/package_skill.py",
27
+ "check": "python scripts/package_skill.py --check"
28
+ },
29
+ "dependencies": {
30
+ "pptxgenjs": "^4.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "playwright": "^1.63.0"
34
+ }
35
+ }