@topmindspace/tms-skills 0.1.2 → 0.1.3

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/CHANGELOG.md CHANGED
@@ -1,4 +1,25 @@
1
- ## Unreleased
1
+ ## 0.1.3 — 2026-09-24
2
+
3
+ ### top-ppt-html · QA close-out + docs
4
+
5
+ - **P2-4 playbook 拆表**:意图→页型穷举 → `references/page-type-matrix.md`;图表决策表+七种误用 → `references/chart-decision-tree.md`。playbook 保留 Mode 契约 / V1–V4 / 组合 / **图表多样性摘要** / **反截断** / 路径·命令·L2 路由(体积 22KB→~17KB)。
6
+ - **版本对齐**:根 README / 技能 README / PUBLISHING / `metadata.version` / 双 `package.json` → **0.1.3**(消除残留 0.1.0 横幅)。
7
+ - **IMAGE_CAPTION**:配图页亦认 so-what/lead/figcaption;新增 WARN `IMAGE_NEAR_EMPTY`(近图过空)。
8
+ - **P2-2/P2-3**:不引入 Claude-only `when_to_use`、不写跨端风险 `allowed-tools`(`skills-ref validate` 已通过开放标准字段;扩展字段留给宿主实验)。
9
+ - **P2-5**:可选 `npx skills-ref@0.1.5 validate ./top-ppt-html`(不作为发布硬依赖;主门禁仍 `audit_skill`)。
10
+ - **docs**:根 README 安装表/钉版本/`@0.1.3`;技能 README 改为人类维护指南并指向 SKILL;package REQUIRED + MIN refs ≥25。
11
+
12
+ ### Installer
13
+
14
+ - `@topmindspace/tms-skills` → **0.1.3**(整仓同 tag)。
15
+
16
+ ### 此前 Unreleased(agent-compat,随 0.1.3 一并发布)
17
+
18
+ - **P0-1 Trigger eval**:`evals/trigger-queries.json` + `scripts/check_triggers.py`;`package_skill.py --check` 门禁。
19
+ - **P0-2 Mode A 读预算诚实**:L0+L1=2;Mode A/Fast 可加 L1.5(`default-surface` + `presentation-craft`)。
20
+ - **P0-3 反过读**:禁止整读清单 + 强制 `extract_snippet.py`。
21
+ - **P1 Frontmatter / 安装路径 / Fast 最小大纲 / 插画 brief**:license·compatibility·metadata;Cursor/Codex 路径;`illustration-layout.md`;`agents/openai.yaml`。
22
+
2
23
 
3
24
  ## 0.1.2 — 2026-09-24
4
25
 
package/README.md CHANGED
@@ -8,9 +8,9 @@
8
8
 
9
9
  | 技能 | 版本 | 做什么 |
10
10
  |------|------|--------|
11
- | [`top-ppt-html`](./top-ppt-html/) | 0.1.0 | 报告 / 演示 / 信息架构图:单文件 HTML + 版式保真的可编辑 16:9 PPTX |
11
+ | [`top-ppt-html`](./top-ppt-html/) | 0.1.3 | 报告 / 演示 / 信息架构图:单文件 HTML + 版式保真的可编辑 16:9 PPTX |
12
12
 
13
- 安装器包 [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspace/tms-skills) 亦为 **0.1.0**(与技能版本各自独立演进)。
13
+ 安装器包 [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspace/tms-skills) 亦为 **0.1.3**(整仓发版:安装器与当前技能同 tag;未来多技能仍可各自演进,默认随仓库 release)。
14
14
 
15
15
  更多技能以仓库根目录下的技能目录加入(每个目录含 `SKILL.md`)。
16
16
 
@@ -30,7 +30,7 @@
30
30
  npx @topmindspace/tms-skills list
31
31
  npx @topmindspace/tms-skills install top-ppt-html
32
32
  npx @topmindspace/tms-skills install top-ppt-html --to ./.claude/skills
33
- npx @topmindspace/tms-skills@0.1.0 install top-ppt-html # 钉版本
33
+ npx @topmindspace/tms-skills@0.1.3 install top-ppt-html # 钉版本
34
34
  ```
35
35
 
36
36
  ### GitHub 直装
@@ -48,6 +48,16 @@ node tms-skills/bin/tms-skills.js install top-ppt-html
48
48
 
49
49
  安装器把根目录下的技能目录 `<id>/`(含 `SKILL.md`)复制到目标目录;智能体通过 frontmatter(`name` + `description`)发现技能。
50
50
 
51
+ 默认探测顺序(`resolveDefaultTarget`):项目级 `./.agents` → `./.claude` → `./.cursor` → `./.codex` → `./.mimocode`;再用户级 `~/.claude` → `~/.agents` → `~/.cursor` → `~/.codex`;都没有则落 `./.agents/skills`。也可用 `--to` 显式指定。
52
+
53
+ | 宿主 | 项目级 | 用户级 |
54
+ |------|--------|--------|
55
+ | 通用 / Codex | `.agents/skills` | `~/.agents/skills` |
56
+ | Claude Code | `.claude/skills` | `~/.claude/skills` |
57
+ | Cursor | `.cursor/skills`(兼读 `.agents`) | `~/.cursor/skills` |
58
+ | Codex 兼容 | `.codex/skills` | `~/.codex/skills` |
59
+ | 本仓库另含 | `.mimocode/skills` | — |
60
+
51
61
  > **排错**:不要 `npm install <skill-id>`(技能 id 不是独立 npm 包)。「找不到包」→ 换 GitHub 直装,或 `--registry https://registry.npmjs.org/`。
52
62
 
53
63
  ### 可选依赖(仅 PPTX 精导)
package/bin/tms-skills.js CHANGED
@@ -70,12 +70,17 @@ function readSkillMeta(skillId) {
70
70
  }
71
71
 
72
72
  function resolveDefaultTarget() {
73
+ const home = process.env.HOME || process.env.USERPROFILE || '';
73
74
  const candidates = [
74
75
  path.join(process.cwd(), '.agents', 'skills'),
75
76
  path.join(process.cwd(), '.claude', 'skills'),
77
+ path.join(process.cwd(), '.cursor', 'skills'),
78
+ path.join(process.cwd(), '.codex', 'skills'),
76
79
  path.join(process.cwd(), '.mimocode', 'skills'),
77
- path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'skills'),
78
- path.join(process.env.HOME || process.env.USERPROFILE || '', '.agents', 'skills'),
80
+ path.join(home, '.claude', 'skills'),
81
+ path.join(home, '.agents', 'skills'),
82
+ path.join(home, '.cursor', 'skills'),
83
+ path.join(home, '.codex', 'skills'),
79
84
  ];
80
85
  for (const dir of candidates) {
81
86
  if (dir && fs.existsSync(path.dirname(dir))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topmindspace/tms-skills",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "TopMindspace 智能体技能 monorepo — 通过 npm / GitHub npx 安装技能(top-ppt-html 等)。",
5
5
  "license": "MIT",
6
6
  "author": "TopMindspace",
@@ -3,26 +3,21 @@
3
3
  **让 idea 飞,好想法被看见。** 一套面向 AI 智能体的商务报告生成技能:把想法、调研、分析、架构方案,变成**专业级的 HTML 报告 + 版式保真的可编辑 PPTX**。
4
4
 
5
5
  - 技能标识:`top-ppt-html`(安装/打包目录名与此一致);品牌名:**TopPPT HTML**
6
- - 版本:**v0.1.0** · 完整规范见 `SKILL.md`(智能体入口)+ `references/playbook.md`(唯一常读入口)+ `references/layout-grammar.md`(排版)+ 其余按需 L2
6
+ - 版本:**v0.1.3**(与 `@topmindspace/tms-skills@0.1.3` 同 tag)
7
+ - **智能体入口**:`SKILL.md` → `references/playbook.md`(L1)→ L2 按需
8
+ - **人类维护者**:本 README(安装 / 命令 / 目录);勿把本文件当生成规范
7
9
 
8
- ## 一、技能简介
10
+ ## 一、技能简介(人类速览)
9
11
 
10
12
  | 维度 | 能力 |
11
13
  |------|------|
12
- | 产出物 ① | **单文件 HTML 报告**:零外链、可翻页(方向键整屏翻页)、**每页一屏的稳定页高**、亮暗双主题(记忆按文件隔离)、header 自带工具栏(主题/9 风格实时切换/PPTX WYSIWYG 预览/可复制 AI 提示词/全屏 F/收起工具栏 B) |
13
- | 产出物 ② | **16:9 可编辑 PPTX**:全原生形状/文本框/表格(默认 `pictures=0`;模型显式声明 `section.image` 时按声明数导出素材图片,六版式 full/half/bleed/grid/compare/wall 与 HTML 同比例;无素材时出**原生配图占位框**——可编辑、`pictures` 不增),三模式独立排版比例尺 + **29 种页型**,带数据的图表为**原生数据图表**(双击"编辑数据"),非原生图表**附数据表**(备注/页内表格),口径自动写入演讲者备注,按所选主题导出亮色版或深色版 |
14
- | 三种模式 | A 演示汇报(大字每屏一主张,8–15 页)/ B 研究报告(咨询密排:行动标题 + Exhibit 编号 + 双三栏 + 密表 + 矩阵,12–25 页)/ C 信息架构图(图为王:全幅分层带/泳道/管线,1–3 张图成篇) |
15
- | 9 套风格 | 商务蓝(默认)/ 优雅黑白 / 麦肯锡 / 品牌红 / 暖沙金 / 墨绿 / 石墨深灰(深色优先)/ 靛紫 / 光谱彩色——与模式、主题正交组合;**每套风格各有自己的编码色板 c1–c5**(`styleDataColors` 单源,双引擎消费),多系列图表在任何风格下都可辨。**刻意不再扩张**:新增门槛(新色族 + 新语汇 + 场景缺口)见 `references/styles.md` §10 |
16
- | 复杂信息图 | 桑基 / 树图 / 箱线 / 关系网络 / 马赛克 / 流带 六类专属页型:曲线采样点 ≥16(流带 ≥24)、双边界分别追踪、禁预设形状替代;每页一图,数据表可追溯 |
17
- | 强调带 | 收尾/CTA 用 `band--accent`(软强调)、金句用 `band--accent--solid`(实底)——**浅色模式不再出现深色收尾页**;`band--deep` 仅显式反相页(≤1 处、不作末页) |
18
- | 待核实标注 | `.tbd` 内联标色 + `.tbd-legend`/`.flagbar` 说明——无法核实的数字/判断用**强调色**标出,提示用户二次修改(PPTX 同源 + 演讲者备注) |
19
- | 素材图片 | **六版式**:full 版心全宽 3:1 / half 左图右注 4:3 / bleed 通栏出血 21:9 / grid 多图网格 4:3(2·3·4·6 张)/ compare 双图 A/B / wall Logo 墙;比例由 `imageSpec` 单源锁定(HTML 用 `.media--r*` 类、PPTX 用同一比例算高度并居中)——**两通道比例一致**;`src` 仅 data: 内联或相对路径;PPTX 声明式放行 |
20
- | 配图占位 | 无素材时不省略图也不塞无关图:`.media--ph`(虚线框 + 斜纹 + 图标 + 尺寸提示)+ 模型 `image.placeholder` → PPTX 出**原生圆角矩形占位框**(可编辑、`pictures` 不增),交付前替换 `src` 即可;预览模态会把图位替换成真实图片 |
21
- | 用户图片准备 | `scripts/prepare_images.py <图片\|目录> --layout full\|half\|grid…`:读尺寸/格式/体积 → 按版式建议尺寸缩放压缩(有 Pillow 时)→ 自动选 data: 内联或相对路径 → 产出可粘贴的 `.media` HTML 片段与 `image` 模型对象 |
22
- | 36 种图表 | 环形 / 多段环形 / 饼图 / 柱状 / 堆叠 / 100% 堆叠条 / 折线 / 双折线 / 面积 / 横向条形 / 双向条形 / 雷达 / 仪表盘 / 玫瑰 / 瀑布 / 漏斗 / 甘特 / 散点 / 气泡 / 矩形树图 / 马赛克 / 进度条组 / 迷你趋势线 / 桑基 / 斜率 / 哑铃 / 棒棒糖 / 点图 / 子弹图 / 华夫 / 箱线 / 帕累托 / 径向条 / 流图 / K 线 / 关系网络(全内联 SVG,随主题与风格变色;**16 类走 PPTX 原生图表,其余形状还原 + 数据表**) |
23
- | 按需深度模式 | 命中「高保真/1:1/精确还原/正式交付」或含复杂信息图时自动升级:`--deep` 把连续文本流与空间锚点纳入 strict,`--emit-manifest` 产出锚点/容器/数据表/图表通道/图片资产登记,`render_compare.py` 准备渲染对照材料(缺依赖自动跳过) |
24
- | 质量闭环 | `validate_report.py`(HTML strict 全 PASS,含强调带约束/待核实标注/素材图片与配图占位/图表数据表策略)+ `validate_pptx.py --strict`(0 错误 0 警告,含容器级溢出/表格语义字号与密度/未声明图片硬拦/图片版式·裁切·多图数量·相对路径文件存在性)+ WCAG 对比度与单源完整性审计 + 双通道回归双裁判 + 素材图片导出探针 |
25
- | 设计标准 | Material Design 3 对齐(克制执行);研究模式对齐咨询机构实践 |
14
+ | 产出 | 单文件 HTML(可翻页、亮暗双主题、header 工具栏)+ 16:9 可编辑 PPTX(精导通道) |
15
+ | 三模式 | A 演示 · B 研究 · C 架构(页型/字号/密度契约见 `playbook.md` §一) |
16
+ | 风格 | 9 套(`styles.md`);编码色板 c1–c5 随风格 |
17
+ | 图表 | 核图 8 默认 + registry 全量;多样性 / 反截断 / Mode A 工艺见 playbook + `presentation-craft.md` |
18
+ | 质量 | `validate_report --strict`(A 隐含 layout-qa)· `validate_pptx --strict` · `quality_gate --deliver` |
19
+
20
+ 生成规范、页型/图表穷举、铁律 **不在本文件**——智能体读 `SKILL.md` / playbook;选型大表见 `page-type-matrix.md` / `chart-decision-tree.md`。
26
21
 
27
22
  **核心架构**:HTML 与 PPTX 出自同一内容模型 `window.REPORT_MODEL`(唯一事实源);页面只预览不导出,PPTX 由智能体走「精导通道」生成(extract → build → strict 校验)。阈值与几何全部单源化:`scripts/layout-constants.json`(常量)+ `scripts/model-schema.json`(页型 DSL)。
28
23
 
@@ -48,6 +43,16 @@ node tms-skills/bin/tms-skills.js install top-ppt-html
48
43
 
49
44
  > **GitHub 更新不会自动进 npm。** 日常可钉 npm 版本;要最新技能用 GitHub 直装,或等 maintainer 打 tag 发版。
50
45
  >
46
+
47
+ ### 触发词回归(维护者)
48
+
49
+ ```bash
50
+ python3 scripts/check_triggers.py # keyword/heuristic vs SKILL description
51
+ # 扩展:编辑 evals/trigger-queries.json(how_to_extend)
52
+ ```
53
+
54
+ `package_skill.py --check` 会自动跑 trigger coverage。
55
+
51
56
  > 「找不到这个包」→ 换 GitHub 直装,或 `--registry https://registry.npmjs.org/`(镜像索引可能滞后)。不要 `npm install top-ppt-html`(技能 id 不是独立 npm 包)。
52
57
 
53
58
  也可将本目录(或 GitHub Release 附件 `top-ppt-html.zip` 解压结果)复制到智能体技能目录,目录名保持 `top-ppt-html`。技能识别面为 `SKILL.md`(frontmatter 的 `name` / `description` 即触发描述)。
@@ -106,9 +111,12 @@ top-ppt-html/
106
111
  │ ├─ infographics.md # 铁律与边界(逻辑入口);代码已拆分见下两行 │
107
112
  │ ├─ infographics-stats.md # 统计图形族 §1–§6 / §71–§77 │
108
113
  │ ├─ infographics-structure.md # 结构图形族 §78–§82 │
114
+ │ ├─ page-type-matrix.md # L2 意图→页型穷举(playbook §三 速记) │
115
+ │ ├─ chart-decision-tree.md # L2 图表决策表+误用(playbook §五 摘要) │
116
+ │ ├─ illustration-layout.md # L2 插画/配图 brief │
109
117
  │ └─ …(modes / styles / design-system / content-rules / icons / default-surface / │
110
- │ outline-design / pptx-export / high-fidelity / │
111
- │ failure-modes / tech-design;归档见 docs/archive/refs/) │
118
+ │ outline-design / pptx-export / high-fidelity / failure-modes / tech-design; │
119
+ │ 归档见 docs/archive/refs/) │
112
120
  ├─ evals/ # Eval 框架(结果/过程/风格/效率四类目标) │
113
121
  │ ├─ prompts.csv # 14 条 prompt(显式/隐式/上下文/负对照) │
114
122
  │ ├─ rubric.schema.json # 风格目标结构化评分契约 │
@@ -145,18 +153,23 @@ python scripts/package_skill.py --check
145
153
  python scripts/audit_skill.py && python scripts/audit_docs.py
146
154
  python scripts/audit_styles.py && python scripts/audit_css.py
147
155
  python scripts/negative_tests.py
156
+ python scripts/check_triggers.py
157
+ # 可选第三方:npx --yes skills-ref@0.1.5 validate .
148
158
  ```
149
159
 
150
160
  ## 目录要点
151
161
 
152
162
  | 路径 | 用途 |
153
163
  |------|------|
154
- | `SKILL.md` | L0 路由(≤13KB) |
155
- | `references/playbook.md` | L1 决策层 |
156
- | `references/default-surface.md` | Mode A 主读:12 页型 + 核图 8 + V1–V4;主力骨架 P1–P4+P6/P10 |
164
+ | `SKILL.md` | L0 路由(≤13KB);智能体唯一入口 |
165
+ | `references/playbook.md` | L1 决策层(Mode / 路径 / V1–V4 / 组合 / 多样性摘要 / 命令 / 路由) |
166
+ | `references/page-type-matrix.md` | L2 页型穷举表 |
167
+ | `references/chart-decision-tree.md` | L2 图表决策树 + 七种误用 |
168
+ | `references/default-surface.md` | Mode A L1.5:12 页型 + 核图 8 + V1–V4 |
169
+ | `references/presentation-craft.md` | Mode A L1.5 工艺(反截断 / 大气正式) |
157
170
  | `assets/examples/` | 3 份黄金样张(每模式 1) |
158
- | `assets/style-gallery.html` | 9 风格 × 模式 × 亮暗 |
159
- | `docs/archive/` | 历史规范 / 旧示例 / 全量 build_examples |
171
+ | `evals/trigger-queries.json` | description 触发正/负例;`check_triggers.py` |
172
+ | `docs/archive/` | 历史规范 / 旧示例 |
160
173
 
161
174
  风格画廊与主题参考图:`assets/theme-overview*.png`(Gate 0)。完整规范索引见 playbook §十。
162
175
 
@@ -1,8 +1,12 @@
1
1
  ---
2
2
  name: top-ppt-html
3
- description: "TopPPT HTML:报告 / 演示 / 信息架构图生成器。单文件零外链 HTML(可翻页、亮暗双主题)+ 版式保真的原生可编辑 16:9 PPTX。三模式(A 演示·每屏一主张 / B 研究·咨询密排 / C 架构·图为王)× 9 风格;布局骨架 P1–P12;内容只填 REPORT_MODEL,render_from_model 回填正文;strict 0/0 才交付。Use when 用户要做报告、演示、汇报、PPT、slides、deck、路演,或写研究报告、分析报告、咨询报告、白皮书、调研、评测、对标、经营分析、复盘、项目汇报、商务/HTML/网页报告,或做架构图、拓扑图、流程图、泳道图、方案图,或把材料/数据做成可视化报告,或导出 HTML/PPT/PPTX(保真、可编辑、高保真、1:1),或优化排版、版式、配色、密度、图文布局,或要快速模式/fast/直接生成/一键出稿/少问一句。Do NOT use for 纯代码工程、非报告类网页或应用开发、视频/图片生成、直接改写已有 Word/PPT 源文件本身。"
3
+ description: "Use when 用户要做报告、演示、汇报、PPT、slides、deck、路演,或写研究报告、分析报告、咨询报告、白皮书、调研、评测、对标、经营分析、复盘、项目汇报、商务/HTML/网页报告,或做架构图、拓扑图、流程图、泳道图、方案图,或把材料做成可视化报告并导出 HTML/PPT/PPTX,或优化排版/版式/配色/图文布局,或要快速模式/fast/直接生成/一键出稿/少问一句。TopPPT HTML:零外链可翻页 HTML(亮暗双主题)+ 版式保真可编辑 16:9 PPTX;三模式(A 演示·每屏一主张 / B 研究·咨询密排 / C 架构·图为王)× 9 风格。Do NOT use for 纯代码工程、非报告类网页或应用开发、视频/图片生成、直接改写已有 Word/PPT 源文件本身。"
4
+ license: MIT
5
+ compatibility: "Python 3 stdlib for HTML generation; Node >=18 + pptxgenjs for PPTX; optional playwright for browser regression / theme captures."
6
+ metadata:
7
+ version: "0.1.3"
8
+ author: TopMindspace
4
9
  ---
5
-
6
10
  # TopPPT HTML
7
11
 
8
12
  **让 idea 飞,好想法被看见。** 一套技能、三种模式、两种交付:**单文件 HTML 报告**(可翻页、可演示、header 自带工具栏)+ **版式保真的原生可编辑 PPTX**(智能体精导唯一交付通道)。两者同源于一个内容模型 `REPORT_MODEL`。设计对齐 Material Design 3,执行克制(Google/Apple 风);研究模式对齐咨询机构(McKinsey/BCG)的密度与论证结构,但**克制优先**——不加多余的页头标签、页脚信息与装饰。
@@ -32,7 +36,7 @@ description: "TopPPT HTML:报告 / 演示 / 信息架构图生成器。单文
32
36
  | 篇幅 | A=10 / B=12 / C=6 | |
33
37
  | format | html only(用户要 PPT→html+pptx) | |
34
38
 
35
- 流程:一行宣布「Fast 选用:…」→ 走 playbook §二轻量命令链(骨架→模型单写→回填→strict→`quality_gate --deliver`;可选 pptx)。路径永远轻量;回复末可附 `assets/style-gallery.html`。开场须声明「已跳过参考图」。**标准模式**仍强制 Gate 0 + 六项。
39
+ 流程:一行宣布「Fast 选用:…」→ **最小大纲**(`outline-design.md`「轻量最小集」)→ playbook §二轻量链(骨架→模型单写→回填→strict→`quality_gate --deliver`;可选 pptx)。路径轻量;末可附 `assets/style-gallery.html`。开场声明「已跳过参考图」。**标准模式**仍强制 Gate 0 + 六项。
36
40
 
37
41
  ## 唯一入口流程
38
42
 
@@ -42,7 +46,7 @@ description: "TopPPT HTML:报告 / 演示 / 信息架构图生成器。单文
42
46
  (命令链见 playbook §二/§九;PPTX 见 pptx-export)
43
47
  ```
44
48
 
45
- **预算(硬)**:交互轮次 **≤3**;默认必读仅 2 份——本文件 + L1 决策层 `references/playbook.md`;L2 深度文件命中才读、读一份用一份、不预读。
49
+ **预算(硬)**:交互轮次 **≤3**;**L0+L1 共 2 份**(本文件 + `playbook.md`)。**Mode A/Fast**可加 L1.5:`default-surface.md`+`presentation-craft.md`(非违约)。其余 L2 命中才读、不预读。
46
50
 
47
51
  ## 六项问询(标准模式 · 一次问完 · 唯一一次形式参数确认)
48
52
 
@@ -61,7 +65,7 @@ description: "TopPPT HTML:报告 / 演示 / 信息架构图生成器。单文
61
65
 
62
66
  | 路径 | 何时 | 多做什么 |
63
67
  |------|------|---------|
64
- | **轻量**(默认) | 页数不多、材料单一完整、关键判断已敲定 | 仅 1 张规划卡,直接生成 |
68
+ | **轻量**(默认) | 页数不多、材料单一完整、关键判断已敲定 | 最小大纲→1 张规划卡(`outline-design.md`「轻量最小集」) |
65
69
  | **完整** | 长篇、材料量大且杂、含未敲定关键判断、用户要看框架 | 证据盘点 → 故事线 → 主张树 → 逐页规划卡 → 大纲确认(1 轮) |
66
70
 
67
71
  两条路径的**精确判定条件与完整步骤以 `references/playbook.md` §二为准**。完整路径确认只做一次,用户说"调整"只改指定处;确认后不再有内容层面的反复确认。
@@ -85,16 +89,16 @@ description: "TopPPT HTML:报告 / 演示 / 信息架构图生成器。单文
85
89
  **L2 一览**(命中条件与逐任务只读清单的**详表以 playbook §十为准**,此处仅索引):
86
90
 
87
91
  - 模式契约与锁定版式 → `references/modes.md` · 完整路径七步 → `references/outline-design.md`
88
- - **A/Fast 主读 → `references/default-surface.md`** + **`presentation-craft.md`** · 骨架分层见 `layout-grammar.md` §七
89
- - 组件/版式**代码** → `components.md` · 图表门面 `charts.md`(纪律+核图;extended 按需取节)· 信息图 → `infographics.md`
92
+ - **A/Fast L1.5 → `default-surface.md` + `presentation-craft.md`** · 骨架 `layout-grammar.md` §七 · 插画 `illustration-layout.md`
93
+ - 组件/版式**代码** → `components.md` · 页型表 `page-type-matrix.md` · 图表门面 `charts.md` + 决策树 `chart-decision-tree.md`(extended 按需)· 信息图 → `infographics.md`
90
94
  - 配色/主题/字阶 → `styles.md` + `design-system.md` · 写作 → `content-rules.md` · 图标语义 → `icons.md`
91
95
  - PPTX 精导 → `references/pptx-export.md` · 深度高保真 → `references/high-fidelity.md` · 修复顺序 → `references/failure-modes.md` · 技能维护 → `references/tech-design.md`
92
96
 
93
- **操作方式**:定模式/页型/组合/图 → 只读 `playbook.md`;取代码 → `extract_snippet.py`;**禁止整读** `layouts-combo.md` / `charts-basic.md` 等大文件;**同一阶段不重复读同一文件**。
97
+ **操作方式**:定模式/页型/组合/图 → 只读 `playbook.md`;取代码 → **必须** `extract_snippet.py`。**禁止整读**:`layouts-combo` / `components-atoms` / `charts-basic` / `charts-extended` / `content-rules` 全文 / `pptx-export` / 模式模板 HTML(走 scaffold)。详表 playbook §十。同阶段不重读。
94
98
 
95
99
  ## 铁律(12 条 · 交付硬门禁)
96
100
 
97
- > 门禁语义;阈值见 playbook / layout 常量 JSON。排版读 `layout-grammar.md`。**motion=none**(无炫技转场;见 `presentation-craft.md`)。
101
+ > 门禁语义;阈值见 playbook / layout 常量 JSON。排版读 `layout-grammar.md`。**motion=none**(无炫技转场;`presentation-craft.md`)。
98
102
 
99
103
  1. **单文件零外链**——无 CDN/外部字体/外部图片,图形一律内联 SVG;`<img src>` 仅 `data:` 或相对路径且必带 `alt`(单图 ≤1.5MB、全篇 ≤8MB);无素材图不留空不省略,用配图占位(`components.md` §11c-3)。
100
104
  2. **模式先定后写**——从对应模式模板起步;`data-mode` = `REPORT_MODEL.mode`,页面无模式切换;MD3 映射;PPTX 字号走三模式独立比例尺。
@@ -0,0 +1,5 @@
1
+ # Codex / ChatGPT Skills UI metadata (optional)
2
+ display_name: "TopPPT HTML"
3
+ short_description: "Reports, decks, and architecture diagrams as single-file HTML + editable 16:9 PPTX."
4
+ default_prompt: "Generate a professional presentation or research report as HTML (and optional PPTX)."
5
+ allow_implicit_invocation: true
@@ -0,0 +1,181 @@
1
+ {
2
+ "version": 1,
3
+ "skill": "top-ppt-html",
4
+ "description": "Keyword/heuristic trigger coverage against SKILL.md frontmatter description. Not an LLM eval — CI gates regressions when trigger keywords drift.",
5
+ "how_to_extend": [
6
+ "Add a positive query that should select this skill (报告/路演/PPT/HTML/调研…).",
7
+ "Add a negative query that must NOT select it (coding/video/edit-existing-pptx…).",
8
+ "Each entry: {id, query, expect: 'hit'|'miss', notes?}",
9
+ "Runner: python3 scripts/check_triggers.py — matches query tokens against description keywords extracted from SKILL.md.",
10
+ "Wire: package_skill.py --check invokes check_triggers; also npm run check."
11
+ ],
12
+ "positive": [
13
+ {
14
+ "id": "P01",
15
+ "query": "帮我做一份季度经营分析报告",
16
+ "expect": "hit"
17
+ },
18
+ {
19
+ "id": "P02",
20
+ "query": "明天路演用的融资 PPT,10页左右",
21
+ "expect": "hit"
22
+ },
23
+ {
24
+ "id": "P03",
25
+ "query": "生成一份可翻页的 HTML 演示文稿",
26
+ "expect": "hit"
27
+ },
28
+ {
29
+ "id": "P04",
30
+ "query": "把调研材料做成 slides deck",
31
+ "expect": "hit"
32
+ },
33
+ {
34
+ "id": "P05",
35
+ "query": "写一份麦肯锡风格的对标分析研究报告",
36
+ "expect": "hit"
37
+ },
38
+ {
39
+ "id": "P06",
40
+ "query": "项目复盘汇报 PPTX,要能编辑",
41
+ "expect": "hit"
42
+ },
43
+ {
44
+ "id": "P07",
45
+ "query": "画一张系统架构拓扑图,图为王",
46
+ "expect": "hit"
47
+ },
48
+ {
49
+ "id": "P08",
50
+ "query": "泳道流程图 + 方案说明页",
51
+ "expect": "hit"
52
+ },
53
+ {
54
+ "id": "P09",
55
+ "query": "白皮书大纲做成网页报告",
56
+ "expect": "hit"
57
+ },
58
+ {
59
+ "id": "P10",
60
+ "query": "评测报告可视化,导出 HTML 和 PPT",
61
+ "expect": "hit"
62
+ },
63
+ {
64
+ "id": "P11",
65
+ "query": "商务汇报用的一页一主张演示",
66
+ "expect": "hit"
67
+ },
68
+ {
69
+ "id": "P12",
70
+ "query": "快速模式一键出稿,少问一句",
71
+ "expect": "hit"
72
+ },
73
+ {
74
+ "id": "P13",
75
+ "query": "fast mode generate a pitch deck",
76
+ "expect": "hit"
77
+ },
78
+ {
79
+ "id": "P14",
80
+ "query": "咨询报告:发现、证据、so-what",
81
+ "expect": "hit"
82
+ },
83
+ {
84
+ "id": "P15",
85
+ "query": "优化这份报告的排版版式和配色密度",
86
+ "expect": "hit"
87
+ },
88
+ {
89
+ "id": "P16",
90
+ "query": "把数据做成可视化经营分析 deck",
91
+ "expect": "hit"
92
+ },
93
+ {
94
+ "id": "P17",
95
+ "query": "发布会演讲 PPT,亮暗双主题",
96
+ "expect": "hit"
97
+ },
98
+ {
99
+ "id": "P18",
100
+ "query": "行业调研 + 对标分析 HTML 报告",
101
+ "expect": "hit"
102
+ },
103
+ {
104
+ "id": "P19",
105
+ "query": "直接生成项目汇报 slides",
106
+ "expect": "hit"
107
+ },
108
+ {
109
+ "id": "P20",
110
+ "query": "高保真 1:1 导出可编辑 PPTX",
111
+ "expect": "hit"
112
+ },
113
+ {
114
+ "id": "P21",
115
+ "query": "做个信息架构图和分层带",
116
+ "expect": "hit"
117
+ },
118
+ {
119
+ "id": "P22",
120
+ "query": "董事会汇报材料,正式演示风格",
121
+ "expect": "hit"
122
+ }
123
+ ],
124
+ "negative": [
125
+ {
126
+ "id": "N01",
127
+ "query": "帮我写一个 React 组件库并跑单测",
128
+ "expect": "miss"
129
+ },
130
+ {
131
+ "id": "N02",
132
+ "query": "debug 这段 Python 报错",
133
+ "expect": "miss"
134
+ },
135
+ {
136
+ "id": "N03",
137
+ "query": "生成一段产品宣传视频脚本并渲染成 mp4",
138
+ "expect": "miss"
139
+ },
140
+ {
141
+ "id": "N04",
142
+ "query": "用 Midjourney 生成一张产品海报图",
143
+ "expect": "miss"
144
+ },
145
+ {
146
+ "id": "N05",
147
+ "query": "直接改这个已有的 pptx 里第三页的字号",
148
+ "expect": "miss"
149
+ },
150
+ {
151
+ "id": "N06",
152
+ "query": "打开 Word 文档把第二段改成被动语态",
153
+ "expect": "miss"
154
+ },
155
+ {
156
+ "id": "N07",
157
+ "query": "搭建一个电商官网前端,不要报告",
158
+ "expect": "miss"
159
+ },
160
+ {
161
+ "id": "N08",
162
+ "query": "给我写 SQL 迁移脚本",
163
+ "expect": "miss"
164
+ },
165
+ {
166
+ "id": "N09",
167
+ "query": "配置 nginx 反向代理",
168
+ "expect": "miss"
169
+ },
170
+ {
171
+ "id": "N10",
172
+ "query": "把这段代码 refactor 成 TypeScript",
173
+ "expect": "miss"
174
+ },
175
+ {
176
+ "id": "N11",
177
+ "query": "剪辑这段会议录像加字幕",
178
+ "expect": "miss"
179
+ }
180
+ ]
181
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "top-ppt-html",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": true,
5
5
  "description": "TopPPT HTML:报告 / 演示 / 信息架构图技能。单文件 HTML + 版式保真的可编辑 PPTX;布局骨架 P1–P12;模型单写;strict 0/0 交付。",
6
6
  "license": "MIT",
@@ -24,7 +24,8 @@
24
24
  "regression": "python3 scripts/regression.py",
25
25
  "negative": "python3 scripts/negative_tests.py",
26
26
  "package": "python3 scripts/package_skill.py",
27
- "check": "python3 scripts/package_skill.py --check"
27
+ "check": "python3 scripts/package_skill.py --check",
28
+ "triggers": "python3 scripts/check_triggers.py"
28
29
  },
29
30
  "dependencies": {
30
31
  "pptxgenjs": "^4.0.0"
@@ -0,0 +1,42 @@
1
+ # 图表选型决策树(L2)
2
+
3
+ > **何时读**:选图 / 分析意图→图型;常读入口仍是 `playbook.md` §五(核图 8 + 多样性摘要)。读完即停。
4
+ > 完整登记与代码 → `extract_snippet.py --chart <类型>`;误用纪律 → `charts.md`(先 `charts-discipline`,核图 8,extended 按需)。
5
+
6
+ ## 决策表
7
+
8
+ | 分析意图(读者要得出的结论) | 首选 | 次选 | 禁用 / 改判条件 |
9
+ |---------------------------|------|------|----------------|
10
+ | 谁大谁小 | `hbar` | `lollipop` / `bar` | 类别 >8 → Top7 + 附录 |
11
+ | 随时间怎么变 | `line` | `area` / `dualline` | 时间点 >8 不标点值 |
12
+ | 占比是多少 | `donut` | `pie` / `multidonut` | 扇区 >5 → 合并"其他"或 `treemap` |
13
+ | 每 1% 的直觉 | `waffle` | `donut` | 类别 >3 改 `marimekko` |
14
+ | 结构在变形 | `streamgraph` | `stackline` | 系列 >6 合并 |
15
+ | 总量 × 构成双编码 | `marimekko` | `treemap` | 列 >6 / 段 >4 → 拆 |
16
+ | 份额悬殊(头部集中) | `treemap` | `donut` | 叶 >16 → 合并小项 |
17
+ | 从 A 到 B 是谁贡献的 | `waterfall` | `pareto` | 段 >6 → 合并 |
18
+ | 主要矛盾是哪几个 | `pareto` | `waterfall` | 类别 >7 → 合并 |
19
+ | 转化/流失在哪一环 | `funnel` | `sankey` | 层 >5 → 改 `hbar` |
20
+ | 多对多的流向 | `sankey` | `network` | 节点 >12 / 流带 >24 → 拆页 |
21
+ | 谁和谁相连 | `network` | `diagram` | 节点 >18 / 边 >30 → 拆页 |
22
+ | 两期谁升谁降 | `slope` | `dumbbell` | 系列 >6 → 取 Top 6 |
23
+ | 单指标前后对比(多对象) | `dumbbell` | `vsbar` | 行 >6 → 拆页 |
24
+ | 实际 vs 目标(含区间) | `bulletchart` | `bullet` | 行 >6 → 拆页 |
25
+ | 达成率(多指标同心) | `radialbar` | `gauge` | 环 >5 → 改 `bullet` |
26
+ | 一个值够不够 | `gauge` | `radialbar` | 单值叙事,勿与图并存 |
27
+ | 分布不是均值 | `boxplot` | `dotplot` | 组 >8 → 拆页 |
28
+ | 双维定位 + 第三维权重 | `bubble` | `scatter` | 气泡 >8 → 标注关键项 |
29
+ | 六维能力画像 | `radar` | `rose` | 维度 >6 → 拆两组 |
30
+ | 区间波动(开高低收) | `candlestick` | `line` | 蜡烛 >12 → 聚合 |
31
+ | 多项目完成度 | `progress` | `bullet` | 行 >6 → 拆页 |
32
+ | 迷你趋势(卡内) | `sparkline` | — | 只用于指标卡,不与大图并存 |
33
+
34
+ ## 七种最常见的误用(出现即改判)
35
+
36
+ 1. 用 `bar` 表达占比 → 改 `donut`/`stackline`/`waffle`。
37
+ 2. 用 `donut` 表达 8 个类别 → 合并或改 `treemap`。
38
+ 3. 用 `line` 表达类别对比(无时间轴)→ 改 `hbar`。
39
+ 4. 用 `table` 表达趋势 → 改 `line`/`area`。
40
+ 5. 用均值型图表表达分布 → 改 `boxplot`/`dotplot`。
41
+ 6. 同一页放两张同型图 → 改 `split`/`halftable` 并让两图**编码不同维度**。
42
+ 7. 多系列图用单色明度阶梯(分不清) → 用 `f-c1~c5` 编码色板(见 playbook §八)。
@@ -1,6 +1,6 @@
1
1
  # 默认生成面(L1.5 · Mode A 主读 · ≤6KB)
2
2
 
3
- > **Mode A / Fast 演示的首要读面**(正式场合 · 大气演讲)。完整决策见 `playbook.md`;工艺清单见 `presentation-craft.md`;代码用 `extract_snippet.py`。
3
+ > **Mode A / Fast 演示的首要读面**(正式场合 · 大气演讲)。完整决策见 `playbook.md`;工艺清单见 `presentation-craft.md`;插画/配图见 `illustration-layout.md`;代码用 `extract_snippet.py`。
4
4
  > Mode B/C 能力保留——**需要时**再读 modes / layouts-*;勿把密排/架构默认反向污染 A。
5
5
 
6
6
  ## A 默认三件套
@@ -59,3 +59,4 @@ scaffold_report → 只填 REPORT_MODEL → render_from_model --inplace
59
59
  ## 长文与密度(Mode A)
60
60
 
61
61
  一屏一主张;证据用卡/列表或跟进页。**禁止**为稀疏 demo 感删实质。溢出顺序:重构 → 拆页 → 换 V/栅格 → 有限 fontShrink。详见 `presentation-craft.md`「长文与信息承载」。
62
+ 配图/插画页:caption+so-what、安全边距、勿与大图双重心——`illustration-layout.md`。
@@ -0,0 +1,39 @@
1
+ # 插画 / 非数据配图 brief(L2 · ≤4KB)
2
+
3
+ > **何时读**:页含情绪图 / 产品图 / 截图 / 示意图 / `image.placeholder`;或 Mode A 需要 full-bleed 照片+主张叠字。
4
+ > **何时不读**:纯数据图表选型(走 playbook §五 / `charts.md`)。
5
+ > **取码**:`extract_snippet.py --task image-layout`(`components.md` §11c);勿整读 `components-atoms.md`。
6
+
7
+ ## 配图 vs 数据图(互斥优先)
8
+
9
+ | 意图 | 用什么 | 不要 |
10
+ |------|--------|------|
11
+ | 趋势 / 构成 / 对比 / 排名 | 数据图(核图 8 优先) | 用照片代替数据 |
12
+ | 氛围 / 品牌 / 产品外观 / UI 截图 | `<img>` / `.media` / `image.placeholder` | 硬画假图表 |
13
+ | 无素材但仍需图位 | `image.placeholder` + `.media--ph` | 留空或塞无关图 |
14
+
15
+ **一页一主视觉**:同页不要「大照片 + 大图表」双重心(FAIL 级审美风险);icon 可点缀,chart 占主位时照片改小或拆页。
16
+
17
+ ## 版式与安全边距
18
+
19
+ - **安全边距**:距版心边缘 ≥ 24px(演示投影更宽松);文字不得压在图片关键焦点上。
20
+ - **图文共存**:半幅图(half)→ 图左/上 + 注右/下;注含 **caption(图注)+ so-what(含义一句)**。
21
+ - **不重叠**:标题 / 标签 / 图例不得与照片主体或 icon 碰撞;必要叠字用半透明底或高对比条。
22
+ - **icon + chart**:icon 在注释列或卡眉,不进 SVG 绘图区;每屏 icon 仍 3–8。
23
+
24
+ ## Mode A · full-bleed 照片 + 主张叠字
25
+
26
+ 1. 仅用于封面 / 章节幕 / 金句休止 / 收尾 —— **不做证据页**。
27
+ 2. 主张句叠在照片暗侧或统一遮罩条上;对比度满足 WCAG(正文感 ≥4.5:1)。
28
+ 3. `layout: bleed` + 安全区内 claim;勿在 bleed 页再塞密表/多卡。
29
+ 4. 必须有 **caption 或来源/版权**(可沉 `.fig__cap` / footnote);证据含义用跟进页,不塞进 bleed。
30
+
31
+ ## 清单(写模型前 10 秒)
32
+
33
+ - [ ] 这页是数据图还是插画?二者勿抢主位
34
+ - [ ] 有 caption + so-what(或明确「氛围休止页无需 so-what」)
35
+ - [ ] 无文字压焦点、无标签重叠、边距够
36
+ - [ ] 无素材 → placeholder,不留空洞
37
+ - [ ] 校验:`validate_report` 对缺 caption/so-what 的配图页 WARN
38
+
39
+ > 详细几何与六版式(full/half/bleed/grid/compare/wall)→ `extract_snippet.py --task image-layout`。
@@ -20,6 +20,30 @@
20
20
  之后才进入生成(SKILL.md 工作流),规划即填写 REPORT_MODEL 的直接输入
21
21
  ```
22
22
 
23
+ ## 〇、轻量最小集(Fast / 轻量路径 · 非七步)
24
+
25
+ > **不强迫完整七步**,但禁止「零大纲直接 scaffold」。路演/汇报材料杂时尤其需要这一屏。
26
+
27
+ 写在内部笔记(≤1 屏)即可:
28
+
29
+ 1. **核心主张一句话**(≤30 字;含判断/数字更好)。
30
+ 2. **页清单**(每行三列):`claim`(本页主张) / `pageType` / `chart`(无图写 `—` 或 `image`/`placeholder`)。
31
+
32
+ 示例:
33
+
34
+ ```
35
+ 主张:Q3 增长靠转化而非流量,优先修结账漏斗
36
+ 1. 议程 | agenda | —
37
+ 2. 转化率跌 4pt | kpi | —
38
+ 3. 漏斗三段对比 | bar | funnel
39
+ 4. 竞品截图+含义 | image | —
40
+ 5. 行动三项 | points | —
41
+ ```
42
+
43
+ 之后进入 playbook §二轻量命令链。完整路径仍走下方七步法。
44
+
45
+ ---
46
+
23
47
  > **为什么前置证据表与故事线脑暴**:直接从材料跳到单版大纲,等于用第一条想到的叙事结构绑架全部材料——证据冲突会被静默抹平、弱枝论点会混进主张树。**先摊开证据、再发散故事线、最后收敛**,是咨询材料的标准做法。
24
48
 
25
49
  ### ① 意图解析(问自己四个问题,写进内部笔记,不进报告)
@@ -0,0 +1,35 @@
1
+ # 页型选型矩阵(L2)
2
+
3
+ > **何时读**:选页型 / 意图→页型映射;常读入口仍是 `playbook.md`。读完即停。
4
+ > 自动选型:`python scripts/recommend_layout.py --mode A --intent "…" --json`
5
+ > 穷举表(内容形态 → 版式 → PPTX 页型)见 `components.md` §46;密度档 `components.md` §46b;组合见 playbook §四。
6
+
7
+ | 我要表达 | 首选页型 | 次选 | 关键约束 |
8
+ |---------|---------|------|---------|
9
+ | 要点式并列主张(默认页) | `points` | `cards` | 每卡宜 3–5 条;更多拆卡/跟进页,勿截断条目 |
10
+ | 现状基线 / 指标快照 | `metrics` | `kpi` | 4–6 个;单数压场用 `kpi` |
11
+ | 单个核心数字压场 | `kpi` | `metrics` | hero 一数一结论 |
12
+ | 多维对标清单 | `table` | `halftable` | ≤8 行(research ≤16) |
13
+ | 时间趋势 / 爬坡 | `bar`(chart.type=line/area/dualline) | `exhibit` | 时间点 >8 改折线 |
14
+ | 构成占比 | `donut`(pie/multidonut/waffle) | `halftable` / **V3 KPI** | 扇区 ≤5,最小扇区 ≥8%;**极偏(min&lt;5% 或 max/min&gt;20)禁 donut→V3** |
15
+ | 排名 / 大小对比 | `bar`(chart.type=hbar/lollipop/pareto) | `table` | 类别 >8 取 Top 7 + 附录 |
16
+ | 现状 vs 目标 | `bullet` / `comparison` | `bar`(vsbar/bulletchart) | 目标线与实际条同量纲 |
17
+ | 两期升降(谁升谁降) | `bar`(slope/dumbbell) | `table` | 两端都要标数值 |
18
+ | 双维分布 / 优先级 | `bar`(scatter/bubble) | `matrix` | 气泡半径 ∝ √值 |
19
+ | 分布 / 离散度 | `boxplot` | `bar`(dotplot) | 组数 ≤8;箱线四件齐备 |
20
+ | 增减归因(A→B) | `bar`(waterfall) | `table` | 每段标变化量 + 合计收口 |
21
+ | 转化 / 筛选漏斗 | `bar`(funnel) | `sankey` | 层数 ≤5 |
22
+ | 计划排期(并行) | `bar`(gantt) | `timeline` | 里程碑叙事用 `timeline`,勿混 |
23
+ | 里程碑 / 路线叙事 | `timeline` | `steps` | 3–5 个,每个 ≤2 行 |
24
+ | 步骤 / 实施节奏 | `steps` | `timeline` | 3–6 步;高亮步 ≤2 处 |
25
+ | 二维强度对标 | `heatmap` | `matrix` | 行列 ≤5×5;只用强调色明度阶梯 |
26
+ | 定位 / 优先级 / 象限 | `matrix` | `bar`(scatter) | ≤3×3 |
27
+ | 层级递进 / 价值阶梯 | `pyramid` | `diagram` | 3–5 层;强调层 ≤1 |
28
+ | 关键判断 / 金句休止 | `quote` | `points` | 全文 1–2 处,多了廉价 |
29
+ | 完整论述(发现→证据→含义) | `twocol`(research R1) | `threecol` | 段 ≤200 字;标题必须结论句 |
30
+ | 数据证据页(主力) | `exhibit`(R2) | `split` | 全篇 Exhibit 连续编号 |
31
+ | 三栏并列论点 | `threecol`(R6) | `cards` | 每栏 ≤150 字 |
32
+ | 系统分层架构 | `diagram` | `bar`(chart.type=network) | 节点 ≤24;层 ≤4 |
33
+ | 流程 / 职责协作 | `lane` | `diagram` | 每行 ≤6 步;正交折线优先 |
34
+ | 素材图片(实拍/截图) | `image` | `split` | 六版式;无图用 `image.placeholder` |
35
+ | 待核实项收口 | `flags` 字段 | `table` | 标色必须配说明 |
@@ -35,6 +35,7 @@
35
35
  **密度选错的症状**:A 出现双栏小字墙(投影看不清)→ 拆页/换形态;A 为「疏朗」删证据/so-what → **反模式**,按 content-rules §四-c 恢复;B 大面积留白 → 合页或补证据;C 成段正文 → 转图注。
36
36
  **节奏**:禁止连续 3 页同密度档;同一版式不连用超过 2 页;research 每 3–4 页插一个低密度页(指标带/金句/大数)。
37
37
  **反截断**:溢出顺序 = 重构承载 → 拆页/分章 → 换布局 → 有限 fontShrink;禁静默截断(见 `presentation-craft.md`)。
38
+ **插画页**:情绪/产品/占位图 ≠ 数据图;安全边距、图文不叠、icon+chart 共存、Mode A full-bleed+主张叠字规则见 `illustration-layout.md`。
38
39
 
39
40
  ---
40
41
 
@@ -42,10 +43,10 @@
42
43
 
43
44
  **轻量路径**(默认)——同时满足:≤12 页 · 材料单一完整 · 无未敲定关键判断 · 用户没要求看框架。
44
45
  ```
45
- Gate 0 参考图 → 六项问询(1 轮)→ 1 张规划卡 → scaffold_report.py
46
+ Gate 0 参考图 → 六项问询(1 轮)→ 最小大纲(outline-design「轻量最小集」)→ 1 张规划卡 → scaffold_report.py
46
47
  → **只填 REPORT_MODEL** → render_from_model.py --inplace → validate_report.py --strict → 交付
47
48
  ```
48
- (Fast Mode 跳过 Gate 0/六项,其余同链;**禁止**手改 HTML 正文与模型双写。)
49
+ (Fast Mode 跳过 Gate 0/六项,仍须最小大纲;其余同链;**禁止**手改 HTML 正文与模型双写。)
49
50
 
50
51
  **完整路径**(任一命中)——研究 ≥20 页 / 演示 ≥12 页 / 材料量大且杂 / 含未敲定关键判断 / 用户要看框架。
51
52
  ```
@@ -53,7 +54,7 @@ Gate 0 参考图 → 六项问询(1 轮)→ 证据表 → 故事线脑暴
53
54
  → scaffold_report.py → **只填 REPORT_MODEL** → render_from_model.py --inplace → validate_report.py --strict → 交付
54
55
  ```
55
56
 
56
- **预算(硬)**:交互轮次 ≤3;必读文件 = `SKILL.md` + 本文件(≤2 份);L2 深度文件按需且单份读完即停。
57
+ **预算(硬)**:交互轮次 ≤3;常读面仅入口两份(`SKILL.md` + 本手册)。正式演示 / Fast 演示路径额外允许工艺双件为 L1.5(`default-surface` 与 `presentation-craft`),不记作超读。深度 L2 命中再开、读完即停。
57
58
 
58
59
  ---
59
60
 
@@ -61,37 +62,9 @@ Gate 0 参考图 → 六项问询(1 轮)→ 证据表 → 故事线脑暴
61
62
 
62
63
  > 自动选型:`python scripts/recommend_layout.py --mode A --intent "路演" --pages 10 --json`(或 `--from-model report.model.json`)→ `{pageType,skel,chart,rationale}`;Mode A 交付 `--strict` 已含 layout-qa。
63
64
 
64
- > 穷举表(内容形态 → 版式 → PPTX 页型)见 `components.md` §46;密度档适配见 `components.md` §46b;组合见下节 §四。
65
-
66
- | 我要表达 | 首选页型 | 次选 | 关键约束 |
67
- |---------|---------|------|---------|
68
- | 要点式并列主张(默认页) | `points` | `cards` | 每卡宜 3–5 条;更多拆卡/跟进页,勿截断条目 |
69
- | 现状基线 / 指标快照 | `metrics` | `kpi` | 4–6 个;单数压场用 `kpi` |
70
- | 单个核心数字压场 | `kpi` | `metrics` | hero 一数一结论 |
71
- | 多维对标清单 | `table` | `halftable` | ≤8 行(research ≤16) |
72
- | 时间趋势 / 爬坡 | `bar`(chart.type=line/area/dualline) | `exhibit` | 时间点 >8 改折线 |
73
- | 构成占比 | `donut`(pie/multidonut/waffle) | `halftable` / **V3 KPI** | 扇区 ≤5,最小扇区 ≥8%;**极偏(min&lt;5% 或 max/min&gt;20)禁 donut→V3** |
74
- | 排名 / 大小对比 | `bar`(chart.type=hbar/lollipop/pareto) | `table` | 类别 >8 取 Top 7 + 附录 |
75
- | 现状 vs 目标 | `bullet` / `comparison` | `bar`(vsbar/bulletchart) | 目标线与实际条同量纲 |
76
- | 两期升降(谁升谁降) | `bar`(slope/dumbbell) | `table` | 两端都要标数值 |
77
- | 双维分布 / 优先级 | `bar`(scatter/bubble) | `matrix` | 气泡半径 ∝ √值 |
78
- | 分布 / 离散度 | `boxplot` | `bar`(dotplot) | 组数 ≤8;箱线四件齐备 |
79
- | 增减归因(A→B) | `bar`(waterfall) | `table` | 每段标变化量 + 合计收口 |
80
- | 转化 / 筛选漏斗 | `bar`(funnel) | `sankey` | 层数 ≤5 |
81
- | 计划排期(并行) | `bar`(gantt) | `timeline` | 里程碑叙事用 `timeline`,勿混 |
82
- | 里程碑 / 路线叙事 | `timeline` | `steps` | 3–5 个,每个 ≤2 行 |
83
- | 步骤 / 实施节奏 | `steps` | `timeline` | 3–6 步;高亮步 ≤2 处 |
84
- | 二维强度对标 | `heatmap` | `matrix` | 行列 ≤5×5;只用强调色明度阶梯 |
85
- | 定位 / 优先级 / 象限 | `matrix` | `bar`(scatter) | ≤3×3 |
86
- | 层级递进 / 价值阶梯 | `pyramid` | `diagram` | 3–5 层;强调层 ≤1 |
87
- | 关键判断 / 金句休止 | `quote` | `points` | 全文 1–2 处,多了廉价 |
88
- | 完整论述(发现→证据→含义) | `twocol`(research R1) | `threecol` | 段 ≤200 字;标题必须结论句 |
89
- | 数据证据页(主力) | `exhibit`(R2) | `split` | 全篇 Exhibit 连续编号 |
90
- | 三栏并列论点 | `threecol`(R6) | `cards` | 每栏 ≤150 字 |
91
- | 系统分层架构 | `diagram` | `bar`(chart.type=network) | 节点 ≤24;层 ≤4 |
92
- | 流程 / 职责协作 | `lane` | `diagram` | 每行 ≤6 步;正交折线优先 |
93
- | 素材图片(实拍/截图) | `image` | `split` | 六版式;无图用 `image.placeholder` |
94
- | 待核实项收口 | `flags` 字段 | `table` | 标色必须配说明 |
65
+ > **穷举意图→页型表** → L2 `page-type-matrix.md`(命中才读)。`components.md` §46 / §46b;组合见 §四。
66
+
67
+ **速记(默认面)**:要点→`points`/`cards` · 指标→`metrics`/`kpi` · 证据图→`exhibit`/`split` · 对标表→`table`/`halftable` · 趋势→`bar`+line/area · 占比→`donut`(极偏→**V3**)· 架构→`diagram`/`lane` · 图文演讲→§三-b V1–V4。
95
68
 
96
69
  ---
97
70
 
@@ -154,48 +127,11 @@ Gate 0 参考图 → 六项问询(1 轮)→ 证据表 → 故事线脑暴
154
127
 
155
128
  > **默认面(8 核心图)**:`bar` · `hbar` · `line` · `donut` · `progress` · `area` · `stack` · `dualline`
156
129
  > (= `layoutSystem.defaultCharts`)。完整登记与代码 → `extract_snippet.py --chart <类型>`;误用纪律 → `charts.md`(先 `charts-discipline`,核图 8,extended 按需)。
157
- > 下表仍保留决策提示;**生成默认只从 8 核心里选**,扩展图仅在意图明确命中时用。
158
-
159
-
160
- > 穷举代码见 `charts.md` §16–§31、§35、§52–§70;误用反例与多样性纪律见 `charts.md` §66(facade:纪律→核图→extended)。
161
- > **默认生成面(P1 收敛)**:优先 `bar / hbar / line / donut / progress / area / stack / dualline`。
162
- > **高级图型**(waterfall/gantt/funnel/slope/… 与 6 类信息图)按需选用,不进默认轮换。
163
- > **纪律**:全篇不同 `data-chart` 类型 ≥ `min(模式上限, ⌈图表页数 × 0.6⌉)`(上限:research 6 / presentation 4 / architecture 3);**相邻图表页不得同型**。多样性 **preferCoreFirst**:先拉开核图 8;advanced 计入 minTypes(不罚)但只在意图命中时用,**禁止预读** `charts-extended.md`;**禁**为凑下限硬上冷门图、简单图全幅、极偏 donut/pie。
164
-
165
- | 分析意图(读者要得出的结论) | 首选 | 次选 | 禁用 / 改判条件 |
166
- |---------------------------|------|------|----------------|
167
- | 谁大谁小 | `hbar` | `lollipop` / `bar` | 类别 >8 → Top7 + 附录 |
168
- | 随时间怎么变 | `line` | `area` / `dualline` | 时间点 >8 不标点值 |
169
- | 占比是多少 | `donut` | `pie` / `multidonut` | 扇区 >5 → 合并"其他"或 `treemap` |
170
- | 每 1% 的直觉 | `waffle` | `donut` | 类别 >3 改 `marimekko` |
171
- | 结构在变形 | `streamgraph` | `stackline` | 系列 >6 合并 |
172
- | 总量 × 构成双编码 | `marimekko` | `treemap` | 列 >6 / 段 >4 → 拆 |
173
- | 份额悬殊(头部集中) | `treemap` | `donut` | 叶 >16 → 合并小项 |
174
- | 从 A 到 B 是谁贡献的 | `waterfall` | `pareto` | 段 >6 → 合并 |
175
- | 主要矛盾是哪几个 | `pareto` | `waterfall` | 类别 >7 → 合并 |
176
- | 转化/流失在哪一环 | `funnel` | `sankey` | 层 >5 → 改 `hbar` |
177
- | 多对多的流向 | `sankey` | `network` | 节点 >12 / 流带 >24 → 拆页 |
178
- | 谁和谁相连 | `network` | `diagram` | 节点 >18 / 边 >30 → 拆页 |
179
- | 两期谁升谁降 | `slope` | `dumbbell` | 系列 >6 → 取 Top 6 |
180
- | 单指标前后对比(多对象) | `dumbbell` | `vsbar` | 行 >6 → 拆页 |
181
- | 实际 vs 目标(含区间) | `bulletchart` | `bullet` | 行 >6 → 拆页 |
182
- | 达成率(多指标同心) | `radialbar` | `gauge` | 环 >5 → 改 `bullet` |
183
- | 一个值够不够 | `gauge` | `radialbar` | 单值叙事,勿与图并存 |
184
- | 分布不是均值 | `boxplot` | `dotplot` | 组 >8 → 拆页 |
185
- | 双维定位 + 第三维权重 | `bubble` | `scatter` | 气泡 >8 → 标注关键项 |
186
- | 六维能力画像 | `radar` | `rose` | 维度 >6 → 拆两组 |
187
- | 区间波动(开高低收) | `candlestick` | `line` | 蜡烛 >12 → 聚合 |
188
- | 多项目完成度 | `progress` | `bullet` | 行 >6 → 拆页 |
189
- | 迷你趋势(卡内) | `sparkline` | — | 只用于指标卡,不与大图并存 |
190
-
191
- **七种最常见的误用(出现即改判)**:
192
- 1. 用 `bar` 表达占比 → 改 `donut`/`stackline`/`waffle`。
193
- 2. 用 `donut` 表达 8 个类别 → 合并或改 `treemap`。
194
- 3. 用 `line` 表达类别对比(无时间轴)→ 改 `hbar`。
195
- 4. 用 `table` 表达趋势 → 改 `line`/`area`。
196
- 5. 用均值型图表表达分布 → 改 `boxplot`/`dotplot`。
197
- 6. 同一页放两张同型图 → 改 `split`/`halftable` 并让两图**编码不同维度**。
198
- 7. 多系列图用单色明度阶梯(分不清) → 用 `f-c1~c5` 编码色板(见 §八)。
130
+ > **扩展决策表 + 七种误用** → L2 `chart-decision-tree.md`(命中才读)。**生成默认只从 8 核心里选**,扩展图仅意图明确命中。
131
+
132
+ **多样性(硬摘要 · 保留)**:全篇不同 `data-chart` ≥ `min(模式上限, ⌈图表页数 × 0.6⌉)`(上限 research 6 / presentation **4** / architecture 3);**相邻图表页不得同型**。**preferCoreFirst**:先拉开核图 8;advanced 计入 `minTypes`(不罚)但禁预读 `charts-extended.md`;**禁**为凑下限硬上冷门图、简单图全幅、极偏 donut/pie。
133
+
134
+ **速记**:谁大谁小→`hbar` · 时间→`line`/`area` · 占比→`donut`(扇区>5/极偏改判)· 归因→`waterfall` · 转化→`funnel` · 流向→`sankey`。
199
135
 
200
136
  ---
201
137
 
@@ -261,24 +197,26 @@ python scripts/validate_pptx.py 2026-09-15-主题.pptx --strict --model=….mode
261
197
 
262
198
  ## 十、L2 节级路由(按任务只读这些,读完即停)
263
199
 
264
- > 默认生成面:`default-surface.md`(12 页型 + 8 图 + V1–V4)。Mode A 工艺清单:`presentation-craft.md`。
265
- > **不要整读** `components.md` / `charts.md` 背后的物理拆分大文件。需要代码时优先:
266
- > `python scripts/extract_snippet.py --list` · `--task <名>` · `--chart <类型>` · `--page-type <页型>` · `--file components.md --section 46`(逻辑名自动路由)
200
+ > 常读仍为入口两份;演示路径可加 **L1.5 工艺双件**:`default-surface.md` + `presentation-craft.md`。
201
+ > 默认生成面:`default-surface.md`(12 页型 + 8 图 + V1–V4)。Mode A 工艺:`presentation-craft.md`。插画:`illustration-layout.md`。
202
+ >
203
+ > **禁止整读(强制走 `extract_snippet.py`)**:`layouts-combo.md` · `components-atoms.md` · `charts-basic.md` · `charts-extended.md` · `content-rules.md` 全文 · `pptx-export.md` · 模式模板 HTML(`assets/templates/*.html`,走 `scaffold_report.py`)。
204
+ > 取码:`python scripts/extract_snippet.py --list` · `--task <名>` · `--chart <类型>` · `--page-type <页型>` · `--file components.md --section 46`(逻辑名自动路由)
267
205
 
268
206
  | 任务 | 只读 |
269
207
  |------|------|
270
- | research 证据页 / Exhibit / 密表 | `components.md` §36d/§46/§46c · 本文件 §三/§四 · `extract_snippet.py --task research-evidence` |
271
- | 正式演示 / Mode A 工艺 | `default-surface.md` · `presentation-craft.md` · 本文件 §三-b/§五 |
208
+ | research 证据页 / Exhibit / 密表 | `components.md` §36d/§46/§46c · 本文件 §三/§四 · `page-type-matrix.md` · `extract_snippet.py --task research-evidence` |
209
+ | 正式演示 / Mode A 工艺 | `default-surface.md` · `presentation-craft.md` · 本文件 §三-b/§五 · `page-type-matrix.md` |
272
210
  | 演示组合版式 | `components.md` §39–§42/§46/§46b/§46c · `--task presentation-combo` |
273
211
  | 架构 / 泳道 / 分层 | `components.md` §37–§38b · `infographics.md` §78–§80 · `--task architecture-diagram` |
274
- | 选图 / 取图表代码 | 本文件 §五 · `--chart <类型>` · 误用见 `charts.md` §66 |
212
+ | 选图 / 取图表代码 | 本文件 §五 · `chart-decision-tree.md` · `--chart <类型>` · 误用见 `charts.md` §66 |
275
213
  | 密度 / 字数 / 去 AI 味 | `content-rules.md` §一/§四 · 本文件 §六 · `--task content-rules` |
276
- | 素材图片 / 占位 | `components.md` §11c · `--task image-layout` |
214
+ | 素材图片 / 占位 / 插画页 | `illustration-layout.md` · `components.md` §11c · `--task image-layout` |
277
215
  | PPTX 精导字段 | `pptx-export.md` · 本文件 §九 · `--task pptx-export` |
278
216
  | 高保真 / 锚点 | `high-fidelity.md` · `--task high-fidelity` |
279
217
  | 配色 / 风格 | `styles.md` · `design-system.md` §1a–§1b/§9 · `--task style-theme` |
280
218
  | 图标 / 语义速查 | `icons.md` · `--task icons` |
281
219
  | 起骨架用节奏包 | `scaffold_report.py --list-types` → `--preset consulting` 等 |
282
220
 
283
- **纪律**:L0+L1 是默认全部所需;上表命中才开 L2;**读完即执行,不预读下一份**。页型语义槽位见 `layout-constants.json` → `layoutSlots`(双通道同源 IR)。
221
+ **纪律**:L0+L1 是默认全部所需(Mode A/Fast 可加 L1.5);上表命中才开 L2;**读完即执行,不预读下一份**;大文件**禁止整读**,一律 `extract_snippet.py`。页型语义槽位见 `layout-constants.json` → `layoutSlots`(双通道同源 IR)。
284
222
  **维护者**:改常量/schema/引擎后必跑 `sync_runtime.py` → `audit_styles.py` → `audit_docs.py` → `audit_skill.py` → `build_examples.py` → `regression.py`。
@@ -46,6 +46,14 @@ quality_gate.py … --deliver # 同口径
46
46
  - [ ] `motion = none`;翻页靠内容节奏
47
47
 
48
48
 
49
+ ## 插画页(非数据配图)
50
+
51
+ - 情绪/产品/占位图与数据图**勿同页抢主位**;规则见 `illustration-layout.md`。
52
+ - **安全边距** ≥24px;文字不压照片焦点;标签/图例不重叠。
53
+ - **icon + chart**:icon 在注释列,不进绘图区。
54
+ - **full-bleed + 主张叠字**(Mode A):仅封面/章节幕/金句/收尾;遮罩保对比度;必有 caption/来源;证据另页。
55
+ - 配图页写 **caption + so-what**(氛围休止页可免 so-what);校验对缺项 WARN。
56
+
49
57
  ## 长文与信息承载(anti-truncation)
50
58
 
51
59
  > **硬原则**:大量文字**不得**为了「看起来像稀疏 demo 甲板」而被故意压缩或删除。留白是设计;**删掉证据 / so-what / 口径不是设计**。
@@ -136,3 +136,9 @@
136
136
  | `evals/*` | Eval 框架:`prompts.csv`(14 条,含负对照)+ `rubric.schema.json`(风格目标评分契约)+ `run_evals.py`(结果/过程/风格/效率四类目标) |
137
137
  | `assets/templates/*` | 三模式模板 + 公共引擎/UI(标记块由 `sync_runtime.py` 注入) |
138
138
  | `assets/examples/*` | 示例矩阵(含信息图页型与原生图表技巧) |
139
+
140
+ ## 附:第三方校验与实验 frontmatter
141
+
142
+ - **主门禁**:`audit_skill.py` / `package_skill.py --check`(体积、披露、Gate0、触发覆盖)。
143
+ - **可选**:`npx --yes skills-ref@0.1.5 validate .`(Agent Skills 开放标准;本技能已通过)。**不**作为 CI 硬依赖。
144
+ - **不启用**:Claude-only `when_to_use`(会破坏严格 allowlist);跨端 `allowed-tools`(宿主语法分叉)——需要时由宿主侧实验,不进本仓库 frontmatter。
@@ -139,7 +139,7 @@ def main() -> int:
139
139
  # ⑤ 篇数与必需文件
140
140
  n_ref = len(list(REF.glob('*.md')))
141
141
  sk = (ROOT / 'SKILL.md').read_text(encoding='utf-8')
142
- d = re.search(r'^description:\s*"(.*)"\s*$', sk, re.M | re.S)
142
+ d = re.search(r'^description:\s*"(.*)"\s*$', sk, re.M)
143
143
  dlen = len(d.group(1)) if d else -1
144
144
  nm = re.search(r'^name:\s*(\S+)\s*$', sk, re.M)
145
145
  missing = [r for r in REQUIRED if not (ROOT / r).exists()]
@@ -13,7 +13,7 @@
13
13
 
14
14
  审计项(任一不过 → 退出码 1):
15
15
  ① 体积预算 —— SKILL.md / 常读入口 playbook.md / 单份 reference / 模式模板 的上限
16
- ② 元数据 —— frontmatter name 与技能名一致;description ≤ DESC_HARD,且 ≤ DESC_SOFT(触发精度)
16
+ ② 元数据 —— frontmatter name 与技能名一致;description ≤ DESC_HARD/SOFT;可选 license/compatibility/metadata(开放标准)
17
17
  ③ 披露分层 —— SKILL.md 必须声明 L0/L1/L2 三档,且 L1(常读入口)恰好 1 份
18
18
  ④ 交互门禁 —— SKILL.md 必须含「Gate 0 参考图先行」,且其出现位置在「六项问询」之前;若声明 Fast Mode,须同时有豁免句且标准路径仍为硬门禁
19
19
  ⑤ 效率预算 —— SKILL.md 必须显式声明交互轮次上限与必读文件数上限
@@ -139,7 +139,7 @@ def main() -> int:
139
139
  f'最大 {kb(max((p.stat().st_size for p in TPL.glob("*.html")), default=0))} / 上限 {kb(BUDGET["template"])}')
140
140
 
141
141
  # ② 元数据
142
- d = re.search(r'^description:\s*"(.*)"\s*$', sk, re.M | re.S)
142
+ d = re.search(r'^description:\s*"(.*)"\s*$', sk, re.M)
143
143
  dlen = len(d.group(1)) if d else -1
144
144
  nm = re.search(r'^name:\s*(\S+)\s*$', sk, re.M)
145
145
  chk('② name 一致', bool(nm) and nm.group(1) == NAME,
@@ -149,9 +149,37 @@ def main() -> int:
149
149
  chk('② description 软上限(触发精度)', 0 < dlen <= BUDGET['desc_soft'],
150
150
  f'{dlen} / 建议 ≤ {BUDGET["desc_soft"]}')
151
151
 
152
+ # ②b 开放标准可选 frontmatter(允许额外键;校验存在与粗约束)
153
+ lic = re.search(r'^license:\s*(.+)$', sk, re.M)
154
+ chk('② license', bool(lic) and 'MIT' in (lic.group(1) if lic else ''),
155
+ '缺 license: MIT(开放标准可选,本技能应对齐 package.json)',
156
+ 'license=MIT')
157
+ compat = re.search(r'^compatibility:\s*"(.*)"\s*$', sk, re.M | re.S)
158
+ clen = len(compat.group(1)) if compat else -1
159
+ chk('② compatibility', 0 < clen <= 500,
160
+ f'compatibility 缺失或超 500 字符({clen})',
161
+ f'{clen} 字符')
162
+ meta_ver = re.search(r'^\s+version:\s*"?([\w.\-]+)"?\s*$', sk, re.M)
163
+ meta_author = re.search(r'^\s+author:\s*(\S+)\s*$', sk, re.M)
164
+ pkg_ver = ''
165
+ try:
166
+ import json as _json
167
+ pkg_ver = str(_json.loads((ROOT / 'package.json').read_text(encoding='utf-8')).get('version') or '')
168
+ except Exception:
169
+ pass
170
+ chk('② metadata.version', bool(meta_ver) and (not pkg_ver or meta_ver.group(1) == pkg_ver),
171
+ f'metadata.version 缺失或与 package.json 不一致(fm={meta_ver.group(1) if meta_ver else None} pkg={pkg_ver})',
172
+ f'{meta_ver.group(1) if meta_ver else "?"}')
173
+ chk('② metadata.author', bool(meta_author),
174
+ '缺 metadata.author',
175
+ meta_author.group(1) if meta_author else '')
176
+
152
177
  # ③ 渐进式披露分层(机器可读标记:L0=… · L1=… · L2=…)
153
- m_l1 = re.search(r'L1\s*=\s*`?([^`\s·|]+)`?', sk)
154
- has_l0 = bool(re.search(r'L0\s*=', sk))
178
+ # Prefer machine-readable disclosure marker `L1=references/...`(忽略正文「L0+L1 共 2」等)
179
+ m_l1 = re.search(r'L1\s*=\s*`?(references/[a-z0-9\-./]+\.md)`?', sk)
180
+ if not m_l1:
181
+ m_l1 = re.search(r'L1\s*=\s*`?([^`\s·|]+)`?', sk)
182
+ has_l0 = bool(re.search(r'L0\s*=\s*`?SKILL', sk)) or bool(re.search(r'`L0=SKILL', sk))
155
183
  has_l2 = bool(re.search(r'L2\s*=', sk))
156
184
  l1_files = [f.strip() for f in re.split(r'[,、]', m_l1.group(1)) if f.strip()] if m_l1 else []
157
185
  chk('③ 披露分层 L0/L1/L2', has_l0 and has_l2 and len(l1_files) == BUDGET['l1_files'],
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """TopPPT HTML · description trigger coverage (keyword/heuristic, no LLM).
4
+
5
+ Gates regressions when SKILL.md description drifts away from eval queries.
6
+ See evals/trigger-queries.json → how_to_extend.
7
+
8
+ Usage:
9
+ python3 scripts/check_triggers.py
10
+ python3 scripts/check_triggers.py --json
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import re
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ try:
20
+ sys.stdout.reconfigure(encoding='utf-8', errors='replace')
21
+ except Exception:
22
+ pass
23
+
24
+ ROOT = Path(__file__).resolve().parent.parent
25
+ SKILL = ROOT / 'SKILL.md'
26
+ QUERIES = ROOT / 'evals' / 'trigger-queries.json'
27
+
28
+ # Tokens that, if present in a query AND in description (or Do-NOT zone for negatives),
29
+ # count toward a hit. Multi-char CJK / ASCII keywords preferred over single chars.
30
+ POS_KEYWORDS = [
31
+ '报告', '演示', '汇报', '路演', '调研', '白皮书', '评测', '对标', '经营分析', '复盘',
32
+ 'PPT', 'PPTX', 'pptx', 'slides', 'deck', 'HTML', '网页报告',
33
+ '架构图', '拓扑', '流程图', '泳道', '方案图',
34
+ '排版', '版式', '配色', '图文',
35
+ '快速模式', 'fast', '一键出稿', '直接生成', '少问一句',
36
+ '可视化', '高保真', '可编辑',
37
+ '咨询报告', '分析报告', '研究报告', '项目汇报', '商务',
38
+ ]
39
+
40
+ # Negative-zone cues in description (Do NOT …) — if a miss-query matches these
41
+ # boundary phrases more than positive product cues, treat as correctly excluded.
42
+ NEG_BOUNDARY = [
43
+ '纯代码', '代码工程', '非报告类', '视频', '图片生成',
44
+ 'Word', '源文件', '应用开发', 'coding', 'Do NOT',
45
+ ]
46
+
47
+ # Extra strong negative query cues (if query has these AND lacks report cues → expect miss)
48
+ NEG_QUERY_CUES = [
49
+ 'react', '组件', '单测', 'debug', 'python 报错', '视频', 'mp4', 'midjourney',
50
+ '海报图', '已有的 pptx', '已有 pptx', 'word 文档', '电商官网', 'sql',
51
+ 'nginx', 'refactor', 'typescript', '剪辑', '录像', '字幕', '迁移脚本',
52
+ ]
53
+
54
+
55
+ def load_description() -> str:
56
+ txt = SKILL.read_text(encoding='utf-8')
57
+ m = re.search(r'^description:\s*"(.*)"\s*$', txt, re.M)
58
+ if not m:
59
+ raise SystemExit('SKILL.md missing description frontmatter')
60
+ return m.group(1)
61
+
62
+
63
+ def tokenize_hits(query: str, desc: str) -> list[str]:
64
+ q_low = query.lower()
65
+ d_low = desc.lower()
66
+ hits = []
67
+ for kw in POS_KEYWORDS:
68
+ if kw.lower() in q_low and kw.lower() in d_low:
69
+ hits.append(kw)
70
+ return hits
71
+
72
+
73
+ def looks_negative_query(query: str) -> bool:
74
+ q = query.lower()
75
+ return any(c in q for c in NEG_QUERY_CUES)
76
+
77
+
78
+ def boundary_covered(desc: str) -> bool:
79
+ return sum(1 for b in NEG_BOUNDARY if b.lower() in desc.lower()) >= 2
80
+
81
+
82
+ def evaluate(desc: str, data: dict) -> tuple[list[dict], int, int]:
83
+ rows = []
84
+ fails = 0
85
+ for bucket, default_expect in (('positive', 'hit'), ('negative', 'miss')):
86
+ for item in data.get(bucket, []):
87
+ q = item['query']
88
+ expect = item.get('expect', default_expect)
89
+ hits = tokenize_hits(q, desc)
90
+ if expect == 'hit':
91
+ ok = len(hits) >= 1
92
+ detail = f'keywords={hits}' if ok else 'no shared trigger keyword with description'
93
+ else:
94
+ # miss: either no positive keyword overlap, OR query is clearly
95
+ # out-of-scope and description has Do-NOT boundaries.
96
+ ok = (len(hits) == 0) or (
97
+ looks_negative_query(q) and boundary_covered(desc) and len(hits) <= 1
98
+ )
99
+ # Stricter: if query is a known out-of-scope cue, require miss even
100
+ # when a weak overlapping token exists (e.g. "pptx" in "改已有 pptx").
101
+ if looks_negative_query(q) and boundary_covered(desc):
102
+ ok = True
103
+ detail = (
104
+ f'miss-ok boundary; weak_hits={hits}' if ok
105
+ else f'unexpected trigger overlap={hits}'
106
+ )
107
+ rows.append({
108
+ 'id': item.get('id'),
109
+ 'expect': expect,
110
+ 'ok': ok,
111
+ 'query': q,
112
+ 'detail': detail,
113
+ })
114
+ if not ok:
115
+ fails += 1
116
+ return rows, fails, len(rows)
117
+
118
+
119
+ def main() -> int:
120
+ as_json = '--json' in sys.argv
121
+ if not QUERIES.exists():
122
+ print(f'MISSING {QUERIES}')
123
+ return 1
124
+ data = json.loads(QUERIES.read_text(encoding='utf-8'))
125
+ desc = load_description()
126
+ rows, fails, total = evaluate(desc, data)
127
+ n_pos = sum(1 for r in rows if r['expect'] == 'hit')
128
+ n_neg = sum(1 for r in rows if r['expect'] == 'miss')
129
+ if as_json:
130
+ print(json.dumps({
131
+ 'total': total, 'fails': fails,
132
+ 'positive': n_pos, 'negative': n_neg,
133
+ 'description_chars': len(desc),
134
+ 'rows': rows,
135
+ }, ensure_ascii=False, indent=2))
136
+ else:
137
+ print(f'trigger coverage · {total - fails}/{total} '
138
+ f'(+{n_pos} / −{n_neg}) · description {len(desc)} chars')
139
+ for r in rows:
140
+ mark = 'OK' if r['ok'] else 'FAIL'
141
+ print(f' [{mark}] {r["id"]} expect={r["expect"]} {r["detail"]}')
142
+ if not r['ok']:
143
+ print(f' Q: {r["query"]}')
144
+ if fails:
145
+ print(f'\nFAILED {fails} query(ies). Extend keywords in SKILL description '
146
+ f'or adjust evals/trigger-queries.json (see how_to_extend).')
147
+ else:
148
+ print('\nAll trigger heuristics passed.')
149
+ return 1 if fails else 0
150
+
151
+
152
+ if __name__ == '__main__':
153
+ sys.exit(main())
@@ -23,6 +23,7 @@
23
23
  L4 截断迹象(列表项省略号砍义)
24
24
  L5 溢出未拆页
25
25
  L6 混排缺对齐(ALIGN_RHYTHM)
26
+ N18 配图页缺 caption/图注(IMAGE_CAPTION)
26
27
 
27
28
  用法: python scripts/negative_tests.py
28
29
  """
@@ -176,6 +177,15 @@ def main() -> int:
176
177
  '"footnote": "<strong>x</strong> ', 1)
177
178
  cases.append(('N17 模型夹带标签', t17, 'HTML_TAG_IN_TEXT'))
178
179
 
180
+ # N18 配图页缺 caption(有 <img>/media 无图注类)
181
+ t18 = txt.replace(
182
+ '</body>',
183
+ '<section class="band" data-page-type="image">'
184
+ '<div class="media media--full">'
185
+ '<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="注入无图注">'
186
+ '</div></section></body>', 1)
187
+ cases.append(('N18 配图缺 caption', t18, 'IMAGE_CAPTION'))
188
+
179
189
  ok = True
180
190
  for name, content, keyword in cases:
181
191
  if content == txt:
@@ -87,6 +87,7 @@ INCLUDE = [
87
87
  'references/*',
88
88
  'scripts/*',
89
89
  'evals/*',
90
+ 'agents/*',
90
91
  ]
91
92
 
92
93
  # 出包规则(命中即跳过;与 .gitignore 口径一致)
@@ -120,6 +121,9 @@ REQUIRED = [
120
121
  'references/layout-grammar.md',
121
122
  'references/default-surface.md',
122
123
  'references/presentation-craft.md',
124
+ 'references/illustration-layout.md',
125
+ 'references/page-type-matrix.md',
126
+ 'references/chart-decision-tree.md',
123
127
  'references/modes.md', 'references/outline-design.md', 'references/design-system.md',
124
128
  'references/styles.md', 'references/content-rules.md', 'references/components.md',
125
129
  'references/charts.md',
@@ -145,13 +149,15 @@ REQUIRED = [
145
149
  'references/infographics-stats.md', 'references/infographics-structure.md',
146
150
  'evals/prompts.csv', 'evals/run_evals.py', 'evals/rubric.schema.json',
147
151
  'evals/trace.example.json',
152
+ 'evals/trigger-queries.json',
153
+ 'scripts/check_triggers.py',
148
154
  ]
149
155
 
150
156
  # 必须达到最小数量的集合(名称含日期,故按数量校验)
151
157
  MIN_COUNTS = {
152
158
  'assets/examples/*.html': 3, # Batch3 每模式 1 份黄金样张
153
159
  'assets/examples/*.model.json': 3,
154
- 'references/*.md': 22, # craft 轮后含 default-surface + presentation-craft;≥22 防误删
160
+ 'references/*.md': 25, # + page-type-matrix + chart-decision-tree;≥25 防误删
155
161
  }
156
162
 
157
163
 
@@ -255,6 +261,16 @@ def main():
255
261
  return 1
256
262
  print(' 校验通过:必需文件齐全 · frontmatter 合规 · 无临时/缓存路径')
257
263
 
264
+ # P0-1 trigger heuristic gate(廉价、无 LLM)
265
+ trig = ROOT / 'scripts' / 'check_triggers.py'
266
+ if trig.exists():
267
+ import subprocess
268
+ r = subprocess.run([sys.executable, str(trig)], cwd=str(ROOT))
269
+ if r.returncode != 0:
270
+ print(' ✗ trigger coverage 失败(evals/trigger-queries.json)')
271
+ return 1
272
+ print(' ✓ trigger coverage 通过')
273
+
258
274
  if check_only:
259
275
  print('\n(--check 模式:仅校验,不打包)')
260
276
  return 0
@@ -1215,6 +1215,33 @@ def _check_media(txt, chk, model):
1215
1215
  chk("模型配图占位 ↔ 正文 .media--ph 对应", False,
1216
1216
  f"{n_ph} 页模型声明 image.placeholder 但正文无 .media--ph", level="WARN")
1217
1217
 
1218
+ # 配图页 caption / so-what(廉价 WARN);近邻主张/导语亦可
1219
+ bands = re.split(r'(?=<section\b)', txt)
1220
+ miss_cap = []
1221
+ near_empty = []
1222
+ for i, b in enumerate(bands):
1223
+ if not re.search(r'class="[^"]*\bmedia\b|<img\b|class="[^"]*media--', b):
1224
+ continue
1225
+ if len(b) < 80:
1226
+ continue
1227
+ has_cap = bool(re.search(
1228
+ r'class="[^"]*(?:fig__cap|media__cap|media__ph|caption|exhibit__src|footnote|so-what|lead)', b)
1229
+ or re.search(r'<figcaption\b|class="[^"]*\bsoWhat\b', b))
1230
+ if not has_cap:
1231
+ miss_cap.append(f'band[{i}]')
1232
+ # 近图过空:有 media 但正文文本极少且无要点/指标(WARN)
1233
+ textish = re.sub(r'<script[\s\S]*?</script>|<style[\s\S]*?</style>|<[^>]+>', ' ', b)
1234
+ textish = re.sub(r'\s+', ' ', textish).strip()
1235
+ has_points = bool(re.search(r'class="[^"]*(?:points|bullets|kpi|metrics|card)', b))
1236
+ if len(textish) < 40 and not has_points and not re.search(r'media--ph', b):
1237
+ near_empty.append(f'band[{i}]')
1238
+ chk("配图页含 caption/图注(IMAGE_CAPTION)", not miss_cap,
1239
+ f"{len(miss_cap)} 处配图区缺 .fig__cap/.media__cap/.footnote/so-what 等图注" if miss_cap else "",
1240
+ level="WARN")
1241
+ chk("配图页近邻过空(IMAGE_NEAR_EMPTY)", not near_empty,
1242
+ f"{len(near_empty)} 处配图页几乎无注解/要点(补 caption 或要点条)" if near_empty else "",
1243
+ level="WARN")
1244
+
1218
1245
 
1219
1246
  # 失败检查项 → 失败模式 / 处置动作 / 精确取码命令。
1220
1247
  # 目的:校验失败时直接给出「改什么、按什么顺序改、去哪取代码」,