Skill: wjyhahaha/ski-assistant (version 6.0.1)

--- name: ski-assistant description: | Global ski resort assistant covering 854 resorts across 40+ countries. Plan trips, compare prices, analyze your form, and find early-bird deals. 全球滑雪助手，覆盖 854 座雪场（40+ 国，中国 470 座最全）。帮你挑雪场、查价格、看动作、盯早鸟、报天气。 Triggers / 触发词: ski, snowboard, 滑雪, 雪票, 雪场, 去哪滑, 外滑, 早鸟票, 季卡, 滑雪攻略, 动作分析, weather, budget, coaching. Responds naturally to casual requests in Chinese or English — no special keywords needed. 自然语言触发：周末去哪滑、雪票太贵了、帮我看看这个动作、万龙多少钱、早鸟票什么时候买。 Not for: non-ski travel, general city weather, non-winter sports. 不覆盖：非滑雪旅行、城市天气预报、其他运动装备。 license: MIT version: 6.0.1 allowed-tools: "Bash(python3 tools/price_api.py *) Bash(python3 tools/exchange_rate.py *) Bash(python3 tools/card_generator.py *) Bash(python3 tools/resort_discovery.py *) Bash(python3 tools/strategy_maint.py *) WebFetch WebSearch" metadata: author: wjyhahaha version: 6.0.1 category: travel-lifestyle tags: [skiing, travel, budget, weather, recommendation] --- # Ski Assistant v6.0.0 — 全球滑雪综合服务助手（动态教程生成架构） 像一个懂滑雪的朋友——帮你挑雪场、比价捡漏、分析动作、盯早鸟、列清单、查山顶天气。 > 数据：`data/resorts_db.json`（854 座雪场，含 178 个搜索别名） | 策略：`data/search_strategies.json`（161 区域搜索模板） | 模块：`modules/`（执行协议） | 参考：`references/`（攻略模板、装备、预算、教练标准、教程技能骨架） | 工具：`tools/`（联网查询） --- ## 全局 MUST 规则（所有模块必须遵守，不可违反） 1. **降级必须告知**：任何步骤因工具不可用、网络失败、信息缺失而降级/跳过，必须在输出中说明原因。不可静默跳过。 2. **价格必须标注来源**：每项价格标注 `（实时）`、`（网络搜索）`、`（数据库参考）` 或 `（估算）`。 3. **国际场景必换算汇率**：涉及非 CNY 币种，必须调用 `exchange_rate.py` 获取实时汇率。失败时用备用汇率并标注"参考汇率"。 4. **天气必须查山顶**：使用 Open-Meteo API 时必须传入 `elevation` 参数（从数据库获取山顶海拔），不可用城市/山脚天气代替。 5. **安全提醒不可省略**：头盔必戴、滑雪专项险必推荐、国际需含救援。每次攻略/查价输出结尾必须包含。 --- ## 意图识别与路由 根据用户请求识别意图，加载对应模块协议文件： | 用户意图 | 触发词示例 | 加载模块 | |---------|-----------|---------| | 推荐雪场 / 行程规划 | 去哪滑、帮我规划、滑雪攻略、recommend resort | `modules/trip-planning.md` | | 查价格 / 比价 / 预算 | 多少钱、雪票价格、便宜票、预算、how much | `modules/pricing.md` | | 动作分析 / 教练 | 分析动作、看看姿态、滑雪打分、ski coach | `modules/coaching.md` | | 早鸟预售 / 季卡 | 早鸟票、什么时候买、帮我盯着、presale | `modules/presale.md` | | 发现雪场 / 更新数据库 | 发现新雪场、update-db、discover | `modules/discovery.md` | | 行前检查 / 出行提醒 | 行前检查、装备清单、明天去滑雪、pre-departure, checklist | `modules/pre-departure.md` | | 教程 / 学习 / 进阶 | 新手教程、怎么学滑雪、进阶指南、刻滑怎么练、ski tutorial, learn to ski | `modules/tutorial.md` | **组合意图**：用户同时涉及多个场景（如"推荐万龙并查价格"），加载所有对应模块。 **读取规则**： - 首次只读本文件（SKILL.md），识别意图后加载对应 module - `references/` 是知识库（攻略模板、装备清单、预算参考价），由模块协议指定何时读取 - `tools/` 是联网工具脚本，仅由模块协议指定的步骤调用 --- ## 数据操作 ### 用户数据目录 所有用户数据存储在 `~/.ski-assistant/`（可通过 `SKI_ASSISTANT_DATA_DIR` 自定义）： | 文件 | 内容 | |------|------| | `user_profile.json` | 用户画像（水平、城市、偏好、预算、板型、风格） | | `records.json` | 电子教练评分记录（JSON 数组格式，每个元素是一条完整记录） | | `watchlist.json` | 预售监听列表 | | `price_history.json` | 用户记录的价格数据 | | `custom_resorts.json` | 用户自定义雪场（推荐时合并到主数据库） | | `upcoming_trips.json` | 即将出行的行程（日期、提醒状态） | | `usage_stats.json` | 命令调用统计 | | `exports/` | 分享卡片图片 | ### 读写方式 ```bash # 读取 python3 -c "import json; print(json.dumps(json.load(open('$HOME/.ski-assistant/user_profile.json')), ensure_ascii=False, indent=2))" # 写入（先读再写，保留已有字段） python3 -c " import json, os path = os.path.expanduser('~/.ski-assistant/user_profile.json') data = json.load(open(path)) if os.path.exists(path) else {} data.update({'city': '北京', 'level': 'intermediate'}) json.dump(data, open(path, 'w'), ensure_ascii=False, indent=2) " ``` 每次执行功能后，递增 `usage_stats.json` 中对应计数。 --- ## 数据库读取指南 `data/resorts_db.json`（约 595KB，854 座雪场）是核心数据文件。由于文件较大，**不建议一次性读取全部内容**。推荐按以下方式按需访问： | 场景 | 推荐方式 | 说明 | |------|---------|------| | 查询单个雪场 | Python 内联脚本过滤 | 按名称/ID 查找单条记录 | | 按地区筛选 | Python 内联脚本过滤 | 按 region/province 筛选子集 | | 统计/元信息 | 读取 `_meta` 字段 | 获取版本、更新日期、雪场总数 | | 发现新雪场 | `tools/resort_discovery.py` | 联网查询并更新数据库 | **示例**（查询单个雪场）： ```bash python3 -c " import json data = json.load(open('data/resorts_db.json')) resort = data.get('万龙滑雪场', {}) print(json.dumps(resort, ensure_ascii=False, indent=2)) " ``` --- ## 环境变量 本技能**不依赖任何必需环境变量**。唯一可选：`SKI_ASSISTANT_DATA_DIR`（自定义数据目录）。 电子教练使用 Agent 自身视觉能力，不需要 API Key。 --- ## 网络请求说明 所有网络请求由 Agent 在用户明确请求时触发，技能脚本不创建后台服务、守护进程或定时任务： | 场景 | 目标 | 触发条件 | |------|------|---------| | 高山天气 | api.open-meteo.com | 用户查询天气时 | | 汇率换算 | api.exchangerate-api.com | 国际价格换算时 | | 雪场发现 | overpass-api.de / nominatim.openstreetmap.org | 运行 discover 时 | | 数据库同步 | raw.githubusercontent.com | 运行 update-db 时 | | 实时查价 | flyai CLI | 查机票/酒店且 flyai 可用时 | | 联网搜索 | Agent WebSearch/WebFetch | 查价、查攻略时 | --- ## 搜索策略说明 `data/search_strategies.json` 是搜索策略引擎，指导 agent 如何高效搜索各区域雪场的实时价格和票务信息。 ### 数据结构 | 部分 | 内容 | 更新频率 | |------|------|---------| | `region_strategies` | 11 个区域策略（关键词模板、flyai 参数、优先级） | 事件驱动，几乎不需要更新 | | `official_channels` | 16 个中国头部雪场官方微信公众号名称 | 季度复核（90 天） | | `fliggy_platform` | 飞猪平台关键词模板 | 每年雪季前（9 月）验证 | ### 区域覆盖 11 个策略覆盖 161 个区域、822/854 座雪场（96.3%），剩余 32 个由 default 策略兜底。 ### 维护方式 运行 `python3 tools/strategy_maint.py` 进行维护： | 命令 | 功能 | |------|------| | `check` | 检查数据健康度（覆盖率、必填字段、空关键词、复核超期） | | `review` | 交互式季度复核（逐个验证微信公众号名称） | | `add-channel` | 添加新的官方渠道 | | `report` | 生成维护报告到 `docs/strategies_maintenance_report.md` | 复核状态记录在 `official_channels._verification_status` 字段，格式为 `created_YYYY-MM-DD_next_review_YYYY-MM-DD`。运行 `check` 时会自动计算是否超期。

path: README.md
content: # ski-assistant

Global ski resort assistant for trip planning, pricing, coaching & presale monitoring.
全球滑雪综合服务助手 — 行程规划、智能查价、AI 电子教练、早鸟预售。

## v6.0.0 — Progressive Disclosure + Data Deduplication

Major architecture overhaul: progressive disclosure loading for tutorials, data deduplication with aliases, and complete file restructure.

Key changes:
- **Tutorial progressive disclosure**: Split monolithic 1454-line `_index.md` into 12 focused files, reducing per-request load by 60-70%
- **Data deduplication**: 900 → 854 unique resorts via aliases merge (46 duplicates removed, 178 aliases preserved for search compatibility)
- **File restructure**: `levels/` directory with short filenames (`sb-0.md`, `ski-3.md`, etc.)
- **Framework separation**: `training.md`, `faq.md`, `gear.md` extracted from index
- **Code fixes**: `resort_discovery.py` field name consistency (`lat/lon` → `latitude/longitude`)
- **Complete skill ID consistency**: All 68 skills across 8 level files, continuous and verified

重大架构升级：教程渐进式披露加载、数据去重合并、完整文件重构。

核心变更：
- **教程渐进式加载**：1454 行单文件拆分为 12 个专注文件，每次请求减少 60-70% 加载量
- **数据去重**：900 → 854 座雪场，通过 aliases 合并（删除 46 个重复，保留 178 个别名确保搜索兼容）
- **文件重构**：`levels/` 目录 + 短文件名（`sb-0.md`、`ski-3.md` 等）
- **框架分离**：`training.md`、`faq.md`、`gear.md` 从索引中提取
- **代码修复**：`resort_discovery.py` 字段名一致性修复
- **技能 ID 完整一致**：8 个文件 68 个技能，连续无重复，已验证

## v5.3.6 — Complete Tutorial System + Style Branches + DOCX Export

Complete 4-level tutorial system (Level 0-3) × 2 board types (snowboard/ski), with style branches and DOCX export.

Key additions:
- **Level 2-3 tutorials**: 4 new files with advanced techniques
- **Style branches**: Carving/Park/Freeride (snowboard), Carving/Mogul/Freeride (ski)
- **CASI/CSIA terminology**: Full integration (Scheme C) in Level 2+ core skills
- **DOCX export**: Professional Word document generation for tutorials
- **Complete technical tree**: From beginner to expert, all skills covered

完善 4 级别教程体系（Level 0-3）× 2 种板型（单板/双板），含风格分支和 DOCX 导出。

新增内容：
- **Level 2-3 教程**：4 个新文件，含高级技术
- **风格分支**：刻滑/公园/野雪（单板），卡宾/蘑菇/野雪（双板）
- **CASI/CSIA 术语**：Level 2+ 核心技能完整集成（方案 C）
- **DOCX 导出**：专业 Word 文档生成
- **完整技术树**：从零基础到专家，所有技能覆盖

## v5.3.5 — Ski Tutorial System + Complete Technical Framework

New ski tutorial system with 4 levels (0-3) × 2 board types (snowboard/ski), complete technical coverage from beginner to advanced. Features:

- **Complete technical tree**: PSIA-AASI framework + CASI/CSIA terminology reference (Scheme C: PSIA primary, CASI/CSIA supplementary)
- **Separate files by board type**: Snowboard users only see snowboard content, ski users only see ski content
- **Level 0-1 implemented**: 4 tutorial files with full technical coverage (854 resorts, search strategies, structured output, rich user profile, pre-departure, tutorials)
- **International terminology**: Level 2+ will show terminology对照 (PSIA-AASI / CASI / CSIA) for core skills
- **Tutorial-to-coaching loop**: AI coaching scores can recommend specific tutorial chapters for improvement

新增滑雪教程系统，4 个级别（0-3）× 2 种板型（单板/双板），从零基础到高级的完整技术覆盖。特性：

- **完整技术树**：PSIA-AASI 框架 + CASI/CSIA 术语对照（方案 C：PSIA 为主，CASI/CSIA 为辅）
- **按板型分离文件**：单板用户只看单板内容，双板用户只看双板内容
- **Level 0-1 已实现**：4 个教程文件，完整技术覆盖（899 雪场、搜索策略、结构化输出、丰富用户画像、行前提醒、教程）
- **国际术语对照**：Level 2+ 核心技能显示术语对照（PSIA-AASI / CASI / CSIA）
- **教程-教练闭环**：AI 教练评分可推荐对应教程章节进行改进

新增模块：`modules/tutorial.md`、`references/tutorial-curriculum/`（8 个教程文件 + 索引 + 通用内容）

## v5.3.3 — Structured Output + Rich User Profile

All 5 modules now define scenario-based output format templates with mandatory tables, fallback handling, and personalized columns for agent flexibility. Trip planning scoring formula expanded with board_type, style, and experience dimensions (snow_hours, ski_days, mileage). Added National Alpine Skiing Centre (Olympic venue) to resorts_db.

全部 5 个模块定义了基于场景的输出格式模板，含强制表格、兜底处理和个性化列。行程规划打分公式新增板型、风格和雪时/天数/里程维度。新增国家高山滑雪中心（奥运场馆）。

## v5.3.2 — Search Strategies Maintenance

Search strategies maintenance tool, health check & quarterly review workflow.

搜索策略维护工具，健康检查 + 季度复核流程。

## v5.3.1 — 854 Resorts + Search Strategy Engine

854 ski resorts across 40+ countries. Three-layer architecture (instruction + protocol + knowledge). Flyai integration expanded with keyword-search & search-poi. 8-tier price credibility labels. Search strategy engine covering 161 regions.

854 座雪场覆盖 40+ 国。三层架构（指令层+协议层+知识层）。flyai 扩展 keyword-search 和 search-poi。8 级价格可信度标签。搜索策略引擎覆盖 161 个区域。

## Use Cases / 使用场景

Ski enthusiasts need a knowledgeable assistant for trip planning, price comparison, skill improvement, and finding deals. Here's what ski-assistant can do for you:

滑雪爱好者在规划行程、对比价格、提升技术、寻找优惠时，需要一个懂滑雪的助手：

### 1. Where to ski this weekend? / 周末不知道去哪滑？

**Smart recommendation + trip planning — 智能推荐 + 行程规划**

You might ask:
- "周末从北京出发，中级水平，推荐个雪场"
- "Recommend a ski resort near Beijing for beginners this weekend"
- "How much for a 5-day trip to Niseko for 2 people?"
- "去二世谷滑雪要花多少钱？2人5天"

What I'll do: Understand your skill level, budget, and schedule, then match from 854 global resorts using a structured scoring formula. You'll get a complete plan with transport, accommodation, gear checklist, and mountaintop weather forecast.

了解你的水平、预算、时间后，从 854 座全球雪场用结构化打分公式智能匹配，输出包含交通、住宿、装备清单的完整方案，并附带山顶天气预报。

### 2. Lift tickets too expensive? / 雪票太贵？

**Multi-channel pricing + deal hunting — 四路径查价 + 低价捡漏**

You might ask:
- "万龙现在什么价？有没有残票转让"
- "Find discounted lift tickets for Wanlong"
- "飞猪上有什么滑雪套餐？"

What I'll do: Check four channels — flyai keyword-search for Fliggy packages, search-flight/hotel for real-time transport, WebSearch for official ticket prices, social platforms for resale tickets. Automatic currency conversion for international trips. Every price labeled with 8-tier credibility source.

同时查四个渠道 — flyai keyword-search 飞猪套餐、search-flight/hotel 实时交通住宿、WebSearch 官网雪票、社交平台转让票。涉及外币时自动换算。每项价格标注 8 级可信度来源标签。

### 3. Want to improve your technique? / 想提升滑雪技术？

**AI electronic coach — AI 电子教练**

You might ask:
- "帮我看看这张滑雪照片，姿态打个分"
- "Rate my skiing form from this photo"

What I'll do: Analyze your photos/videos across four dimensions (posture, turning, freestyle, overall), highlight strengths and areas for improvement, and track your progress over time.

分析你的照片/视频，按四维度（基础姿态、转弯技术、自由式、综合滑行）打分，指出亮点和改进建议，并记录进步轨迹。

### 4. When's the best time to buy? / 早鸟票什么时候买最划算？

**Presale monitoring — 预售监听**

You might ask:
- "万龙的早鸟票什么时候开售？帮我盯着"
- "When do early-bird passes go on sale?"

What I'll do: Share historical sale timelines, search for the latest season announcements, and compare single-trip vs multi-day vs season pass value. Add to watchlist for periodic checks and notifications.

告诉你历年开售时间规律，搜索当季最新公告，对比单次票/次卡/季卡的性价比。添加监听后，定期检查并通知你。

### 5. What to pack for an international trip? / 第一次外滑要准备什么？

**Gear guide + travel tips — 装备 + 攻略**

You might ask:
- "去北海道滑雪要带什么装备？"
- "What gear should I bring for a Japan ski trip?"

What I'll do: Based on your level and destination, list essential gear, clothing tips, visa/insurance reminders, local transport options, and cultural notes like onsen etiquette.

根据你的水平和目的地，列出必备装备、穿衣建议、签证/保险提醒、当地交通方式，以及温泉文化等本地贴士。

### 6. Mountain weather check / 查雪场天气

**Summit-level forecasts, not valley-town weather — 必须是山顶的**

You might ask:
- "查一下万龙未来7天的山顶天气"
- "Check the mountaintop weather at Wanlong for the next 7 days"

What I'll do: Query professional weather forecasts at the resort's summit elevation (not the town below), including snowfall, wind speed, visibility, and a ski condition rating.

查询雪场山顶海拔（而非山脚城镇）的专业天气预报，包括降雪量、风速、能见度，并给出滑雪条件评分。

## Quick Start / 快速开始

```bash
clawhub install ski-assistant
```

安装后直接对话即可开始，无需额外配置。Just start chatting — no configuration needed.

## Coverage / 覆盖范围

| Region / 区域 | Resorts / 雪场数 | Countries / 代表国家 |
|---------------|-----------------|---------------------|
| China / 中国 | 470 | 崇礼、北京、东北、新疆、全国 30 省份 |
| Japan / 日本 | 51 | 北海道、长野、新潟、东北 |
| North America / 北美 | 104 | 美国（科罗拉多/犹他/加州）、加拿大（惠斯勒） |
| Europe / 欧洲 | 134 | 法国、瑞士、奥地利、意大利、德国等 |
| Korea / 韩国 | 23 | 江原道平昌、旌善、洪川 |
| Southern Hemisphere / 南半球 | 40 | 新西兰、澳大利亚、智利、阿根廷 |
| Other / 其他 | 32 | 其他欧洲国家、东南亚室内等 |

## Architecture / 架构

v5.3.1 adopts a three-layer architecture:

- **Instruction Layer** (`SKILL.md`): 115 lines, intent routing, 5 global MUST rules
- **Protocol Layer** (`modules/`): 7 protocol files with MUST/SHOULD/MAY grading, explicit output formats
- **Knowledge Layer** (`references/`): 20 reference files with pure reference data, no imperative language

Plus:
- **Data Layer** (`data/`): Resort database + search strategy engine
- **Tools Layer** (`tools/`): 5 Python tools with security documentation (incl. strategy maintenance)

v5.3.1 采用三层架构：

- **指令层**（`SKILL.md`）：115 行，意图路由，5 条全局 MUST 规则
- **协议层**（`modules/`）：7 个协议文件，MUST/SHOULD/MAY 分级，明确输出格式
- **知识层**（`references/`）：20 个参考文件，纯参考数据，无指令性语言

外加：
- **数据层**（`data/`）：雪场数据库 + 搜索策略引擎
- **工具层**（`tools/`）：5 个 Python 工具，含安全文档（含策略维护工具）

## Search Strategy Engine / 搜索策略引擎

`data/search_strategies.json` covers 161 regions with:

- 11 region strategies (崇礼/东北/新疆/北京/国内其他/日本/韩国/欧洲/北美/南半球/default)
- 16 official WeChat channels for top Chinese resorts
- Fliggy keyword templates for package deals
- flyai search parameters (search-poi, keyword-search)

Each strategy includes websearch keywords, fliggy keywords, flyai parameters, priority level, and season info.

`data/search_strategies.json` 覆盖 161 个区域：

- 11 个区域策略
- 16 个中国头部雪场官方微信公众号渠道
- 飞猪套餐关键词模板
- flyai 搜索参数

## Data Storage / 数据存储

Default: `~/.ski-assistant/` (customizable via `SKI_ASSISTANT_DATA_DIR`). All data stored locally only, never uploaded.
默认 `~/.ski-assistant/`，可通过环境变量自定义。所有数据仅存储在用户本机。

## Support / 支持

If you like this project, please give it a star!
[![GitHub Stars](https://img.shields.io/github/stars/wjyhahaha/ski-assistant?style=social)](https://github.com/wjyhahaha/ski-assistant/stargazers)

如果你喜欢这个项目，请给它一个 Star！你的支持是我持续更新的动力。

## Changelog

- **v6.0.1** (2026-04-12): Tutorial reading optimization (44% reduction), terminology consistency (刻滑/卡宾), records.json cross-module consistency, 6-round comprehensive verification
- **v6.0.0** (2026-04-11): Progressive Disclosure + Data Deduplication
- **v5.3.6** (2026-04-11): Complete tutorial system + style branches + DOCX export
- **v5.3.5** (2026-04-11): Ski tutorial system (4 levels × 2 board types), complete technical tree, PSIA-AASI + CASI/CSIA terminology, tutorial-to-coaching loop
- **v5.3.4** (2026-04-11): Pre-departure reminder module with dynamic checklist, cron scheduling support
- **v5.3.1** (2026-04-11): Search strategy engine (161 regions), flyai keyword-search + search-poi integration, 8-tier price credibility labels, three-layer architecture refinement
- **v5.3.0** (2026-04-11): Three-layer architecture refactor (SKILL.md 550→115 lines, 5 module protocols, 5 references)
- **v5.2.4** (2026-04-11): ClawHub security audit fix — removed broad `Bash(python3 -c *)` permission
- **v5.2.2** (2026-04-11): International resort database expansion to 854 resorts (40+ countries)
- **v5.1.0** (2026-04-11): Bilingual frontmatter, 304-resort database (27 countries), expanded discovery regions, tightened allowed-tools
- **v5.0.1**: Restricted allowed-tools to specific scripts only
- **v5.0.0**: Knowledge-hub architecture refactor (10 scripts → 4 tools, 86% reduction)
- **v4.4.0**: Fixed ClawHub security review transparency issues
- **v4.3.0**: Local usage statistics
- **v4.2.0**: XHS sharing + international packages + price trends
- **v4.0.0**: 155-resort database + OSM discovery + mountain weather

## License

MIT


path: assets/fonts/README.md
content: # Fonts / 字体资源

本目录存放用于小红书分享卡片生成的可选字体文件。

## 字体优先级

`card_generator.py` 按以下顺序自动查找字体（无需手动配置）：

| 优先级 | macOS | Linux | Windows |
|--------|-------|-------|---------|
| 1（首选） | `/System/Library/Fonts/PingFang.ttc` | `/usr/share/fonts/truetype/noto/NotoSansCJK-Bold.ttc` | `C:/Windows/Fonts/simhei.ttf` |
| 2（常规） | `/System/Library/Fonts/PingFang.ttc` | `/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc` | `C:/Windows/Fonts/msyh.ttc` |
| 3（兜底） | 系统默认字体 | 系统默认字体 | 系统默认字体 |

## 手动安装（可选）

如果系统上缺少中日韩字体导致卡片文字显示异常，可将字体文件放入本目录：

1. 下载 [Noto Sans CJK](https://github.com/googlefonts/noto-cjk)（开源免费）
2. 将 `.ttc` 或 `.ttf` 文件放入 `assets/fonts/`
3. 卡片生成器会自动检测并使用

## 推荐字体

- **Noto Sans SC**（简体中文）— Google Fonts / GitHub: googlefonts/noto-cjk
- **Noto Sans TC**（繁体中文）
- **思源黑体 / Source Han Sans** — Adobe + Google 联合开发


path: data/search_strategies.json
content: {
  "_meta": {
    "version": "1.0.0",
    "created": "2026-04-11",
    "purpose": "搜索策略模板 - 指导 agent 如何高效搜索各区域雪场实时价格和票务信息",
    "data_type": "关键词模板，无需验证 URL 可用性",
    "coverage": {
      "total_regions": 161,
      "china_regions": 30,
      "intl_countries": 35,
      "intl_sub_regions": 96
    }
  },

  "region_strategies": {
    "崇礼": {
      "description": "河北崇礼滑雪核心区，中国最密集优质雪场",
      "resort_count": 73,
      "top_resorts": ["万龙滑雪场", "太舞滑雪小镇", "云顶滑雪公园", "富龙滑雪场", "翠云山银河滑雪场"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["崇礼滑雪", "崇礼 万龙 雪票", "崇礼 太舞 门票"]
      },
      "websearch_keywords": [
        "崇礼滑雪场 2026 雪票价格",
        "万龙滑雪场 门票 预订",
        "太舞滑雪小镇 雪票 官网"
      ],
      "fliggy_keywords": ["崇礼滑雪", "崇礼滑雪票"],
      "priority": "highest",
      "season": "11月-次年3月"
    },

    "东北": {
      "description": "吉林+黑龙江+辽宁，天然粉雪区",
      "resort_count": 89,
      "top_resorts": ["北大湖滑雪场", "松花湖滑雪场", "亚布力滑雪场", "长白山万达滑雪场"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["吉林滑雪", "亚布力滑雪", "北大湖 雪票"]
      },
      "websearch_keywords": [
        "吉林 滑雪 2026 雪票价格",
        "亚布力滑雪场 门票 预订",
        "北大湖滑雪场 雪票 官网"
      ],
      "fliggy_keywords": ["吉林滑雪", "亚布力滑雪"],
      "priority": "high",
      "season": "11月-次年3月"
    },

    "新疆": {
      "description": "阿尔泰山区，粉雪天堂，雪期长",
      "resort_count": 19,
      "top_resorts": ["将军山滑雪场", "可可托海滑雪场", "丝绸之路滑雪场"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["新疆滑雪", "阿勒泰滑雪", "将军山 雪票"]
      },
      "websearch_keywords": [
        "新疆 阿勒泰 滑雪 2026 雪票",
        "将军山滑雪场 门票 预订",
        "可可托海国际滑雪场 官网"
      ],
      "fliggy_keywords": ["新疆滑雪", "阿勒泰滑雪"],
      "priority": "high",
      "season": "10月-次年4月"
    },

    "北京": {
      "description": "北京周边一日滑雪圈",
      "resort_count": 24,
      "top_resorts": ["南山滑雪场", "军都山滑雪场", "怀北国际滑雪场"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["北京滑雪", "北京 南山 雪票", "密云滑雪"]
      },
      "websearch_keywords": [
        "北京滑雪场 2026 雪票价格",
        "南山滑雪场 门票 预订",
        "北京周边滑雪 一日游"
      ],
      "fliggy_keywords": ["北京滑雪", "北京滑雪票"],
      "priority": "high",
      "season": "12月-次年2月"
    },

    "国内其他": {
      "description": "山东/河南/山西/湖北/四川等南方及中部省份室内/小型雪场",
      "resort_count": 276,
      "top_resorts": ["融创雪世界（成都）", "融创雪世界（哈尔滨）", "金象山滑雪场"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["成都 室内滑雪", "山东滑雪", "湖北神农架滑雪"]
      },
      "websearch_keywords": [
        "{省份} 滑雪场 2026 门票",
        "融创雪世界 票价",
        "室内滑雪 价格 对比"
      ],
      "fliggy_keywords": ["室内滑雪", "{省份}滑雪"],
      "priority": "medium",
      "season": "全年（室内）/ 12月-2月（室外）",
      "note": "使用 {省份} 占位符，agent 根据用户查询替换"
    },

    "日本": {
      "description": "日本滑雪区（北海道+长野+新潟+东北）",
      "resort_count": 51,
      "top_resorts": ["Niseko", "白马五龙", "志贺高原", "留寿都"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["日本滑雪", "北海道 滑雪", "长野 白马 滑雪"]
      },
      "websearch_keywords": [
        "日本滑雪 2026 雪票价格",
        "Niseko Grand Hirafu lift ticket",
        "白马五龙滑雪场 门票"
      ],
      "fliggy_keywords": ["日本滑雪", "北海道滑雪", "日本滑雪票"],
      "priority": "high",
      "season": "12月-次年4月",
      "currency": "JPY",
      "note": "需货币换算，价格通常 5000-8000 JPY/天"
    },

    "韩国": {
      "description": "韩国滑雪（江原道为主）",
      "resort_count": 12,
      "top_resorts": ["龙平度假村", "阿尔卑斯希亚", "旌善滑雪场"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["韩国滑雪", "江原道滑雪", "龙平 滑雪"]
      },
      "websearch_keywords": [
        "韩国滑雪 2026 价格",
        "龙平度假村 滑雪票",
        "江原道滑雪 一日游"
      ],
      "fliggy_keywords": ["韩国滑雪", "韩国滑雪票"],
      "priority": "medium",
      "season": "12月-次年3月",
      "currency": "KRW"
    },

    "欧洲": {
      "description": "法国/瑞士/奥地利/意大利/德国/西班牙等阿尔卑斯及欧洲滑雪区",
      "resort_count": 134,
      "top_resorts": ["Chamonix", "Verbier", "St. Anton", "Val Thorens", "Zermatt", "Courchevel"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["法国滑雪", "瑞士滑雪", "阿尔卑斯滑雪", "Chamonix skiing"]
      },
      "websearch_keywords": [
        "Chamonix Mont-Blanc lift ticket price 2026",
        "Verbier forfait journalier prix",
        "St. Anton am Arlberg ski pass price"
      ],
      "fliggy_keywords": [],
      "priority": "medium",
      "season": "12月-次年4月",
      "currency": "EUR/CHF",
      "note": "多币种（EUR/CHF），需货币换算。飞猪无欧洲滑雪产品"
    },

    "北美": {
      "description": "美国/加拿大滑雪区（落基山脉+东部）",
      "resort_count": 104,
      "top_resorts": ["Vail", "Whistler Blackcomb", "Aspen", "Park City", "Breckenridge"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["Vail滑雪", "Whistler滑雪", "科罗拉多滑雪", "Aspen skiing"]
      },
      "websearch_keywords": [
        "Vail lift ticket price 2026",
        "Whistler Blackcomb day pass price",
        "Aspen Snowmass lift ticket cost"
      ],
      "fliggy_keywords": [],
      "priority": "medium",
      "season": "11月-次年4月",
      "currency": "USD/CAD",
      "note": "Ikon/Epic Pass 覆盖多数雪场，查单日票价格。飞猪无北美滑雪产品"
    },

    "南半球": {
      "description": "澳大利亚/新西兰/阿根廷/智利（反季滑雪 6-10月）",
      "resort_count": 40,
      "top_resorts": ["Perisher", "Coronet Peak", "Las Lenas", "Thredbo", "Treble Cone"],
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["澳大利亚滑雪", "新西兰滑雪", "皇后镇滑雪", "Perisher skiing"]
      },
      "websearch_keywords": [
        "Perisher NSW lift ticket price 2026",
        "Coronet Peak Queenstown ski pass cost",
        "Las Lenas Argentina ski ticket price"
      ],
      "fliggy_keywords": [],
      "priority": "low",
      "season": "6月-10月",
      "currency": "AUD/NZD/ARS/CLP",
      "note": "反季，北半球夏季时开放。飞猪无南半球滑雪产品"
    },

    "default": {
      "description": "默认搜索策略，用于未覆盖区域（小众国际雪场）",
      "resort_count": 44,
      "flyai_params": {
        "search_poi_category": "skiing",
        "keywords": ["{resort_name}滑雪", "{resort_name}雪票"]
      },
      "websearch_keywords": [
        "{resort_name} 雪票价格 2026",
        "{resort_name} lift ticket price",
        "{resort_name} 官网 预订"
      ],
      "fliggy_keywords": ["{resort_name}"],
      "priority": "low",
      "season": "因地区而异",
      "note": "使用雪场名称动态替换 {resort_name}"
    }
  },

  "official_channels": {
    "_description": "国内头部雪场官方渠道 - 需手动验证 URL 有效性（建议季度复核）",
    "_verification_status": "created_2026-04-11_next_review_2026-07-11",
    "_note": "仅覆盖 Top 20 中国雪场（用户查询量 80%），其余走 region_strategies",

    "万龙滑雪场": {
      "type": "wechat",
      "name": "万龙滑雪场",
      "value": "万龙滑雪场 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：万龙滑雪场"
    },
    "太舞滑雪小镇": {
      "type": "wechat",
      "name": "太舞滑雪小镇",
      "value": "太舞滑雪小镇 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：太舞滑雪小镇"
    },
    "云顶滑雪公园": {
      "type": "wechat",
      "name": "云顶滑雪公园",
      "value": "云顶滑雪公园 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：云顶滑雪公园"
    },
    "富龙滑雪场": {
      "type": "wechat",
      "name": "富龙滑雪场",
      "value": "崇礼富龙四季小镇 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：崇礼富龙四季小镇"
    },
    "北大湖滑雪场": {
      "type": "wechat",
      "name": "北大湖滑雪场",
      "value": "北大湖滑雪度假区 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：北大湖滑雪度假区"
    },
    "松花湖滑雪场": {
      "type": "wechat",
      "name": "松花湖滑雪场",
      "value": "万科松花湖度假区 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：万科松花湖度假区"
    },
    "亚布力滑雪场": {
      "type": "wechat",
      "name": "亚布力滑雪旅游度假区",
      "value": "亚布力滑雪旅游度假区 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：亚布力滑雪旅游度假区"
    },
    "南山滑雪场": {
      "type": "wechat",
      "name": "北京南山滑雪场",
      "value": "北京南山滑雪 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：北京南山滑雪"
    },
    "将军山滑雪场": {
      "type": "wechat",
      "name": "阿勒泰将军山",
      "value": "阿勒泰地区文旅局 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "通过阿勒泰文旅获取信息"
    },
    "长白山万达滑雪场": {
      "type": "wechat",
      "name": "长白山万达国际度假区",
      "value": "长白山万达国际度假区 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：长白山万达国际度假区"
    },
    "融创雪世界": {
      "type": "wechat",
      "name": "融创雪世界",
      "value": "融创文旅俱乐部 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "统一入口：融创文旅俱乐部小程序"
    },
    "军都山滑雪场": {
      "type": "wechat",
      "name": "北京军都山滑雪场",
      "value": "军都山滑雪场 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：军都山滑雪场"
    },
    "怀北国际滑雪场": {
      "type": "wechat",
      "name": "怀北国际滑雪场",
      "value": "怀北国际滑雪场 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：怀北国际滑雪场"
    },
    "翠云山银河滑雪场": {
      "type": "wechat",
      "name": "翠云山银河滑雪场",
      "value": "翠云山国际旅游度假区 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：翠云山国际旅游度假区"
    },
    "可可托海滑雪场": {
      "type": "wechat",
      "name": "可可托海国际滑雪场",
      "value": "可可托海国际滑雪场 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：可可托海国际滑雪场"
    },
    "丝绸之路滑雪场": {
      "type": "wechat",
      "name": "丝绸之路滑雪场",
      "value": "丝绸之路山地度假区 (WeChat MP)",
      "url": "",
      "verified": false,
      "note": "微信搜索公众号：丝绸之路山地度假区"
    }
  },

  "fliggy_platform": {
    "_description": "飞猪平台搜索能力 - 可搜索雪票/机酒套餐/当地游",
    "supported_categories": ["雪票", "机酒套餐", "当地游", "住宿"],
    "search_command": "flyai keyword-search",
    "note": "优先搜索 飞猪 keyword-search 获取实时套餐价格",
    "keyword_templates": {
      "china_top": "{resort_name} 雪票",
      "china_region": "{region} 滑雪 套餐",
      "japan": "日本 {region} 滑雪 套餐",
      "europe": "阿尔卑斯 滑雪 机酒",
      "north_america": "{resort_name} 滑雪 套餐"
    }
  }
}


path: docs/strategies_maintenance_report.md
content: # Search Strategies 维护报告
生成时间: 2026-04-11 17:52

## 1. 区域策略覆盖
- **国内其他**: 276 resorts, priority=medium, season=全年（室内）/ 12月-2月（室外）
- **欧洲**: 134 resorts, priority=medium, season=12月-次年4月
- **北美**: 104 resorts, priority=medium, season=11月-次年4月
- **东北**: 89 resorts, priority=high, season=11月-次年3月
- **崇礼**: 73 resorts, priority=highest, season=11月-次年3月
- **日本**: 51 resorts, priority=high, season=12月-次年4月
- **default**: 44 resorts, priority=low, season=因地区而异
- **南半球**: 40 resorts, priority=low, season=6月-10月
- **北京**: 24 resorts, priority=high, season=12月-次年2月
- **新疆**: 19 resorts, priority=high, season=10月-次年4月
- **韩国**: 12 resorts, priority=medium, season=12月-次年3月

## 2. 官方渠道 (16 个)
- ⏳ 万龙滑雪场: 微信搜索公众号：万龙滑雪场
- ⏳ 丝绸之路滑雪场: 微信搜索公众号：丝绸之路山地度假区
- ⏳ 云顶滑雪公园: 微信搜索公众号：云顶滑雪公园
- ⏳ 亚布力滑雪场: 微信搜索公众号：亚布力滑雪旅游度假区
- ⏳ 军都山滑雪场: 微信搜索公众号：军都山滑雪场
- ⏳ 北大湖滑雪场: 微信搜索公众号：北大湖滑雪度假区
- ⏳ 南山滑雪场: 微信搜索公众号：北京南山滑雪
- ⏳ 可可托海滑雪场: 微信搜索公众号：可可托海国际滑雪场
- ⏳ 太舞滑雪小镇: 微信搜索公众号：太舞滑雪小镇
- ⏳ 富龙滑雪场: 微信搜索公众号：崇礼富龙四季小镇
- ⏳ 将军山滑雪场: 通过阿勒泰文旅获取信息
- ⏳ 怀北国际滑雪场: 微信搜索公众号：怀北国际滑雪场
- ⏳ 松花湖滑雪场: 微信搜索公众号：万科松花湖度假区
- ⏳ 翠云山银河滑雪场: 微信搜索公众号：翠云山国际旅游度假区
- ⏳ 融创雪世界: 统一入口：融创文旅俱乐部小程序
- ⏳ 长白山万达滑雪场: 微信搜索公众号：长白山万达国际度假区

## 3. 维护建议
- region_strategies: 无需定期更新，事件驱动调整
- official_channels: 季度复核微信公众号名称
- fliggy_platform: 每年雪季前（9月）验证一次

path: modules/coaching.md
content: # Module 3: AI Coach — 电子教练

**触发词**：分析滑雪动作、看看姿态、滑雪打分、电子教练、视频分析、雪季总结、analyze my form, rate my skiing, ski coach

**加载知识**：必须读取 `references/coaching-rubric.md`（四维度评分标准）

---

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 场景 A：单次动作分析（用户发照片/视频）

1. **接收媒体**：用户提交滑雪照片或视频
2. **视觉分析**：使用 Agent 自身视觉能力（或用户已配置的视觉模型），严格按 coaching-rubric.md 的四维度标准打分
3. **输出评分**：按下方"输出格式 - 场景 A"输出，不可省略任一部分
4. **保存记录**：追加写入 `~/.ski-assistant/records.json`（JSON 数组格式）。写入步骤：
   a. 读取现有数组（如文件不存在，初始化为空数组 `[]`）
   b. 追加新记录对象，格式必须包含以下字段：
      ```json
      {
        "id": "YYYYMMDD-HHMMSS",
        "date": "YYYY-MM-DD",
        "resort": "雪场名",
        "scores": {"posture": X, "turning": X, "overall": X},
        "dimension_averages": {"posture": X, "turning": X, "overall": X},
        "total_score": X,
        "highlights": ["...", "..."],
        "issues": ["...", "..."]
      }
      ```
   c. 写回文件
   d. **强制校验**：写入后确认文件已成功更新（读取文件验证最后一条记录的 id 与本次一致）。如 id 不匹配（并发写入等异常），重试一次写入；如仍不匹配，告知用户"评分记录可能存在冲突，已保存但不保证完整性"
   e. **失败兜底**：如写入失败（文件权限、磁盘满等），在输出末尾告知用户"评分记录保存失败，下次分析可能无法追踪进步趋势"

### 场景 B：进步报告 / 雪季总结（用户说"帮我做雪季总结"或"看看我进步了多少"）

1. **读取记录**：读取 `~/.ski-assistant/records.json`（JSON 数组）
2. **统计分析**：
   - 统计总记录数、各维度平均分变化
   - 标记变化 > +0.5 为"进步"，< -0.5 为"退步"
   - 统计反复出现的问题（出现 2 次以上）
3. **输出报告**：按下方"输出格式 - 场景 B"输出
4. **雪季定义**：当年 10 月至次年 5 月。按最近记录日期推断所属雪季

### 场景 C：教程推荐（打分后自动触发）

1. **读取用户档案**：从 `~/.ski-assistant/user_profile.json` 读取用户的 `level` 和 `board_type`。如无记录，跳过场景 C 并告知用户"建议先建立用户档案以便获得个性化教程推荐"
2. **读取目标分数**：从 `references/tutorial-curriculum/_index.md` 读取该级别对应维度的目标分数
3. **对比评分**：对比 posture、turning、overall 三个维度平均分与目标分数下限。如场景为公园/mogul/跳台，同时对比 freestyle 维度
4. **推荐教程**：如有任一维度低于目标分数下限，按下方"场景 C 输出格式"输出推荐
5. **触发教程模块**：用户同意后，加载 tutorial 模块场景 B 输出对应教程内容

**推荐逻辑**：

| 低于目标的维度 | 推荐教程章节 | 适用场景 |
|--------------|------------|---------|
| posture < 目标 | 基础姿态章节（站姿、重心、膝盖弯曲） | 全部场景 |
| turning < 目标 | 转弯技术章节（换刃、弯型控制、点杖） | 全部场景 |
| overall < 目标 | 综合滑行章节（速度控制、节奏感、地形适应） | 全部场景 |
| freestyle < 目标 | 风格专精 → 公园/蘑菇章节 | 仅公园/mogul/跳台场景 |

## 评分维度概要

| 维度 | 子项数量 | 适用场景 |
|------|---------|---------|
| 基础姿态 posture | 6 项 | 所有水平必评 |
| 转弯技术 turning | 6 项 | 所有水平必评 |
| 自由式 freestyle | 5 项 | 仅 park/mogul/跳台 |
| 综合滑行 overall | 6 项 | 所有水平必评 |

所有分数 1-10 分，精确到 0.5。freestyle 仅在公园场景出现。

## 输出格式

### 场景 A：单次动作分析

必须包含以下五部分，顺序不可变：

**1. 各维度评分**（表格，仅评适用的维度）

| 维度 | 总分 | 关键子项得分 |
|------|------|------------|
| 基础姿态 | 7.0/10 | 重心 7.5、膝盖弯曲 6.0、上半身稳定 7.5 |
| 转弯技术 | 6.5/10 | 换刃时机 7.0、弯形控制 6.0、压力管理 6.5 |
| 综合滑行 | 7.0/10 | 节奏 7.5、线路 7.0、流畅度 6.5 |

如照片/视频角度无法评估某维度，写"无法评估（原因：正面角度无法看清换刃动作）"，不可省略该维度。

**2. 亮点**（2-3 条，必须具体到动作细节）

- ✅ 重心位置良好：滑行中重心保持在前脚掌，没有后坐
- ✅ 弯形对称：左右转弯弧度基本一致，说明立刃角度控制稳定

不可写模糊评价如"滑得不错"。

**3. 问题**（1-3 条，必须具体到可改进的点）

- ⚠️ 上半身在换刃时转动过大：每次换刃时肩膀朝向山下旋转，导致重心偏移
- ⚠️ 膝盖弯曲不足：陡坡段腿部过于伸直，降低减震能力

**4. 改进建议**（1-3 条，必须可执行）

- 🎯 在缓坡反复练习换刃时上半身保持面向山下，可对着镜子或在手机录像中检查
- 🎯 下一个雪日专门练膝盖弯曲：在蓝道上刻意保持"微蹲姿态"滑行 10 趟

不可写模糊建议如"多练习"。

**5. 一句话总结**
"整体姿态不错，重心控制好。重点改进换刃时上半身稳定性和膝盖弯曲度，下次会有明显提升。"

**媒体质量异常处理**
如照片模糊或角度不佳，必须在输出开头说明：
> ⚠️ 照片/视频角度不佳（原因：正面拍摄无法看清立刃角度），评分仅供参考。建议提供侧面 15-60 秒视频或清晰静态照片。

### 场景 B：进步报告 / 雪季总结

必须包含以下五部分，顺序不可变：

**1. 记录概览**

| 指标 | 数值 |
|------|------|
| 总记录数 | X 次 |
| 首次分析日期 | YYYY-MM-DD |
| 最近分析日期 | YYYY-MM-DD |
| 所属雪季 | 2025-2026 雪季 |

**2. 维度变化趋势**（表格，按时间顺序）

| 日期 | 基础姿态 | 转弯技术 | 综合滑行 | 综合 |
|------|---------|---------|---------|------|
| 2025-12-01 | 6.0 | 5.5 | 6.0 | 5.8 |
| 2026-01-15 | 6.5 | 6.0 | 6.5 | 6.3 |
| 2026-03-01 | 7.0 | 6.5 | 7.0 | 6.8 |
| **变化** | **+1.0 ↑** | **+1.0 ↑** | **+1.0 ↑** | **+1.0 ↑** |

变化 > +0.5 标记"↑ 进步"，< -0.5 标记"↓ 退步"，±0.5 以内标记"→ 持平"。如无记录，输出"暂无历史记录，先发照片开始第一次分析吧"。

**3. 反复出现的问题**（出现 2 次以上才列出）

| 问题 | 出现次数 | 趋势 |
|------|---------|------|
| 上半身转动过大 | 3次 | 未改善 |
| 膝盖弯曲不足 | 2次 | 有改善（最近1次未出现） |

如无反复问题，输出"未发现反复出现的问题，继续保持！"

**4. 成长亮点**
- 基础姿态从 6.0 提升到 7.0，重心控制明显改善
- 换刃流畅度提升，弯形控制从不对称到基本对称

如无记录，输出"—"。

**5. 下阶段练习重点**
1. 继续改进换刃时上半身稳定性（已出现 3 次，优先解决）
2. 尝试在蓝道上练习小弯，提升转弯技术维度
3. 建议下次拍摄侧面 15-60 秒视频，便于更精准分析

## 小红书分享

调用：`python3 tools/card_generator.py score-card '<json>'`

参数含 resort、date、scores、highlights、style。依赖 Pillow，未安装时提示用户运行 `pip install Pillow`。

## MAY（可选）

- 生成进步趋势图（文本描述或 Markdown 表格）
- 生成小红书分享卡片
- 教程推荐后引导用户主动请求教程内容


path: modules/discovery.md
content: # Module 5A: Resort Discovery & DB Update — 雪场发现

**触发词**：发现新雪场、添加雪场、update-db、同步数据库、discover, add resort, update database

---

## 发现新雪场

调用：`python3 tools/resort_discovery.py discover '{"region":"中国","enrich":true,"merge":false}'`

**region 可选值**：中国、日本、韩国、欧洲、北美 等，或具体区域如 "中国-崇礼"、"日本-北海道西"。共 65 个预定义区域，覆盖 27 国。

**参数说明**：
- `enrich: true` → 自动通过 Open-Meteo 补充海拔数据
- `merge: true` → 自动合并到 `data/resorts_db.json`（标记 `_needs_review: true`）
- 默认 `merge: false`，仅预览

**数据源**：Overpass API（首选）→ Nominatim（降级）。票价/雪道数/特色等商业信息需人工补充。

## 更新数据库

调用：`python3 tools/resort_discovery.py update-db`

从 GitHub 拉取最新 `resorts_db.json`，自动备份（.bak），对比版本后覆盖。

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 发现新雪场

1. 确认用户意图（发现哪个区域的雪场）
2. 运行 `python3 tools/resort_discovery.py discover '{"region":"<区域>","enrich":true,"merge":<merge值>}'`。默认 `merge: false`（仅预览），如用户要求"发现并合并"或"自动合并"，则设 `merge: true`
3. 输出结果摘要（必须包含下方"输出格式 - 场景 A"的全部字段）
4. 如用户指定了 `merge: true`，提醒用户新雪场标记了 `_needs_review: true`，建议人工校验

### 更新数据库

1. 运行 `python3 tools/resort_discovery.py update-db`
2. 输出更新结果（必须包含下方"输出格式 - 场景 B"的全部字段）
3. 告知用户备份文件位置（.bak）

## 输出格式

### 场景 A：发现新雪场

必须包含以下三部分，顺序不可变：

**1. 发现结果摘要**

| 指标 | 数量 |
|------|------|
| 总计找到 | X 个滑雪区域 |
| 已存在（匹配） | Y 个 |
| 新发现 | Z 个 |
| 错误 | N 个（如无则写 0） |

**2. 新发现雪场列表**（仅当 Z > 0 时输出，如为 0 则说明"未发现新雪场"）

| 名称 | 区域 | 坐标 | 来源 |
|------|------|------|------|
| ... | ... | lat, lon | Overpass/Nominatim |

**3. 后续建议**
- 如新发现雪场 > 0：建议用户说"补充详细信息"来人工校验票价、雪道数等
- 如 merge=true：提醒"新雪场已标记 _needs_review: true，建议人工校验后移除标记"

### 场景 B：更新数据库

必须包含以下三部分，顺序不可变。如任一项因信息不足无法提供，必须说明原因，不可省略不告知。

**1. 更新结果**
- 当前版本：`<旧版本号>` → 新版本：`<新版本号>`
- 雪场数量变化：`<旧数量>` → `<新数量>`（+/- X 个）

**2. 备份位置**
- 备份文件：`data/resorts_db.json.bak`（可通过 git diff 查看差异）

**3. 校验建议**
- 如数量变化 > 50：建议运行 `python3 tools/resort_discovery.py discover` 检查数据一致性
- 如数量变化异常（减少 > 10%）：提醒用户可能是数据源问题，建议核实

## MAY

- 对新发现雪场补充详细信息（票价、雪道数、特色等）
- 批量校验合并后的数据一致性


path: modules/pre-departure.md
content: # Module 5B: Pre-Departure Reminder — 出行提醒

**触发词**：行前检查、出发提醒、装备清单、明天去滑雪、pre-departure, checklist, reminder, packing list

**加载知识**：必须读取 `references/gear-guide.md`（装备数据库）、`references/pre-departure-checklist.md`（行前检查模板）。这 2 个文件无依赖关系，**可并行读取**。

**加载数据**：读取 `~/.ski-assistant/user_profile.json`（用户画像）、`~/.ski-assistant/upcoming_trips.json`（行程记录，如不存在则初始化为空数组 `[]` 并询问用户行程信息）

---

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 场景 A：用户主动触发行前检查（"我明天去滑雪了"、"帮我做行前检查"）

1. **读取行程信息**：读取 `~/.ski-assistant/upcoming_trips.json`，如无记录则询问用户目的地、出发日期、返回日期
2. **读取用户画像**：读取 `~/.ski-assistant/user_profile.json` 获取 level、board_type、style 等
3. **查询天气**：调用 Open-Meteo API 获取目的地山顶天气（必须传 elevation 参数）
4. **生成 checklist**：按下方"输出格式 - 场景 A"生成行前检查清单
5. **可选：设置提醒**：询问用户是否需要创建出发前一天+当天的定时提醒

### 场景 B：用户确认出行日期后自动创建提醒（从 trip-planning 模块流转）

1. 用户在 trip-planning 中确认了具体出行日期
2. 将行程信息保存到 `~/.ski-assistant/upcoming_trips.json`：
   ```json
   {
     "resort": "万龙",
     "city": "河北崇礼",
     "departure_date": "2026-04-15",
     "return_date": "2026-04-17",
     "created_at": "2026-04-11",
     "reminders_set": false
   }
   ```
3. 询问用户是否创建定时提醒任务（必须经用户明确同意）
4. 用户同意后，创建两个定时任务：
   - **出发前一天 20:00**：发送装备检查清单 + 天气速报
   - **出发当天早上 07:00**：发送最终确认清单 + 实时天气 + 交通提醒

### 场景 C：定时提醒触发（由 cron 调度执行）

1. 读取对应行程信息
2. 查询实时天气（Open-Meteo API）
3. 生成检查清单（同场景 A 格式）
4. 将结果发送到用户 IM 会话（如已连接）或在对话中输出

---

## 行前 Checklist 生成规则

根据以下维度动态生成检查清单：

| 维度 | 影响内容 |
|------|---------|
| 目的地气候 | 崇礼/东北需极寒装备，日本需防水装备，室内雪场精简 |
| 用户水平 | 初学者必加护腕/护臀，高级加野雪装备 |
| 板型 | 单板加护腕/护臀/护背，双板加雪杖 |
| 行程天数 | 决定内衣/袜子数量（参考 gear-guide.md 穿衣数量建议） |
| 是否国际 | 国际加签证、保险（含救援）、通讯、装备托运 |
| 交通方式 | 自驾加防滑链，公共交通加装备打包建议 |
| 天气预测 | 大风加面罩/护目镜，降雪加防水套，极寒加暖宝宝 |

---

## 输出格式

### 场景 A：用户主动触发行前检查

必须包含以下五部分，顺序不可变：

**1. 行程速览**

| 项目 | 信息 |
|------|------|
| 目的地 | 万龙滑雪场，河北崇礼 |
| 出发日期 | 2026-04-15（周三） |
| 返回日期 | 2026-04-17（周五） |
| 行程天数 | 2天1晚 |
| 山顶天气 | -8°C ~ -2°C，小雪，风力 3-4 级 |
| 穿衣建议 | 极寒模式：加厚保暖层+围脖+暖宝宝 |

如行程信息不全，输出"未找到你的行程记录，请告诉我目的地和出发日期"。

**2. 装备检查清单**（按类别分组，每项带勾选框）

根据用户画像和目的地气候动态生成，必须包含以下分类：

| 类别 | 物品 | 数量 | 已确认 | 备注 | 适合你因为 |
|------|------|------|--------|------|-----------|
| 安全必备 | 头盔 | 1 | □ | CE/ASTM 认证 | 你说过安全第一 |
| 安全必备 | 滑雪专项险 | 2天 | □ | 含救援 | 必买！普通旅游险不含滑雪 |
| 安全必备 | 滑雪镜 | 1 | □ | 阴天用增光镜片 | 预报有小雪， visibility 低 |
| 服装 | 防水滑雪外套 | 1 | □ | 防水 10000mm+ | 崇礼-8°C，需防风防水 |
| 服装 | 速干内衣 | 3件 | □ | 聚酯纤维，非棉质 | 2天行程，备1件替换 |
| 服装 | 滑雪袜 | 3双 | □ | 长筒压缩款 | 不要穿两双影响血循环 |
| 服装 | 保暖中间层 | 2件 | □ | 抓绒/轻薄羽绒 | -8°C 需加强保暖 |
| 服装 | 围脖/面罩 | 1 | □ | 防风款 | 崇礼风寒效应明显 |
| 护具 | 护腕 | 1对 | □ | 单板必戴 | 你是单板，保护手腕 |
| 护具 | 护臀/小乌龟 | 1 | □ | 初学者推荐 | 你是初学，减少摔跤痛苦 |
| 配件 | 暖宝宝 | 1包 | □ | 贴手套/鞋里 | -8°C 极寒必备 |
| 配件 | 防晒霜 SPF50+ | 1 | □ | 高海拔紫外线强 | 雪地反射紫外线更强 |
| 电子 | 运动相机 | 1 | □ | GoPro/Insta360 | 方便 AI 教练分析动作 |
| 电子 | 充电宝 | 1 | □ | 低温耗电快 | 崇礼低温手机掉电快 |

**物品数量规则**：
- 速干内衣：按 1件/天 + 1件备用
- 滑雪袜：按 1双/天 + 1双备用
- 中间层：1-2 天带 1 件，3 天+ 带 2 件
- 暖宝宝：崇礼/东北/新疆必带，北京周边/室内可不带

**3. 证件与文档**

| 物品 | 状态 | 备注 |
|------|------|------|
| 身份证/护照 | □ | 国内带身份证，国际带护照+签证 |
| 保险保单 | □ | 电子保单截图存手机 |
| 雪票凭证 | □ | 电子票截图或纸质票 |
| 酒店预订单 | □ | 确认含雪具寄存 |
| 紧急联系人 | □ | 存 1-2 个紧急联系人电话 |

国际目的地额外增加：
| 签证 | □ | 确认有效期 |
| 国际保险（含救援） | □ | 确认覆盖滑雪和医疗转运 |
| 通讯（SIM/漫游） | □ | 确认能接打电话 |
| 信用卡/现金 | □ | 部分雪场只收现金 |

**4. 交通确认**

| 项目 | 状态 | 备注 |
|------|------|------|
| 交通方式 | □ | 自驾/大巴/高铁 |
| 路况查询 | □ | 出发前查实时路况 |
| 停车信息 | □ | 确认雪场停车场位置 |
| 装备打包 | □ | 单板包/双板包或雪具袋 |

如行程信息包含交通方式，自动填充对应检查项。

**5. 天气速报与穿衣建议**

| 时段 | 温度 | 天气 | 风力 | 穿衣建议 |
|------|------|------|------|---------|
| 山顶（实时） | -8°C | 小雪 | 3-4级 | 加厚保暖层+围脖 |
| 出发日预报 | -10°C ~ -3°C | 阴转小雪 | 4-5级 | 防风外套+暖宝宝 |
| 返回日预报 | -6°C ~ 0°C | 多云 | 2-3级 | 正常滑雪着装 |

如天气 API 不可用，使用 WebSearch 搜索并标注"网络搜索天气"。

---

### 场景 B：定时提醒（出发前一天 20:00）

输出格式与场景 A 相同，但开头增加：

> 明天就要去滑雪啦！出发前请花 5 分钟检查以下清单：

末尾增加引导：
> 需要我明天早上 7 点再发一次最终确认清单吗？回复"好的"即可。

### 场景 C：定时提醒（出发当天 07:00）

必须包含以下三部分：

**1. 今日天气速报**

| 项目 | 信息 |
|------|------|
| 山顶实时 | -8°C，小雪，风力 3 级 |
| 体感温度 | -12°C（风寒效应） |
| 穿衣建议 | 极寒模式：速干内衣+抓绒+防水外套+围脖+暖宝宝 |
| 能见度 | 中等（小雪），建议用增光镜片（黄色） |

**2. 最终确认清单**（精简版，只列关键项）

- [ ] 头盔 ✓
- [ ] 滑雪镜（今天小雪，用增光镜片）
- [ ] 雪票凭证
- [ ] 身份证
- [ ] 手机充电宝（低温掉电快）
- [ ] 暖宝宝（贴手套和鞋里）
- [ ] 围脖/面罩

**3. 交通提醒**

> 崇礼今日路况：京礼高速正常通行，预计 2.5 小时到达。停车场位置：万龙滑雪场 1 号停车场（导航搜索"万龙滑雪场停车场"）。

---

## 数据存储

### upcoming_trips.json 结构

```json
[
  {
    "resort": "万龙",
    "city": "河北崇礼",
    "departure_date": "2026-04-15",
    "return_date": "2026-04-17",
    "created_at": "2026-04-11",
    "reminders_set": true,
    "reminder_ids": ["cron-xxx", "cron-yyy"],
    "status": "upcoming"
  }
]
```

状态流转：`upcoming` → `in_progress`（出发当天）→ `completed`（返回后）

### 过期清理

返回日期已过 7 天的行程，标记为 `completed`。超过 30 天的记录可清理（告知用户后执行）。

---

## 定时任务管理

### 创建提醒（需用户明确同意）

```
用户："我 4 月 15 号去万龙滑雪"
Agent：好的，已记录你的行程。是否需要我在出发前一天（4 月 14 号晚上 8 点）和出发当天（4 月 15 号早上 7 点）提醒你检查装备？
用户："好的"
Agent：已创建两个提醒：
  - 4 月 14 日 20:00 装备检查提醒
  - 4 月 15 日 07:00 出发确认提醒
```

### 取消提醒

用户说"取消提醒"或"不用提醒了"时：
1. 读取 upcoming_trips.json 找到对应行程
2. 删除关联的 cron 任务
3. 更新 reminders_set 为 false
4. 告知用户"已取消提醒"

### 查看即将出行的行程

用户说"我近期有什么滑雪行程"时：
1. 读取 upcoming_trips.json
2. 筛选 status 为 upcoming 且 departure_date 在未来 30 天内的记录
3. 按日期排序输出

---

## 输出格式：查看近期行程

必须包含以下表格：

| 目的地 | 出发日期 | 返回日期 | 提醒状态 | 操作 |
|--------|---------|---------|---------|------|
| 万龙 | 2026-04-15 | 2026-04-17 | 已设置 | 可取消/可立即检查 |
| 太舞 | 2026-05-01 | 2026-05-03 | 未设置 | 可设置提醒 |

如无记录，输出"你还没有 upcoming 的滑雪行程，说'我X月X号去XX滑雪'可以添加"。

---

## SHOULD 步骤

- 根据天气预报动态调整穿衣建议（降温自动提醒加厚保暖层）
- 国际场景自动提醒签证有效期、保险覆盖范围
- 提供"一键导出 checklist"功能（生成 Markdown 文件）

## MAY（可选）

- 通过 IM 推送提醒消息（需用户已连接 IM）
- 生成可打印的 PDF 检查清单
- 根据雪场实时客流数据提醒错峰出行


path: modules/presale.md
content: # Module 4: Presale Monitoring — 早鸟预售

**触发词**：早鸟票、预售、雪季卡、季卡、什么时候买划算、帮我盯着、开售提醒、early bird, season pass, presale

**加载知识**：按需读取 `references/resorts-reference.md`（各雪场早鸟规律，仅读取目标雪场相关段落）

---

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 单个雪场查询

1. **确认需求**：雪场名称、滑雪次数（预估）、预算范围
2. **提供历史规律**：从 resorts-reference.md 提取该雪场的历年早鸟时间线和价格规律
3. **搜索当季公告**：WebSearch 搜索 `"{雪场名} 早鸟票 {年份}"` / `"{雪场名} 季卡 预售"`
4. **性价比分析**：对比单次票 vs 次卡 vs 季卡的每滑次成本

### 批量查询（用户问"今年早鸟票情况"或"检查预售状态"）

1. **读取 watchlist**：读取 `~/.ski-assistant/watchlist.json`，如为空则告知用户"监听列表为空，说'帮我盯着XX'可添加"
2. **逐个搜索**：对每个雪场执行 WebSearch 搜索当季公告
3. **状态分组**：按搜索结果分为"已开售"和"未开始"两组，不可混合输出
4. **输出结构化报告**：按下方"输出格式"模板输出

**常见时间线参考**：
- 崇礼 4-6 月、东北 5-7 月、新疆 6-8 月
- Ikon/Epic Pass 3-4 月
- 日本 7-9 月

## 预售监听

**纯被动机制**：技能脚本不创建任何后台任务或定时任务。

1. 用户说"帮我盯着XX" → 保存到 `~/.ski-assistant/watchlist.json`：
   ```json
   {
     "resorts": [
       {
         "name": "万龙滑雪场",
         "keywords": ["万龙 早鸟", "Wanlong season pass"],
         "sources": ["雪场官网", "飞猪"],
         "notify_channels": ["im", "console"],
         "added_at": "2026-04-10T10:00:00+08:00",
         "last_status": "未开始",
         "last_found": null,
         "history": []
       }
     ],
     "last_check": null
   }
   ```

2. 检查方式（仅用户主动触发）：
   - "检查预售状态" → 读取 watchlist.json + WebSearch 查最新公告
   - 直接问"XX早鸟开始了吗" → WebSearch 搜索对应信息

3. 定时检查依赖 Agent 平台的 cron 调度能力，必须经用户明确同意后才能创建。

## 输出格式

### 场景 A：单个雪场查询

必须包含以下四部分：

**1. 历史规律**
该雪场历年早鸟开售时间线和价格规律（从 resorts-reference.md 提取）

**2. 当季公告**
搜索到的最新公告。如无则说明"未搜索到当季公告"，不可省略此节。

**3. 性价比对比表**

| 票种 | 总价 | 预估滑次 | 每滑次成本 | 适合场景 |
|------|------|---------|-----------|---------|
| 单次票 | ¥X | 1 | ¥X | 偶尔滑 1-2 次 |
| 次卡 | ¥X | N | ¥X/次 | 季内滑 3-8 次 |
| 季卡 | ¥X | 不限 | ¥X/次（按N次算） | 季内滑 10 次+ |

**4. 购买建议**
结合用户画像（水平、预估滑次、预算）给出具体建议

### 场景 B：批量查询（watchlist 全量检查）

必须包含以下四部分，顺序不可变：

**1. 已开售列表**（表格，按折扣力度从高到低排序）

| 雪场 | 预售内容 | 折扣力度 | 价格 | 截止时间 | 来源 |
|------|---------|---------|------|---------|------|
| 万龙 | 早鸟季卡 | -40% | ¥3500 | 2026-05-31 | 官网 |

如全部未开售，输出"暂无已开售雪场"，不可省略此节。

**2. 未开始列表**（表格，按预计开售时间从近到远排序）

| 雪场 | 预计开售时间 | 依据 | 监听产品 |
|------|------------|------|---------|
| 北大湖 | 2026年5月 | 历史规律（去年5月中旬） | 早鸟季卡 |

如全部已开售，输出"所有监听雪场均已开售"，不可省略此节。

**3. 时间线**（按月份排列，当年 4 月至次年 1 月）

```
2026年4月: 万龙（已开售）、太舞（已开售）
2026年5月: 北大湖（预计）、松花湖（预计）
2026年6月: 将军山（预计）、可可托海（预计）
2026年7月: Niseko（预计）
...
```

**4. 个性化建议**
结合用户画像（`~/.ski-assistant/user_profile.json`）给出：
- 根据水平推荐适合的票种（如高级用户适合季卡，新手适合次卡）
- 根据预估滑次计算最优选择
- 预算范围内的最优组合

### 场景 C：用户问"XX早鸟开始了吗"

直接回答"是/否"，附具体信息：
- 已开售 → 价格、折扣、购买链接/渠道
- 未开售 → 预计时间、依据、建议关注时间

## 价格趋势

用户手动记录价格追加到 `~/.ski-assistant/price_history.json`。查看时分析最低/最高/平均/当前价位，给出购买时机建议。

## MAY（可选）

- 通过 Agent 平台 cron 创建定期检查任务（需用户同意）
- 通过 IM 推送开售通知（需用户已连接 IM）


path: modules/pricing.md
content: # Module 2: Smart Pricing — 智能查价

**触发词**：多少钱、查价格、预算、便宜票、残票、转让票、低价票、折扣票、捡漏、how much, ticket price, cheap tickets, discount

**加载知识**：按需读取 `references/budget-templates.md`（预算模板）、`references/resorts-reference.md`（早鸟/联票信息）。这 2 个文件无依赖关系，**可并行读取**。

**加载数据**：读取 `data/search_strategies.json` 获取当前区域的搜索策略（关键词模板、官方渠道、flyai 参数）

---

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 场景 A：单个雪场查价（用户问"万龙多少钱"）

1. **路径 0 — 飞猪平台搜索**（优先尝试）
   - 运行 `python3 tools/price_api.py check` 检测 flyai 是否可用
   - **可用** → 从 `data/search_strategies.json` 的 `fliggy_platform` 提取关键词模板，执行 `keyword-search`
   - **不可用** → 降级到路径 B，告知用户"flyai 未安装，跳过飞猪套餐搜索"

2. **路径 B — 雪票价格**（必须走网络）
   - 读取 `data/search_strategies.json` 的 `region_strategies`，根据雪场区域获取推荐关键词
   - 尝试访问官方渠道（`official_channels` 中的微信公众号名称，引导用户自行搜索）
   - WebSearch 搜索 2-3 组关键词（优先使用 search_strategies 中的模板）
   - 尝试 WebFetch 官方网站获取当季票价
   - 兜底：使用数据库 `ticket_price` 字段（标注"数据库参考价"）

3. **输出结果**：按下方"输出格式 - 场景 A"输出

### 场景 B：全渠道比价（用户问"帮我查万龙所有购票渠道的价格"）

1. 依次执行路径 0 → A → B（见下方），然后执行场景 C 的残票/转让票搜索
2. 汇总所有渠道结果
3. **输出结果**：按下方"输出格式 - 场景 B"输出

### 场景 C：残票/转让票/低价票（用户问"有没有便宜的残票"）

1. WebSearch 搜索：`"{雪场名} 残票 转让 {年份}"` / `"{雪场名} 低价票 闲鱼"` / `"{雪场名} 雪票转让 小红书"`
2. 来源优先级：闲鱼 > 小红书 > 抖音 > 微信群
3. **输出结果**：按下方"输出格式 - 场景 C"输出
4. 必须附安全提醒

### 路径 A — 交通 + 住宿（仅场景 B 执行）

1. flyai 可用 → 执行 `search-flight` 和 `search-hotel` 获取实时价格
2. 不可用 → WebSearch 搜索（标注"网络搜索参考价"）
3. 降级时必须告知用户

### 国际价格换算

涉及非 CNY 币种，运行 `python3 tools/exchange_rate.py <amount> <from> <to>`。失败时用备用汇率并标注"参考汇率"。

## 价格可信度标签（必须标注）

每项价格必须附带以下 8 级可信度标签之一：

| 标签 | 含义 | 示例 |
|------|------|------|
| `官方实时` | flyai/官方 API 直接返回 | 飞猪套餐价、官网抓取价 |
| `官方当季` | 官网/公众号当季公告 | 雪场微信公众号发布 |
| `平台实时` | 飞猪/酷雪/住滑等平台当前价 | keyword-search 返回 |
| `搜索参考` | WebSearch 搜索结果中的价格 | 攻略/论坛提到的价格 |
| `数据库参考` | resorts_db.json 中的历史数据 | ticket_price 字段 |
| `上季推算` | 基于上季价格 + 通胀估算 | 无当季数据时 |
| `用户上报` | 用户手动记录的价格 | price_history.json |
| `估算` | 基于同类雪场推算 | 小众雪场无数据时 |

不可使用以上以外的标签。

## 输出格式

### 场景 A：单个雪场查价

必须包含以下三部分，顺序不可变：

**1. 雪票价格**

| 票种 | 价格 | 可信度 | 来源 | 备注 |
|------|------|--------|------|------|
| 全天票 | ¥550 | 官方当季 | 万龙滑雪场公众号 | 2025-2026 雪季 |
| 半日票 | ¥380 | 官方当季 | 万龙滑雪场公众号 | 13:00后入场 |
| 夜场票 | ¥280 | 搜索参考 | 小红书攻略 | 17:00-21:00 |

如未搜索到任何价格，使用数据库兜底并标注"数据库参考价"，同时说明"未找到当季官方价格，以下为历史参考价"。

**2. 购票渠道建议**（按优先级排列）

| 优先级 | 渠道 | 价格 | 优势 | 链接/方式 | 建议你选 |
|--------|------|------|------|---------|---------|
| 1 | 官方公众号 | ¥550 | 最可靠 | 微信搜索"万龙滑雪场" | 首次去推荐这个，省心 |
| 2 | 飞猪 | ¥520 | 可能用优惠券 | keyword-search 结果 | 有 88VIP 可以再减 |
| 3 | 酷雪 | ¥530 | 支持在线选日 | 酷雪小程序 | 想指定日期时用 |

**3. 省钱建议**
- 早鸟票通常 4-6 月开售，折扣 20-40%
- 工作日比周末便宜 15-25%
- 连续多天票均摊更便宜

### 场景 B：全渠道比价

必须包含以下四部分，顺序不可变：

**1. 费用汇总**

| 项目 | 价格 | 可信度 | 来源 | 备注 |
|------|------|--------|------|------|
| 交通 | ¥X | 官方实时/搜索参考 | 说明 | 方式 |
| 住宿 | ¥X/晚 | 平台实时/估算 | 说明 | 档位 |
| 雪票 | ¥X | 官方当季/数据库参考 | 说明 | 票种 |
| 餐饮 | ¥X/天 | 估算 | — | — |
| 装备租赁 | ¥X/天 | 估算 | 如需要 | — |
| 保险 | ¥X | 估算 | 滑雪专项险 | — |
| **合计** | **¥X** | | | |

每项必须同时标注可信度标签和来源说明。

**2. 购票渠道对比**

| 渠道 | 雪票价 | 可信度 | 优缺点 | 适合人群 |
|------|--------|--------|--------|---------|
| 官网 | ¥550 | 官方当季 | 最可靠，无折扣 | 首次去的新手 |
| 飞猪 | ¥520 | 平台实时 | 可用优惠券 | 常旅客 |
| 闲鱼 | ¥400 | 搜索参考 | 便宜但需验真 | 预算有限 |

**3. 三档方案对比**（国际场景必选，国内场景 SHOULD）

| 档位 | 交通 | 住宿 | 雪票 | 合计/天 | 适合人群 | 你的选择 |
|------|------|------|------|---------|---------|---------|
| 经济 | 大巴 | 民宿 | 全天票 | ¥800 | 预算有限 | 如果预算紧张选这个 |
| 标准 | 高铁+接驳 | 雪场旁酒店 | 全天票 | ¥1500 | 性价比优先 | 推荐，省心且体验好 |
| 豪华 | 专车 | 滑进滑出度假村 | 全天票+私教 | ¥3500 | 体验优先 | 想犒劳自己时选 |

**4. 省钱建议**
- 早鸟、季卡、工作日、民宿等具体建议

### 场景 C：残票/转让票

必须包含以下三部分，顺序不可变：

**1. 转让票列表**（按价格从低到高排序）

| 来源 | 票种 | 价格 | 原价 | 折扣 | 日期 | 链接/联系方式 | 可信度 |
|------|------|------|------|------|------|-------------|--------|
| 闲鱼 | 全天票 | ¥350 | ¥550 | -36% | 2026-01-15 | 闲鱼搜索 | 搜索参考 |
| 小红书 | 全天票 | ¥380 | ¥550 | -31% | 2026-01-20 | 小红书搜索 | 搜索参考 |

如未找到任何转让票，输出"暂未找到 {雪场名} 的转让票信息，建议关注闲鱼/小红书"。

**2. 安全提醒**（不可省略）
> ⚠️ 二手票安全提醒：
> - 务必通过正规平台交易（闲鱼 > 微信直接转账）
> - 确认票务可转让（部分雪场实名制不可转）
> - 面交时验证票务 APP 内有效票截图
> - 价格过低（< 5 折）需警惕假票

**3. 备选方案**
如转让票不可用，建议正规渠道购买 + 省钱方式（早鸟/工作日/团购）。

## SHOULD 步骤

- 给出经济/标准/豪华三档方案对比（国际场景）
- 提供省钱建议（早鸟、季卡、工作日、民宿等）
- 外滑套餐附加提醒：签证、汇率、含救援保险、装备托运

## MAY（可选）

- 查询具体日期的价格波动
- 比较不同购票渠道（官网 vs 团购 vs 季卡）
- 使用 `search-poi --category skiing` 搜索雪场周边滑雪相关景点/门票


path: modules/trip-planning.md
content: # Module 1: Trip Planning — 行程规划

**触发词**：推荐雪场、去哪滑、帮我规划、去 XX 滑雪、滑雪攻略、recommend resort, where to ski, plan my trip

**加载知识**：按需读取 `references/travel-guide.md`（攻略模板）、`references/gear-guide.md`（装备）、`references/budget-templates.md`（预算）、`references/resorts-reference.md`（雪场软信息）。这 4 个文件无依赖关系，**可并行读取**。

**加载数据**：读取 `data/search_strategies.json` 获取当前区域的搜索策略（用于实时查价步骤）

---

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 场景 A：信息不全（用户只说"周末去哪滑"）

1. **读取用户画像**：读取 `~/.ski-assistant/user_profile.json`
2. **缺失必填项时提问**：水平、出发城市、天数/日期、预算、单板/双板。缺一项问一项。用户明确说"不限"可跳过
3. 用户回答后，进入场景 B

**用户画像关键字段**：
| 字段 | 说明 | 示例值 |
|------|------|--------|
| `level` | 滑雪水平 | beginner / intermediate / advanced |
| `city` | 出发城市 | "北京" |
| `board_type` | 单板/双板 | "snowboard" / "ski" |
| `style` | 风格偏好（单板） | "carving"（刻滑）/ "park"（平花/公园）/ "freeride"（野雪）/ "all-mountain" |
| `style` | 风格偏好（双板） | "carving"（卡宾）/ "mogul"（蘑菇）/ "freeride"（野雪）/ "all-mountain" |
| `days` | 天数 | 2 |
| `budget` | 预算（元） | 2000 |
| `preferences` | 偏好标签 | ["粉雪", "夜滑", "陡坡"] |
| `avoid` | 避免项 | ["人多", "排队久"] |
| `snow_hours` | 累计雪时（小时） | 50 |
| `ski_days` | 上雪天数 | 10 |
| `mileage` | 累计滑行里程（km） | 100 |

### 场景 B：信息完整（直接出攻略）

1. **读取数据库并打分**：读取 `data/resorts_db.json`，合并 `~/.ski-assistant/custom_resorts.json`（如有）。对候选雪场用打分公式计算（见下方），取 top 3。不可主观判断替代公式
2. **尝试查实时价格**：运行 `python3 tools/price_api.py check`
   - flyai 可用：先执行 `keyword-search`（从 `data/search_strategies.json` 提取关键词）查飞猪套餐，再执行 `search-flight` 和 `search-hotel` 查交通住宿
   - flyai 不可用：WebSearch 搜索（标注"网络搜索参考价"）
3. **国际场景必调汇率**：涉及非 CNY 币种，运行 `python3 tools/exchange_rate.py <金额> <源币种> <目标币种>` 获取实时汇率（如 `python3 tools/exchange_rate.py 10000 JPY CNY`）。失败时用内置备用汇率并标注"参考汇率"
4. **检查数据 freshness**：读取 `data/resorts_db.json` 的 `_meta.updated`。超过 90 天未更新，输出时提醒用户

## 打分公式（必须逐项计算）

对每个候选雪场计算总分（满分约 100）：

| 维度 | 规则 | 分值范围 |
|------|------|---------|
| 基础分 | 固定 | 50 |
| 偏好匹配 | 每项 +8，封顶 4 项 | 0 ~ +32 |
| 板型适配 | 单板+公园雪场 +10，单板+无公园 -5 | -5 ~ +10 |
| 风格适配 | 刻滑+宽陡道 +10，平花+平地地形 +10，野雪+粉雪区 +10，不匹配 -5 | -5 ~ +10 |
| 距离 | <300km: +15, <800km: +8, <2000km: +3 | 0 ~ +15 |
| 时间适配 | 短途+远距: -10, 长途+远距: +3 | -10 ~ +3 |
| 预算适配 | 合预算: +12, 超30%: +4, 超更多: -8 | -8 ~ +12 |
| 经验适配 | 雪时/天数/里程与雪场难度匹配: +10，不匹配（新手去高级场或老手去初级场） -8 | -8 ~ +10 |
| 规模加分 | 落差/面积/雪道数加权 | 0 ~ +10 |
| 雪季适配 | 非雪季室内 +15, 南半球反季 +10, 过季 -30 | -30 ~ +15 |
| 避免项 | 每项 -12 | 每项 -12 |

输出时展示每个推荐雪场的**打分依据简述**（如"偏好+24（粉雪/夜滑/陡坡），距离+8（200km），总分94"），不可只给分数不解释。

## 输出格式

### 场景 A：信息不全（需提问）

必须包含以下两部分：

**1. 缺失信息清单**

| 缺失项 | 示例回答 | 用途 |
|--------|---------|------|
| 滑雪水平 | 初/中/高级 | 匹配雪道难度 |
| 单板/双板 | 单板/双板 | 推荐公园/刻滑道/野雪区 |
| 风格偏好 | 刻滑/平花/野雪 | 匹配雪道类型和地形 |
| 累计雪时 | 约50小时 | 评估实际经验，推荐匹配难度的雪道 |
| 上雪天数 | 约10天 | 判断熟练程度，推荐进阶或休闲雪场 |
| 滑行里程 | 约100km | 衡量体能和耐力，推荐合适规模雪场 |
| 出发城市 | 北京 | 计算距离/交通 |
| 天数/日期 | 周末2天 | 筛选合适雪场 |
| 预算范围 | ¥2000以内 | 过滤超预算选项 |

**2. 引导语**
"告诉我这些信息后，我会从 854 座雪场中用打分公式为你匹配最优选择。单板/双板、风格偏好（刻滑/平花/野雪）和累计雪时会影响推荐结果，帮你找到难度匹配的雪场。"

### 场景 B：信息完整（完整攻略）

必须包含以下七部分，顺序不可变：

**1. 推荐雪场 Top 3**（表格，按分数从高到低）

| 排名 | 雪场 | 地区 | 总分 | 打分依据简述 | 特色标签 | 费用估算 | 推荐理由 |
|------|------|------|------|------------|---------|---------|---------|
| 1 | 万龙 | 河北崇礼 | 94 | 偏好+24（粉雪/夜滑/陡坡），板型+10（单板+公园），风格+10（刻滑+宽陡道），经验+10（50h雪时匹配中级道），距离+8（200km） | 粉雪、陡坡 | ¥1200/天 | 你的单板刻滑风格在这里能找到完美宽陡道，50小时雪时正适合进阶黑道 |
| 2 | 太舞 | 河北崇礼 | 88 | 偏好+16（家庭/度假），板型+5（单板有地形公园），风格适配0，经验+8（适合10天经验巩固），距离+8 | 度假小镇 | ¥1000/天 | 配套完善，适合两天一夜轻松行程，地形公园适合练平花 |
| 3 | 南山 | 北京密云 | 82 | 偏好+8（夜滑），板型+10（单板友好），经验-5（对你偏简单），距离+15（50km） | 性价比高 | ¥600/天 | 距离最近，预算友好，适合周末说走就走，但对你水平略简单 |

不可只给分数不解释打分依据。

**2. 交通方案**（至少 2 个方案）

| 方案 | 路线 | 时间 | 费用 | 步骤 |
|------|------|------|------|------|
| 自驾 | 北京市区→京礼高速→崇礼 | 2.5h | ¥200油费+¥50过路费 | 导航"万龙滑雪场停车场" |
| 大巴 | 北京六里桥→崇礼客运站 | 3.5h | ¥120/人 | 提前在"崇礼客运"公众号购票 |

如只能提供 1 个方案，说明原因（如"该雪场仅支持自驾到达"）。

**3. 住宿分档**

| 档位 | 名称 | 价格 | 距离雪场 | 特色 | 适合你因为 |
|------|------|------|---------|------|-----------|
| 经济 | XX民宿 | ¥300/晚 | 步行10分钟 | 含早餐 | 预算有限但位置好，走路到雪道 |
| 标准 | XX酒店 | ¥600/晚 | 雪场接驳车 | 含雪具寄存 | 性价比最优，接驳车省去停车烦恼 |
| 高端 | XX度假村 | ¥1200/晚 | 滑进滑出 | 含温泉 | 滑完直接泡温泉解乏，体验拉满 |

如某档位无数据，写"—"并说明原因，不可省略该档。

**4. 装备清单**（按用户水平和目的地气候适配）

| 类别 | 必需品 | 可选品 | 备注 |
|------|--------|--------|------|
| 服装 | 防水滑雪服、滑雪裤、手套、护目镜 | 滑雪面罩、头盔 | 崇礼-15°C，需防风保暖层 |
| 装备 | 雪板、雪鞋、雪杖 | — | 可租赁 ¥150-300/天 |
| 配件 | 防晒霜、唇膏 | 暖宝宝 | 高海拔紫外线强 |

**5. 预算汇总**（每项标注来源）

| 项目 | 价格 | 可信度 | 来源 | 备注 |
|------|------|--------|------|------|
| 交通 | ¥250 | 官方实时 | flyai/官网 | 往返 |
| 雪票 | ¥550 | 官方当季 | 微信公众号 | 全天票 |
| 住宿 | ¥600 | 平台实时 | flyai | 标准档1晚 |
| 餐饮 | ¥150/天 | 估算 | — | 雪场内餐厅 |
| 装备租赁 | ¥200/天 | 搜索参考 | 攻略 | 全套 |
| 保险 | ¥30 | 参考 | 滑雪专项险 | 含救援 |
| **合计** | **¥1780** | | | 2天1晚 |

每项必须标注可信度（官方实时/官方当季/平台实时/搜索参考/数据库参考/估算）。

**6. 安全提醒**（不可省略）
- 头盔必戴
- 滑雪专项险必买
- 国际目的地含救援保险

**7. 国际目的地额外包含**（仅国际场景）
- 签证要求及办理时间
- 保险（含救援）
- 汇率及通讯支付方式
- 装备托运建议

如任一项因信息不足无法提供，写明"未包含 XX（原因：...）"，不可省略不告知。

## SHOULD 步骤（应执行，失败须降级并告知）

- 按 `references/travel-guide.md` 模板生成完整攻略
- 查询山顶天气（用 Open-Meteo API，必须传 elevation 参数）
- 给出后续引导问题（如"需要我帮你查具体日期的机票吗？"）

## MAY（可选）

- WebSearch 补充雪票实时价格（当 flyai 不可用时）
- 查询美食推荐和当地特色体验


path: modules/tutorial.md
content: # Module 6: Ski Tutorial — 滑雪教程

**触发词**：新手教程、怎么学滑雪、进阶指南、刻滑怎么练、公园怎么练、ski tutorial, beginner guide, learn to ski, how to snowboard

**加载知识**：
- 必须读取 `references/tutorial-curriculum/_index.md`（级别定义、适配规则、技能包索引、coaching-rubric 维度映射表、**动态生成规则摘要**）
- 首次生成教程时可按需读取 `references/tutorial-curriculum/curriculum-skeleton.md`（完整动态生成协议，含质量检查清单、个性化适配），常规请求 _index.md 中的规则摘要已足够
- 按需读取 `references/tutorial-curriculum/levels/sb-{X}.md`（单板）或 `levels/ski-{X}.md`（双板）（对应级别技能包）
- 按需读取 `references/tutorial-curriculum/training.md`（167 行，文件短可直接读取，或按 `training_framework_snowboard.level_X` / `training_framework_ski.level_X` 定位）
- 按需读取 `references/tutorial-curriculum/faq.md`（119 行，文件短可直接读取，或按 `faq_snowboard.level_X` / `faq_ski.level_X` 定位）
- 按需读取 `references/tutorial-curriculum/gear.md`（57 行，文件短可直接读取，或按 `gear_framework.level_X` 定位）
- 按需读取 `references/tutorial-curriculum/level-common.md`（通用内容：安全须知、雪场礼仪）
- 引用 `references/gear-guide.md`（装备推荐，作为 gear.md 的补充）
- **不读取** `references/coaching-rubric.md`（评分维度映射已内嵌到 _index.md）
- 旧版 level 文件（`legacy-backup/`）已在 v3.0 重构中清理，git 历史已保存

> **读取策略**：`_index.md` 和 `levels/{board}-{level}.md` 无依赖关系，**必须并行读取**。training.md / faq.md / gear.md 文件较短（<200 行），可直接读取。常规教程请求不需要读 curriculum-skeleton.md（规则摘要已在 _index.md 中）。

---

## MUST 步骤（不可跳过，跳过须告知用户原因）

### 场景 A：主动请求教程（"给我一份新手教程"、"怎么学滑雪"）

1. **确认板型**：询问用户是单板（snowboard）还是双板（ski）。如 `~/.ski-assistant/user_profile.json` 中有 `board_type` 字段可直接使用
2. **确认水平**：从 `~/.ski-assistant/user_profile.json` 读取 `level`。如无记录或用户表述模糊，执行场景 C 水平校准
3. **读取教程索引**：读取 `references/tutorial-curriculum/_index.md` 获取级别定义、技能骨架、训练框架、FAQ 框架、装备框架、**动态生成规则摘要**
4. **读取对应级别技能包**：并行读取 `levels/sb-{X}.md`（单板）或 `levels/ski-{X}.md`（双板）
5. **读取通用内容**：读取 `references/tutorial-curriculum/level-common.md`（安全须知、雪场礼仪等通用内容）
6. **动态生成教程**：按 `_index.md` 中的动态生成规则摘要，从技能包元数据动态生成教程内容
   - 从技能元数据读取 why_important / action_guide_template / common_mistakes_template / practice_template / success_signal
   - 从 training.md 读取训练计划，从 faq.md 读取 FAQ 要点，从 gear.md 读取装备决策规则
   - **仅当需要质量检查清单或个性化适配时**，才读取 `curriculum-skeleton.md` 获取完整协议
7. **个性化调整**：根据 `~/.ski-assistant/user_profile.json` 的 `style/freestyle` 偏好和 `~/.ski-assistant/records.json` 的历史评分，调整技能顺序和重点
8. **输出教程**：按下方"输出格式 - 场景 A"输出
9. **引导闭环**：末尾引导用户"完成后发视频给 AI 教练打分验证"

> **备用方案**：如动态生成失败（如 `_index.md` 技能元数据不完整），回退到读取 `levels/sb-{X}.md`（单板）或 `levels/ski-{X}.md`（双板），并告知用户"教程正在更新中，当前显示旧版内容"。

### 场景 B：教练推荐教程（从 coaching 场景 A 流转）

1. AI 教练打分后，对比当前级别目标分数（从 `_index.md` 的 coaching-rubric 维度映射表读取）
2. 找出低于目标分的维度
3. 从 `_index.md` 的技能骨架中定位对应 `rubric_mapping` 的技能
4. 推荐对应教程章节（"你的转弯技术 5.0/10，Level 1 目标 6.0，建议参考 Level 1 教程 — 转弯技术章节"）
5. 用户同意后，按 `curriculum-skeleton.md` 规则动态生成对应技能讲解

### 场景 C：水平校准

当用户自评水平与实际情况可能不符时，执行 2-3 个验证问题：

**单板验证问题**：
1. "你能在绿道上完成落叶飘（左右移动方向）吗？"
2. "你能独立完成 S 弯转弯吗？转弯之间不停顿"
3. "上缆车时能自己穿脱雪板吗？"

**双板验证问题**：
1. "你能在绿道上完成平行转弯吗？双板保持平行"
2. "你能控制转弯大小（大弯和小弯）吗？"
3. "上缆车时能自己穿脱雪板吗？"

根据回答判断真实水平：
- 3 个都"能" → 确认用户自评
- 2 个"能" → 可能是用户自评，建议从该级别开始
- 1 个或 0 个"能" → 温和建议降低级别

### 场景 D：查看教程目录（"教程都有哪些级别？"）

1. 读取 `_index.md` 获取级别列表
2. 按下方"输出格式 - 场景 D"输出
3. 根据用户档案标记当前建议级别

---

## 输出格式

### 场景 A：教程内容输出

> 以下格式定义教程的最终输出结构。具体内容由 `curriculum-skeleton.md` 协议驱动，从 `_index.md` 的技能骨架动态生成。

必须包含以下九部分，顺序不可变：

**1. 免责声明**（必须放在最开头）

> ⚠️ 本教程由 AI 生成，基于 PSIA-AASI 教学框架和 AI 电子教练评分标准生成，不能替代专业滑雪教练的现场指导。滑雪有风险，请在安全环境下学习，佩戴头盔，购买滑雪专项保险。

**2. 版本标注**

格式：`版本：v3.0 | 架构：动态教程生成`

**3. 级别标题**

格式：`## [板型] Level [X] — [级别名称]教程`

**4. 本级别适合你吗**

基于 `_index.md` 中级别定义的"定义"列，生成 3-4 句自我评估引导。

**5. 训练计划**

基于 `_index.md` 的 `training_framework` 生成天数、时长、技能顺序表格。

必须包含以下列：

| 阶段 | 技能 | 时长 | 权重 | 关键目标 |
|------|------|------|------|---------|

**6. 核心技能详解**

每个技能必须包含以下 5 个子章节（按 `curriculum-skeleton.md` 规则 1）：

- **为什么重要**：基于 `why_important` 展开为 2-3 句自然语言
- **怎么做**：基于 `action_guide_template` 展开为分步指导（至少 3 步）
- **常见错误**：基于 `common_mistakes_template` 展开为「错误 + 后果 + 纠正」三段式
- **练习方法**：基于 `practice_template` 展开为具体步骤，保留数量和组数
- **成功信号**：基于 `success_signal` 展开为可自检的描述

Level 2+ 核心技能在末尾附加术语对照（从技能的 `terms` 字段读取）。

**7. 装备清单**

基于 `_index.md` 的 `gear_framework` 按优先级分类生成。

**8. 常见问题**

基于 `_index.md` 的 `faq_framework` 生成 5-8 个自然语言问答。

**9. 下一步**

基于级别递进关系生成进阶指引。如有 `~/.ski-assistant/records.json` 历史记录，提及上次进度。

如任一项因信息不足无法提供，写明原因，不可省略不告知。

### 场景 B：教练推荐教程

输出格式：

| 维度 | 得分 | 目标 | 状态 |
|------|------|------|------|
| 基础姿态 | X/10 | ≥ X | ✅/⚠️ |
| 转弯技术 | X/10 | ≥ X | ✅/⚠️ |
| 综合滑行 | X/10 | ≥ X | ✅/⚠️ |
| 自由式 | X/10 | ≥ X | ✅/⚠️/— |

注：自由式仅在公园/mogul/跳台场景评分，普通雪道显示"—"。

**重点关注**：[低于目标的维度]

📚 **建议参考教程**：[Level X 教程 — 具体章节]

核心练习：
1. ...
2. ...

练完后再发视频给我重新打分。

### 场景 C：水平校准

输出验证问题表格，根据回答判断水平，温和建议合适的起始级别。

### 场景 D：教程目录

| 级别 | 适合人群 | 核心能力 | 预计掌握时间 |
|------|---------|---------|------------|
| Level 0 — 零基础 | ... | ... | ... |

**当前状态**：你的用户档案显示 level=XXX，建议从 Level X 开始。

---

## 数据适配规则

从 `_index.md` 读取适配规则，根据以下维度动态调整教程内容：

| 维度 | 数据源 | 影响内容 |
|------|--------|---------|
| board_type | `~/.ski-assistant/user_profile.json` | 选择 `skills_snowboard_level_X` 或 `skills_ski_level_X` |
| style / freestyle | `~/.ski-assistant/user_profile.json` | Level 3 选择风格路线（carving / freestyle / powder / mogul） |
| level | `~/.ski-assistant/user_profile.json` | 决定读取哪个级别的技能骨架 |
| snow_hours / ski_days | `~/.ski-assistant/user_profile.json` / `~/.ski-assistant/records.json` | 跳过已掌握的阶段 |
| 最近评分 | `~/.ski-assistant/records.json` | 弱项强化：找出评分最低的子项，在对应技能讲解中增加针对性建议 |

---

## 输出规则

1. **免责声明不可省略**：每次输出教程必须在开头包含免责声明
2. **版本标注不可省略**：在免责声明后立即标注版本
3. **板型适配**：根据用户板型输出对应内容，不要同时输出单板和双板（除非用户明确要求对比）
4. **技能优先级**：按 `skill_sequence` 定义的顺序排列，建议用户按顺序练习
5. **成功信号可验证**：每个技能的成功信号必须是具体可验证的行为，不是模糊描述
6. **引导闭环**：每个级别末尾引导用户发视频给 AI 教练打分验证
7. **国际术语对照**：Level 0-1 不显示术语对照，Level 2+ 在核心技能末尾显示一行术语对照（从技能 `terms` 字段读取）
8. **动态生成优先**：优先使用 `_index.md` 技能骨架 + `curriculum-skeleton.md` 协议动态生成。旧版 level 文件仅作备用

---

## 国际术语对照显示规则（方案 C）

**Level 0-1**：不显示术语对照

**Level 2+**：在核心技能（转弯技术、姿态进阶）末尾添加术语对照，从技能的 `terms` 字段读取：

```markdown
**术语对照**：
- PSIA-AASI：[terms.psia]
- CASI：[terms.casi]
- CSIA：[terms.csi]
```

**规则**：
- 只在有 `terms` 字段的技能显示
- 不超过 2 行
- 不展开讲解差异
- 用户主动询问"这个在 CASI 里叫什么"时，输出 `_index.md` 中的完整对照表

---

## MAY（可选）

- **生成 DOCX 教程文件**（完整版排版，用户明确要求时）
  - 使用 docx skill 创建专业排版
  - 包含封面、目录、章节标题、表格、图片占位
  - 文件名：`Level[X]_[board_type]_Tutorial_v3.0.docx`
- 根据用户已有 `records.json` 记录，跳过已掌握的技能
- 推荐附近适合练习该级别技能的雪场

---

## DOCX 导出规范

当用户明确要求"生成 DOCX 教程"或"导出为 Word 文档"时：

1. 调用 docx skill
2. 创建以下结构：
   - 封面：级别标题 + 板型 + 版本
   - 目录：自动生成
   - 正文：按教程内容格式
   - 表格：级别目标、训练计划、里程碑
   - 页脚：页码 + 免责声明
3. 输出到工作目录的 `outputs/` 文件夹
4. 提供 file:// 链接给用户


path: references/budget-templates.md
content: # 滑雪行程预算参考

本文件提供标准预算计算公式和参考价格区间。为 `modules/pricing.md` 和 `modules/trip-planning.md` 提供预算参考数据。

## 标准费用项

| 费用项 | 计算公式 | 说明 |
|--------|---------|------|
| 交通（往返） | 单价 × 人数 | 机票/高铁/自驾油费+过路费 |
| 住宿 | 单价 × 晚数 | 晚数通常 = 天数 - 1（当日往返为 0） |
| 雪票 | 单价 × 滑雪天数 × 人数 | 滑雪天数 ≤ 总天数 |
| 装备租赁 | 单价 × 滑雪天数 × 人数 | 自带装备则为 0 |
| 餐饮 | 单价 × 天数 × 人数 | 含雪场午餐 + 早晚餐 |
| 当地交通 | 单价 × 人数 | 接驳巴士/打车/租车 |
| 保险 | 单价 × 人数 | 滑雪专项保险 |
| 其他 | 单价 × 人数 | 温泉、购物等 |

**合计** = 各项之和
**人均** = 合计 ÷ 人数

---

## 国内雪场参考价格

### 崇礼（万龙/太舞/云顶/富龙）

| 费用项 | 经济档 | 标准档 | 高端档 |
|--------|--------|--------|--------|
| 交通（北京出发高铁） | ¥130-180/人 | ¥130-180/人 | ¥350/人（自驾/包车） |
| 住宿 | ¥200-400/晚 | ¥400-800/晚 | ¥800-2000/晚 |
| 雪票 | ¥400-500/天 | ¥450-550/天 | ¥550-650/天（含夜场） |
| 装备租赁 | ¥150-200/天 | ¥200-300/天 | 自带 |
| 餐饮 | ¥80-120/天/人 | ¥120-200/天/人 | ¥200-400/天/人 |
| 保险 | ¥25-50/人 | ¥50-80/人 | ¥80-150/人 |

### 东北（亚布力/北大湖/松花湖/长白山）

| 费用项 | 经济档 | 标准档 | 高端档 |
|--------|--------|--------|--------|
| 交通（机票） | ¥800-1500/人 | ¥1200-2000/人 | ¥2000-3000/人 |
| 住宿 | ¥200-400/晚 | ¥400-800/晚 | ¥800-1500/晚 |
| 雪票 | ¥350-450/天 | ¥400-550/天 | ¥500-680/天 |
| 装备租赁 | ¥100-180/天 | ¥180-280/天 | 自带 |
| 餐饮 | ¥60-100/天/人 | ¥100-180/天/人 | ¥180-350/天/人 |
| 当地交通 | ¥50-100/人 | ¥100-200/人 | ¥200-500/人 |
| 保险 | ¥25-50/人 | ¥50-80/人 | ¥80-150/人 |

### 新疆（阿勒泰/可可托海/将军山）

| 费用项 | 经济档 | 标准档 | 高端档 |
|--------|--------|--------|--------|
| 交通（机票） | ¥1200-2000/人 | ¥1800-2800/人 | ¥2500-4000/人 |
| 住宿 | ¥150-300/晚 | ¥300-600/晚 | ¥600-1200/晚 |
| 雪票 | ¥200-350/天 | ¥300-450/天 | ¥400-580/天 |
| 餐饮 | ¥50-80/天/人 | ¥80-150/天/人 | ¥150-300/天/人 |

---

## 国际雪场参考价格

### 日本（北海道/白马/妙高）

| 费用项 | 经济档 | 标准档 | 豪华档 |
|--------|--------|--------|--------|
| 机票（往返） | ¥2000-3500/人 | ¥3000-5000/人 | ¥5000-8000/人 |
| 住宿 | ¥300-500/晚（民宿） | ¥500-1000/晚 | ¥1000-3000/晚（温泉酒店） |
| 雪票 | ¥300-400/天 | ¥350-500/天 | ¥500-700/天（含夜场） |
| JR Pass/交通 | ¥500-800/人 | ¥800-1200/人 | ¥1500-2500/人（包车） |
| 餐饮 | ¥100-200/天/人 | ¥200-400/天/人 | ¥400-800/天/人 |
| 保险（含救援） | ¥50-100/人 | ¥100-200/人 | ¥200-400/人 |

### 欧洲（法国/瑞士/奥地利）

| 费用项 | 经济档 | 标准档 | 豪华档 |
|--------|--------|--------|--------|
| 机票（往返） | ¥4000-6000/人 | ¥6000-9000/人 | ¥9000-20000/人 |
| 住宿 | ¥400-700/晚 | ¥700-1500/晚 | ¥1500-5000/晚 |
| 雪票（联票） | ¥400-600/天 | ¥500-700/天 | ¥600-900/天 |
| 餐饮 | ¥200-350/天/人 | ¥350-600/天/人 | ¥600-1200/天/人 |
| 保险（含救援） | ¥100-200/人 | ¥200-400/人 | ¥400-800/人 |

### 北美（惠斯勒/范尔/帕克城）

| 费用项 | 经济档 | 标准档 | 豪华档 |
|--------|--------|--------|--------|
| 机票（往返） | ¥5000-8000/人 | ¥7000-12000/人 | ¥12000-25000/人 |
| 住宿 | ¥500-800/晚 | ¥800-1500/晚 | ¥1500-5000/晚 |
| 雪票（Ikon/Epic） | ¥500-800/天 | ¥600-900/天 | ¥800-1200/天 |
| 餐饮 | ¥200-400/天/人 | ¥400-700/天/人 | ¥700-1500/天/人 |
| 租车 | ¥200-400/天 | ¥400-700/天 | ¥700-1500/天 |

---

## 省钱攻略要点

- **早鸟票**：提前 3-6 个月购买，通常比现场便宜 30-50%
- **季卡/次卡**：滑 5 次以上考虑季卡，Ikon/Epic 通卡覆盖多个雪场
- **工作日**：周中雪票通常便宜 20-40%
- **住宿**：雪场山下比山上便宜 30-50%，民宿/青旅可大幅降低成本
- **装备**：初学者全租，进阶后从二手市场购入
- **餐饮**：自带午餐可省下雪场高价餐食

## 保险特别提醒

- 普通旅游险**不含**滑雪等高风险运动
- 国内滑雪：每天 ¥25-50 即可获得基本保障
- 国际滑雪：**必须**购买含紧急救援和医疗转运的保险，每天 ¥100-200
- 推荐在出发前购买，而非到达雪场后


path: references/coaching-rubric.md
content: # AI 电子教练评分参考

本文件定义滑雪姿态分析的评分维度、评分细则和分析输出格式。为 `modules/coaching.md` 提供评分标准的详细参考。

## 评分维度（满分 10 分）

### 一、基础姿态（posture）

| 子项 | 英文 key | 评分要点 |
|------|---------|---------|
| 重心位置 | center_of_gravity | 重心应在双脚之间偏前，膝盖在脚尖正上方。重心过后（坐在板上）扣分严重 |
| 膝盖弯曲 | knee_bend | 膝盖应保持适度弯曲（约 15-25°），过直或过弯都扣分 |
| 上半身姿态 | upper_body | 上半身应微前倾，面向山下。后仰或侧倾扣分 |
| 手臂位置 | arm_position | 双臂自然前伸，高度在腰部以上。手臂乱甩或紧贴身体扣分 |
| 髋部对齐 | hip_alignment | 髋部应面向行进方向，不应过度旋转 |
| 踝关节屈曲 | ankle_flex | 踝关节应有适度前压，保持小腿贴合雪鞋前壁 |

### 二、转弯技术（turning）

| 子项 | 英文 key | 评分要点 |
|------|---------|---------|
| 平行站姿 | parallel_stance | 双板应保持平行，间距约肩宽。内八字或外八字扣分 |
| 立刃角度 | edge_angle | 转弯时雪板应有明确立刃，角度越大表示技术越好 |
| 换刃时机 | edge_transition | 换刃应平滑连贯，不应有明显停顿或中间阶段 |
| 卡宾质量 | carving_quality | 雪面应留下清晰弧线（非搓雪），雪花飞溅越少越好 |
| 弯型控制 | turn_shape | 弯型应圆滑对称，大小一致。S 弯连接流畅 |
| 点杖技术 | pole_plant | 点杖应在转弯入弯点前方，动作轻巧，引导转弯节奏 |

### 三、自由式/公园（freestyle）

仅在公园/mogul/跳台场景评分。普通雪道不评此维度。

| 子项 | 英文 key | 评分要点 |
|------|---------|---------|
| 起跳 | takeoff | 起跳时机、角度和力度 |
| 空中控制 | air_control | 空中身体姿态控制、轴心稳定 |
| 落地 | landing | 落地稳定性、膝盖缓冲 |
| 技巧完成度 | trick_execution | 动作完成度和精确性 |
| 风格表现 | style | 动作流畅度和个人风格 |

### 四、综合滑行（overall）

| 子项 | 英文 key | 评分要点 |
|------|---------|---------|
| 速度控制 | speed_control | 能否根据地形和人流控制速度，不失控 |
| 路线选择 | line_choice | 是否选择合适的滑行路线，利用地形 |
| 地形适应 | terrain_adaptation | 对不同地形（陡坡、缓坡、冰面、粉雪）的适应能力 |
| 节奏感 | rhythm | 转弯和滑行的节奏是否连贯一致 |
| 自信度 | confidence | 滑行是否自信流畅，无犹豫或恐惧感 |
| 安全意识 | safety_awareness | 是否注意周围环境、保持安全距离 |

---

## 分析输出格式

Agent 分析完照片后，输出须包含以下内容：

```json
{
  "scores": {
    "posture": {
      "center_of_gravity": 7.5,
      "knee_bend": 6.0,
      "upper_body": 8.0,
      "arm_position": 7.0,
      "hip_alignment": 6.5,
      "ankle_flex": 5.5
    },
    "turning": {
      "edge_angle": 6.5,
      "turn_shape": 7.0,
      "edge_transition": 5.5,
      "carving_quality": 6.0,
      "pole_plant": 4.0
    },
    "overall": {
      "speed_control": 7.5,
      "line_choice": 7.0,
      "terrain_adaptation": 6.0,
      "confidence": 7.5,
      "safety_awareness": 8.0
    }
  },
  "highlights": ["亮点1", "亮点2"],
  "issues": ["问题1", "问题2"],
  "advice": ["具体可执行的改进建议1", "建议2"],
  "coach_note": "一句话总结"
}
```

### 关键规则

1. **所有分数 1-10 分**，精确到 0.5
2. **freestyle 维度**仅在公园/mogul/跳台场景出现，普通雪道不评
3. **highlights** 和 **issues** 应具体到动作细节（如"膝盖弯曲角度好"而非"姿势不错"）
4. **advice** 必须是可执行的训练建议（如"在缓坡反复练习换刃，关注上半身保持面向山下"）
5. 照片模糊或角度不佳时，在 coach_note 中说明，并建议侧面 15-60 秒视频或清晰静态照片

---

## 记录保存格式（JSON Lines）

每次分析结果追加到 `~/.ski-assistant/records.json`（JSON 数组格式）：

```json
{
  "id": "20260115-143025",
  "date": "2026-01-15",
  "resort": "万龙滑雪场",
  "run_name": "银龙道",
  "trail_difficulty": "blue",
  "snow_condition": "粉雪",
  "media_type": "photo",
  "media_path": "/path/to/photo.jpg",
  "level": "intermediate",
  "sport_type": "alpine",
  "scores": { ... },
  "dimension_averages": {"posture": 6.8, "turning": 5.8, "overall": 7.0},
  "total_score": 6.5,
  "highlights": [...],
  "issues": [...],
  "advice": [...],
  "coach_note": "...",
  "recorded_at": "2026-01-15T14:30:25+08:00"
}
```

- `dimension_averages`：每个维度所有子项的平均分
- `total_score`：所有维度平均分的平均值
- `id` 格式：`YYYYMMDD-HHMMSS`

---

## 进步报告规则

生成进步报告时，对比首次和最近一次记录：

- 变化 > +0.5 → 标记为"进步"
- 变化 < -0.5 → 标记为"退步"
- 变化在 ±0.5 以内 → 标记为"稳定"

统计反复出现的 issues（出现 2 次以上），作为重点改进方向。

## 雪季总结规则

雪季定义：当年 10 月 1 日至次年 5 月 31 日。自动按最近记录的日期推断所属雪季。

总结包含：总次数、去过的雪场、评分变化趋势、各维度成长、本季亮点、持续改进方向、水平提升情况。

## 视觉模型配置

支持的视觉模型提供商：

| 提供商 | 模型 | API Key 环境变量 | 端点 |
|--------|------|-----------------|------|
| OpenAI | gpt-4o, gpt-4o-mini | OPENAI_API_KEY | https://api.openai.com |
| Anthropic | claude-sonnet-4-20250514, claude-3.5-sonnet | ANTHROPIC_API_KEY | https://api.anthropic.com |
| Google | gemini-2.0-flash, gemini-2.0-pro | GOOGLE_API_KEY | generativelanguage.googleapis.com |
| 通义千问 | qwen-vl-max, qwen-vl-plus | DASHSCOPE_API_KEY | dashscope.aliyuncs.com/compatible-mode |
| 豆包 | doubao-vision-pro, doubao-vision-lite | DOUBAO_API_KEY | ark.cn-beijing.volces.com |
| 阶跃星辰 | step-1v | STEPFUN_API_KEY | api.stepfun.com |
| 智谱 | glm-4v-plus, glm-4v | ZHIPU_API_KEY | open.bigmodel.cn |

未配置任何 API Key 时，Agent 使用自身视觉能力按本文档标准完成分析。


path: references/gear-guide.md
content: # 滑雪装备参考

本文件为 ski-assistant 的装备知识库，按类别、水平、目的地提供装备推荐和价格参考。为 `modules/trip-planning.md` 生成装备清单时提供数据支撑。

## 装备数据库

### 安全必备（所有水平必带）

| 物品 | 可租用 | 经济档 | 中档 | 高端档 | 备注 |
|------|--------|--------|------|--------|------|
| 滑雪头盔 | ❌ 需购买 | ¥150-250 | ¥300-600 | ¥600-1500 | 必戴！选 CE/ASTM 认证产品 |
| 滑雪镜 | ❌ 需购买 | ¥80-150 | ¥200-400 | ¥400-1000 | 阴天用增光镜片（黄/橙），晴天用偏光镜片 |
| 高倍防晒霜 SPF50+ | ❌ 需购买 | ¥50-80 | ¥100-150 | ¥150-300 | 高海拔+雪地反射紫外线极强 |
| 滑雪专项保险 | ❌ 需购买 | ¥30-50/天 | ¥50-100/天 | ¥100-200/天 | 普通旅游险不含滑雪，必须买专项险！国际需含紧急救援 |

### 服装（户外雪场必备，室内酌情精简）

| 物品 | 可租用 | 租金 | 经济档 | 中档 | 高端档 | 备注 |
|------|--------|------|--------|------|--------|------|
| 滑雪外套/冲锋衣 | ✅ | ¥50-100/天 | ¥200-400 | ¥500-1000 | ¥1000-3000 | 防水10000mm+、透气8000g+，颜色鲜艳方便辨认 |
| 滑雪裤 | ✅ | ¥30-60/天 | ¥150-300 | ¥400-800 | ¥800-2000 | 背带裤防雪效果优于普通裤 |
| 速干内衣（排汗层） | ❌ | — | ¥50-100 | ¥100-200 | ¥200-500 | 棉质不透气，选聚酯纤维或美利奴羊毛 |
| 保暖中间层（抓绒/轻薄羽绒） | ❌ | — | ¥80-150 | ¥200-400 | ¥400-800 | 崇礼/东北需-10°C以下保暖层，北海道需更厚 |
| 滑雪手套 | ✅ | ¥20-40/天 | ¥50-100 | ¥100-250 | ¥250-600 | 防水保暖，连指手套比五指更暖 |
| 滑雪袜（长筒） | ❌ | — | ¥30-50 | ¥60-120 | ¥120-250 | 有压缩支撑减少小腿疲劳，不要穿两双（影响血循环） |
| 围脖/面罩 | ✅ | ¥10-20/天 | ¥20-40 | ¥50-100 | ¥100-200 | 崇礼/东北必备 |

### 护具

| 物品 | 适用对象 | 可租用 | 租金 | 经济档 | 中档 | 备注 |
|------|---------|--------|------|--------|------|------|
| 护腕 | 单板初学/进阶 | ✅ | ¥20-30/天 | ¥50-100 | ¥100-200 | **单板初学者必戴**，大幅降低手腕骨折风险 |
| 护膝 | 单板初学/进阶 | ✅ | ¥20-30/天 | ¥50-100 | ¥100-200 | 单板摔膝盖概率高 |
| 小乌龟/护臀 | 单板初学者 | ✅ | ¥15-30/天 | ¥30-60 | ¥60-120 | 减少摔跤痛苦，提高练习信心 |
| 护背 | 进阶/高级 | ✅ | ¥30-50/天 | ¥100-200 | ¥200-400 | 公园跳台或刻滑时保护脊椎 |
| 雪崩搜救仪 | 高级/专家（野雪） | ✅ | ¥50-100/天 | ¥800-1500 | ¥1500-3000 | 野雪/非雪道必备，需搭配探杆和雪铲 |

### 滑雪器材

| 物品 | 可租用 | 租金 | 经济档 | 中档 | 高端档 | 备注 |
|------|--------|------|--------|------|--------|------|
| 双板（板+固定器+雪杖） | ✅ | ¥100-200/天 | ¥1500-3000 | ¥3000-6000 | ¥6000-15000 | 初学者建议租雪场的，水平提升后再购买 |
| 单板（板+固定器） | ✅ | ¥100-200/天 | ¥1500-3000 | ¥3000-6000 | ¥6000-15000 | 初学者建议租，学会推坡和换刃后再购买 |
| 滑雪鞋 | ✅ | ¥50-100/天 | ¥800-1500 | ¥1500-3000 | ¥3000-6000 | 鞋子合脚最重要！建议先租再买，买前务必试穿 |

### 电子产品与配件

| 物品 | 适用对象 | 可租用 | 经济档 | 中档 | 备注 |
|------|---------|--------|--------|------|------|
| 运动相机（GoPro/Insta360） | 所有水平 | ✅ ¥50-100/天 | ¥500-1000 | ¥1500-3000 | 记录滑雪视频，方便 AI 教练分析动作 |
| 暖宝宝/暖手贴 | 所有水平 | ❌ | ¥10-20/包 | ¥20-40/包 | 贴在手套或鞋里，极寒天气必备 |

---

## 目的地气候适配

| 区域 | 温度范围 | 额外必备 | 特殊提醒 |
|------|---------|---------|---------|
| 崇礼 | -25°C ~ -5°C | 围脖、暖宝宝 | 风寒效应明显，需充分保暖 |
| 东北（亚布力/北大湖/松花湖/长白山） | -35°C ~ -10°C | 围脖、暖宝宝 | 全国最冷区域，需极地级保暖 |
| 新疆（阿勒泰/可可托海/将军山） | -25°C ~ -5°C | 围脖、暖宝宝、防晒 | 粉雪天堂，紫外线强需防晒 |
| 北京周边（南山/军都山/石京龙） | -15°C ~ 0°C | 防晒 | 当日往返无需太多行李 |
| 日本（北海道/白马/二世谷/妙高/富良野） | -15°C ~ 0°C | 暖宝宝、防晒 | 降雪量大需防水性能好的装备；粉雪区宽板更适合 |
| 欧洲（阿尔卑斯/夏蒙尼/采尔马特） | -20°C ~ 0°C | 防晒 | 海拔高紫外线强 |
| 北美（惠斯勒/范尔/帕克城） | -15°C ~ 5°C | 防晒 | 温差大需分层穿衣 |
| 南半球（皇后镇/新西兰） | -10°C ~ 5°C | 防晒 | 反季滑雪（6-10月），白天可能到 5°C |
| 室内雪场 | -5°C ~ -3°C（恒温） | 无 | 无需厚重保暖层，但外套仍必须 |

---

## 租用 vs 购买建议

- **初学者**：所有器材建议租用，滑 3 天后再决定是否购买
- **短期出行（1-3 天）**：可租装备全部租用更划算
- **长期出行（5 天+）**：可租装备考虑购买（总租金可能超过购买价）
- **头盔、雪镜、内衣、袜子**：卫生考虑，建议购买

## 穿衣数量建议

- **1-2 天**：速干内衣 2 件、外套 1 套、中间层 1 件、滑雪袜 2 双
- **3-4 天**：速干内衣 3 件、外套 1 套、中间层 2 件、滑雪袜 3 双
- **5 天+**：速干内衣按 1 件/天（可中途清洗）、外套 1-2 套、中间层 2-3 件、袜子 1 双/天

## 安全提醒

1. **头盔必戴**！无论水平高低
2. **滑雪专项保险必买**，普通旅游险通常不含滑雪
3. **单板初学者必戴护腕**，可大幅降低手腕骨折风险
4. 崇礼/东北等极寒地区，建议贴暖宝宝在手套和鞋里
5. 国际出行保险需含紧急救援和医疗转运


path: references/pre-departure-checklist.md
content: # 行前检查清单模板

本文件为 ski-assistant 的行前检查知识库，提供标准化 checklist 模板和动态生成规则。为 `modules/pre-departure.md` 生成检查清单时提供数据支撑。

---

## 基础检查清单（所有场景通用）

### 安全必备（不可省略）

| 物品 | 必带 | 可租 | 说明 |
|------|------|------|------|
| 头盔 | 必带 | 否 | CE/ASTM 认证，不可省略 |
| 滑雪专项险 | 必带 | 否 | 普通旅游险不含滑雪，国际需含救援 |
| 滑雪镜 | 必带 | 部分 | 按天气选镜片：晴天偏光，阴天增光 |
| 防晒霜 SPF50+ | 必带 | 否 | 雪地反射紫外线极强 |
| 身份证/护照 | 必带 | 否 | 国内身份证，国际护照+签证 |

### 服装基础

| 物品 | 1-2天 | 3-4天 | 5天+ | 说明 |
|------|-------|-------|------|------|
| 速干内衣 | 2件 | 3件 | 1件/天 | 聚酯纤维或美利奴羊毛，不穿棉质 |
| 滑雪袜 | 2双 | 3双 | 1双/天 | 长筒压缩款，不穿两双 |
| 滑雪外套 | 1件 | 1件 | 1-2件 | 防水 10000mm+ |
| 滑雪裤 | 1条 | 1条 | 1-2条 | 背带裤防雪更好 |
| 保暖中间层 | 1件 | 2件 | 2-3件 | 抓绒或轻薄羽绒 |
| 滑雪手套 | 1双 | 1双 | 1-2双 | 连指比五指更暖 |

---

## 按目的地气候适配

### 极寒模式（崇礼/东北，低于 -15°C）

**额外必带**：
| 物品 | 数量 | 说明 |
|------|------|------|
| 围脖/面罩 | 1 | 防风款，覆盖口鼻 |
| 暖宝宝 | 1-2包 | 贴手套内侧和鞋里 |
| 加厚保暖层 | 1件 | 厚抓绒或羽绒服 |
| 护手霜 | 1 | 防冻裂 |

**穿衣建议**：速干内衣 + 厚抓绒 + 防水外套 + 围脖 + 暖宝宝

### 寒冷模式（新疆/日本北海道，-15°C ~ -5°C）

**额外必带**：
| 物品 | 数量 | 说明 |
|------|------|------|
| 围脖/面罩 | 1 | 崇礼/东北同等级防风 |
| 暖宝宝 | 1包 | 可选，怕冷的人必带 |
| 防水套 | 1套 | 电子器件防水（粉雪区） |

### 温和模式（北京周边，-5°C ~ 0°C）

**可精简**：
- 无需厚重保暖层
- 暖宝宝可不带
- 围脖可选

### 室内雪场模式（恒温 -5°C ~ -3°C）

**可精简**：
| 可省略 | 仍需 |
|--------|------|
| 厚重保暖层 | 滑雪外套（必须） |
| 围脖/面罩 | 滑雪裤 |
| 暖宝宝 | 速干内衣 |
| 加厚手套 | 滑雪镜 |

---

## 按用户水平适配

### 初学者（beginner）

**额外必带**：
| 物品 | 说明 |
|------|------|
| 护腕 | 单板初学者必戴，大幅降低手腕骨折风险 |
| 护臀/小乌龟 | 减少摔跤痛苦，提高练习信心 |
| 护膝 | 单板摔膝盖概率高 |

### 中级（intermediate）

**推荐携带**：
| 物品 | 说明 |
|------|------|
| 护背 | 公园跳台或刻滑时保护脊椎 |
| 运动相机 | 记录动作，方便 AI 教练分析 |

### 高级/专家（advanced）

**野雪额外装备**：
| 物品 | 说明 |
|------|------|
| 雪崩搜救仪 | 野雪/非雪道必备 |
| 探杆 + 雪铲 | 搭配搜救仪使用 |
| 对讲机 | 团队通讯 |
| 急救包 | 含止血带、绷带 |

---

## 按板型适配

### 单板（snowboard）

| 额外必带 | 说明 |
|----------|------|
| 护腕 | 所有水平推荐，初学者必戴 |
| 护臀 | 初学者必带 |
| 护背 | 进阶以上推荐 |

### 双板（ski）

| 额外必带 | 说明 |
|----------|------|
| 雪杖 | 通常与板一起租 |
| 护膝 | 蘑菇/陡坡推荐 |

---

## 按风格适配

### 刻滑（carving）

| 推荐携带 | 说明 |
|----------|------|
| 护背 | 高速刻滑保护脊椎 |
| 运动相机 | 记录滑行线路 |

### 公园/平花（park）

| 推荐携带 | 说明 |
|----------|------|
| 护背 | 跳台必备 |
| 护臀 | 摔道具区保护 |
| 头盔（全盔） | 公园推荐全盔 |

### 野雪（freeride）

| 必带 | 说明 |
|------|------|
| 雪崩搜救仪 | 生命安全装备 |
| 探杆 + 雪铲 | 救援搭档 |
| 对讲机 | 团队通讯 |
| 急救包 | 偏远地区自救 |
| 宽板（100mm+） | 粉雪浮力 |

---

## 国际目的地额外清单

### 文档类

| 物品 | 说明 |
|------|------|
| 护照（有效期 6 月+） | 多数国家要求 |
| 签证/ETA | 提前办理 |
| 国际保险（含救援） | 必须覆盖滑雪和医疗转运 |
| 酒店预订单 | 打印或存手机 |
| 机票行程单 | 打印或存手机 |
| 雪票凭证 | 电子票或确认邮件 |
| 驾照国际认证 | 如计划自驾 |

### 通讯与支付

| 物品 | 说明 |
|------|------|
| 国际漫游/SIM卡 | 确认能接打电话 |
| 信用卡（Visa/MC） | 主流支付方式 |
| 少量当地现金 | 部分雪场只收现金 |
| 转换插头 | 确认目的地插座类型 |

### 装备托运

| 建议 | 说明 |
|------|------|
| 雪具包/板包 | 航空托运专用 |
| 雪鞋单独包 | 避免磨损其他行李 |
| 预留 2-3kg 行李额度 | 雪具通常超重 |

---

## 天气驱动的动态调整

### 大风（风力 4 级+）

| 额外携带 | 说明 |
|----------|------|
| 全脸面罩 | 防风防寒 |
| 护目镜（双层防雾） | 大风天易起雾 |
| 防风外套 | 外层必须防风 |

### 降雪（中雪/大雪）

| 额外携带 | 说明 |
|----------|------|
| 防水套 | 手机/相机防水 |
| 备用雪镜 | 镜片起雾可换 |
| 防水手套 | 比普通手套更防雪水 |

### 晴天（强紫外线）

| 额外携带 | 说明 |
|----------|------|
| 高倍防晒霜 | 补涂频率加倍 |
| 润唇膏 SPF30+ | 防风防紫外线 |
| 偏光镜片雪镜 | 减少雪面反光 |

### 极寒（低于 -20°C）

| 额外携带 | 说明 |
|----------|------|
| 暖宝宝 2 包+ | 手套、鞋、手机各贴 |
| 手机保暖套 | 低温自动关机 |
| 加厚滑雪袜 | 双层保暖 |
| 巴拉克拉法帽 | 全脸覆盖 |

---

## 交通方式适配

### 自驾

| 额外携带/确认 | 说明 |
|---------------|------|
| 防滑链 | 冬季山路可能要求 |
| 玻璃水（防冻型） | -20°C 以下用 |
| 满油出发 | 山区加油站少 |
| 停车位置确认 | 提前查雪场停车场 |

### 高铁/大巴

| 额外携带/确认 | 说明 |
|---------------|------|
| 雪具袋/板包 | 保护雪板 |
| 接驳交通确认 | 雪场到车站接驳车 |
| 轻装行李 | 公共交通不便携带过多 |

### 飞机

| 额外携带/确认 | 说明 |
|---------------|------|
| 航空雪具包 | 符合航司尺寸要求 |
| 提前 2 小时到机场 | 托运雪具需额外时间 |
| 雪具托运标签 | 标记"易碎/运动器材" |

---

## Checklist 输出模板

### 完整版（行前检查）

```
## 行程速览
| 项目 | 信息 |
|------|------|
| 目的地 | {resort}，{city} |
| 出发日期 | {departure_date}（{weekday}） |
| 返回日期 | {return_date} |
| 行程天数 | {days}天{nights}晚 |
| 山顶天气 | {temp_min}~{temp_max}°C，{weather}，风力 {wind} 级 |
| 穿衣建议 | {clothing_advice} |

## 装备检查清单
[按类别输出表格，见 pre-departure.md 场景 A]

## 证件与文档
[输出表格]

## 交通确认
[输出表格]

## 天气速报
[输出表格]
```

### 精简版（当天早上提醒）

```
## 今日天气速报
| 项目 | 信息 |
|------|------|
| 山顶实时 | {temp}°C，{weather}，风力 {wind} 级 |
| 体感温度 | {feels_like}°C |
| 穿衣建议 | {clothing_advice} |
| 能见度 | {visibility}，建议用 {goggle_type} 镜片 |

## 最终确认清单
- [ ] 头盔
- [ ] 滑雪镜（今天{weather}，用{goggle_type}镜片）
- [ ] 雪票凭证
- [ ] 身份证
- [ ] 手机充电宝
- [ ] 暖宝宝（如适用）
- [ ] 围脖/面罩（如适用）

## 交通提醒
{traffic_advice}
```


path: references/resorts-reference.md
content: # 全球滑雪场补充参考

本文件为 ski-assistant 的补充知识库，提供 `resorts_db.json` 未覆盖的软信息：早鸟票预售规律、联票体系、区域特色体验（美食/温泉/文化）、自驾提示、全球速查表等。基础数据（规模/票价/雪道/交通）请查阅数据库。

> **币种说明**：¥ = 人民币（CNY），JPY = 日元，KRW = 韩元，CHF = 瑞士法郎，EUR = 欧元，CAD = 加元，USD = 美元，NZD = 新西兰元，AUD = 澳元。价格均为参考值，以当季官方公告为准。

## 快速索引

| 区域 | 雪场 | 跳转 |
|------|------|------|
| 崇礼 | 万龙、太舞、云顶、富龙 | [崇礼](#一中国---崇礼地区) |
| 东北 | 北大湖、松花湖、亚布力、长白山 | [东北](#二中国---东北地区) |
| 新疆 | 将军山、可可托海、丝绸之路 | [新疆](#三中国---新疆地区) |
| 北京周边 | 南山、军都山、石京龙 | [北京周边](#四中国---北京周边) |
| 其他国内 | 西岭雪山、鹧鸪山、翠华山 | [其他国内](#五中国---其他地区) |
| 日本 | 二世谷、白马、志贺、留寿都、富良野、妙高、安比 | [日本](#六日本) |
| 韩国 | 龙平、凤凰平昌、High1 | [韩国](#七韩国) |
| 欧洲 | 三峡谷、采尔马特、圣安东、夏慕尼、多洛米蒂、基茨比尔 | [欧洲](#八欧洲) |
| 北美 | 惠斯勒、范尔、帕克城、杰克逊霍尔、大天空、阿斯本、太浩湖 | [北美](#九北美) |
| 南半球 | Cardrona、Treble Cone、Remarkables、Coronet Peak、Thredbo、Perisher | [南半球](#十南半球) |
| 联票 | Ikon Pass、Epic Pass、国内联票 | [联票体系](#十一联票体系参考) |
| 速查表 | 全球横向对比 | [速查表](#十二全球雪场速查表) |

---

## 一、中国 - 崇礼地区

### 万龙滑雪场
- **早鸟规律**：通常 4-5 月开启超级早鸟预售，季卡约 ¥3,500-5,000，次卡有 10 次/20 次等档位
- **特色**：崇礼最陡雪场，高级道丰富，追求陡坡和挑战的首选

### 太舞滑雪小镇
- **早鸟规律**：4-6 月预售，季卡约 ¥3,000-4,500
- **特色**：小镇业态丰富（温泉、商业街、酒店群），适合家庭和情侣度假

### 云顶滑雪公园
- **特色**：冬奥遗产场地，U 型槽、坡面障碍技巧等专业赛道，公园和跳台爱好者首选

### 富龙滑雪场
- **特色**：城区步行可达，夜场丰富，初中级交通便利首选

---

## 二、中国 - 东北地区

### 北大湖滑雪场
- **早鸟规律**：5-7 月预售，季卡约 ¥3,000-4,000
- **特色**：东北粉雪天堂，野雪资源丰富

### 松花湖滑雪场
- **早鸟规律**：5-6 月预售
- **特色**：万科运营，配套成熟（青山酒店群），家庭度假首选

### 亚布力滑雪场
- **特色**：老牌雪场，多个雪场组成

### 长白山滑雪场
- **特色**：可搭配长白山景区游览

---

## 三、中国 - 新疆地区

### 将军山滑雪场
- **特色**：阿勒泰「人类滑雪起源地」，粉雪质量顶级，价格亲民（性价比极高）

### 可可托海滑雪场
- **早鸟规律**：6-8 月预售
- **特色**：国内最长雪道（宝石大道约 9km），超大落差（1,219m，国内之最）

---

## 四、中国 - 北京周边

### 南山滑雪场
- **早鸟规律**：10-11 月预售季卡，约 ¥2,000-3,000
- **特色**：北京最受欢迎的中型雪场之一，有单板公园（Nanshan Mellow Park）

### 军都山滑雪场
- **特色**：距北京市区最近的雪场之一，纯初学者和亲子入门体验

### 石京龙滑雪场
- **特色**：可搭配延庆冬奥文化旅游

---

## 五、中国 - 其他地区

### 西岭雪山滑雪场
- **特色**："窗含西岭千秋雪"打卡地，西南地区最知名

### 鹧鸪山自然公园
- **特色**：高海拔（约 3,200m）自然雪景，拍照出片，藏区文化体验
- **注意**：海拔较高，注意高原反应，不建议剧烈运动

### 翠华山滑雪场
- **特色**：西安最近的滑雪选择

---

## 六、日本

### 二世谷（Niseko）
- **早鸟规律**：7-9 月预售季票，通常有 15-25% 折扣
- **特色**：全球顶级粉雪，年降雪量 15m+，夜生活丰富，英语友好
- **交通**：新千岁机场 → 二世谷巴士约 2.5-3 小时

### 白马（Hakuba）
- **特色**：1998 冬奥会场地，地形丰富，性价比高于二世古
- **交通**：东京 → 长野新干线 1.5 小时，长野 → 白马巴士约 1 小时

### 志贺高原（Shiga Kogen）
- **特色**：日本最大滑雪区域，海拔最高（最高 2,307m），雪质稳定

### 妙高高原（Myoko Kogen）
- **特色**：降雪量大，价格低于二世古/白马，人少

### 安比高原（Appi Kogen）
- **特色**：雪质接近北海道，人少，Club Med 入驻

### 留寿都（Rusutsu）
- **特色**：北海道第二大雪场，粉雪优质，人流少于二世古

### 富良野（Furano）
- **特色**：雪质极佳（干粉雪），人少清净，Prince Hotel 配套

---

## 七、韩国

### 龙平（YongPyong）
- **特色**：2018 冬奥会场地

### 凤凰平昌（Phoenix）
- **特色**：配套 Blue Canyon 酒店群，度假体验好

### High1滑雪场
- **特色**：国营雪场，性价比高，赌场度假村配套

---

## 八、欧洲

### 三峡谷（Les 3 Vallées）
- **联票说明**：三峡谷联票（Forfait 3 Vallées）覆盖 Courchevel/Méribel/Val Thorens 全区域，也可单独购买子区域票

### 采尔马特（Zermatt）
- **特色**：马特洪峰景观，全年可滑（冰川），无车小镇

### 圣安东（St. Anton）
- **联票说明**：Ski Arlberg 联票覆盖 St. Anton/Lech/Zürs/Stuben 等多个互联区域
- **特色**：高山滑雪发源地之一，après-ski 文化浓厚

### 夏蒙尼（Chamonix）
- **联票**：Mont Blanc Unlimited 多日票约 EUR 300/6日，覆盖 Chamonix + Courmayeur + Les Houches
- **特色**：白色山谷（Vallée Blanche）传奇路线，极限滑雪圣地

### 多洛米蒂（Dolomiti Superski）
- **联票说明**：覆盖全部 12 个区域，世界最大联票之一
- **特色**：世界遗产景观，阳光充足，意式美食和文化

### 基茨比尔（Kitzbühel）
- **特色**：Hahnenkamm 世界杯赛道，中世纪小镇风情

---

## 九、北美

### 惠斯勒（Whistler）
- **自驾提示**：冬季需冬胎或雪链，Sea-to-Sky 公路沿海风景优美但弯道多

### 范尔（Vail）
- **自驾提示**：I-70 周末/节假日拥堵严重，建议早出晚归或避开高峰

### 帕克城（Park City）
- **自驾提示**：盐湖城机场租车极其方便，I-80/US-40 直达

### 太浩湖区（Lake Tahoe）
- **自驾提示**：旧金山出发约 3.5-4 小时，冬季须携带雪链

---

## 十、南半球

> 南半球雪季为 6-10 月（北半球夏季），适合反季节滑雪。

### Cardrona
- **早鸟规律**：3-5 月预售季票，通常有 15-20% 折扣
- **特色**：世界级地形公园（halfpipe、terrain park），经常举办国际赛事

### Treble Cone
- **特色**：长且陡的雪道，瓦纳卡湖全景视野，本地人最爱

### 皇后镇（Remarkables）
- **特色**：Shadow Basin 野雪区，家庭友好

### Coronet Peak
- **特色**：提供夜滑（Night Ski），景色优美可俯瞰皇后镇

### Thredbo
- **特色**：澳洲最长雪道（Supertrail 5.9km），村庄氛围好，après-ski 文化

### Perisher
- **特色**：4 个互联区域，Epic Pass 南半球唯一覆盖雪场，可乘 Skitube 火车进入

---

## 十一、联票体系参考

### Ikon Pass（国际）
- 覆盖全球 50+ 雪场，包括日本二世谷、加拿大、美国、欧洲部分、新西兰
- 全价 Ikon Pass 约 USD 1,200-1,400（早鸟），无限次畅滑指定雪场
- Ikon Base Pass 约 USD 800-1,000（早鸟），部分雪场有限制日
- 预售通常 3-4 月开启
- 南半球覆盖：新西兰 Coronet Peak、The Remarkables、Mt Hutt

### Epic Pass（Vail Resorts）
- 覆盖全球 40+ 雪场，包括惠斯勒、范尔、帕克城等
- 全价 Epic Pass 约 USD 800-1,000（早鸟）
- Epic Local Pass 约 USD 600-800（有节假日限制）
- 预售通常 3-4 月开启
- 南半球覆盖：澳大利亚 Perisher

### 欧洲多区联票
- **Mont Blanc Unlimited**：覆盖 Chamonix + Courmayeur + Les Houches 等
- **Dolomiti Superski**：覆盖全部 12 个区域，1,200km 雪道
- **Ski Arlberg**：覆盖 St. Anton/Lech/Zürs 等，300km 互联雪道
- **三峡谷联票**：覆盖 Courchevel/Méribel/Val Thorens

### 国内联票
- 各雪场集团偶有联票产品，需关注官方公告
- 崇礼区域暂无统一联票，各雪场独立售票
- GOSKI/GOCAMP 等平台偶有多雪场联票合作

---

## 十二、全球雪场速查表

| 雪场 | 国家/地区 | 难度偏向 | 粉雪指数 | 性价比 | 配套 | 最佳时段 |
|------|----------|---------|---------|--------|------|---------|
| 万龙 | 中国崇礼 | 高级 | ★★★ | ★★★ | ★★★★ | 12-2月 |
| 太舞 | 中国崇礼 | 全段 | ★★★ | ★★★ | ★★★★★ | 12-2月 |
| 北大湖 | 中国吉林 | 中高级 | ★★★★ | ★★★★ | ★★★ | 12-3月 |
| 松花湖 | 中国吉林 | 全段 | ★★★★ | ★★★★ | ★★★★ | 12-3月 |
| 将军山 | 中国新疆 | 全段 | ★★★★★ | ★★★★★ | ★★★ | 11-4月 |
| 可可托海 | 中国新疆 | 高级 | ★★★★★ | ★★★★ | ★★ | 11-4月 |
| 南山 | 中国北京 | 初中级 | ★★ | ★★★★ | ★★★ | 12-2月 |
| 军都山 | 中国北京 | 初级 | ★ | ★★★★★ | ★★ | 12-2月 |
| 西岭雪山 | 中国四川 | 初级 | ★★ | ★★★★ | ★★★ | 12-2月 |
| 二世谷 | 日本北海道 | 全段 | ★★★★★ | ★★★ | ★★★★ | 1-3月 |
| 白马 | 日本长野 | 全段 | ★★★★ | ★★★★ | ★★★★ | 1-3月 |
| 留寿都 | 日本北海道 | 全段 | ★★★★★ | ★★★ | ★★★★ | 12-3月 |
| 富良野 | 日本北海道 | 全段 | ★★★★★ | ★★★★ | ★★★ | 12-3月 |
| 龙平 | 韩国平昌 | 全段 | ★★★ | ★★★ | ★★★★ | 12-2月 |
| 三峡谷 | 法国 | 全段 | ★★★ | ★★★ | ★★★★★ | 1-3月 |
| 采尔马特 | 瑞士 | 中高级 | ★★★ | ★★ | ★★★★★ | 12-4月 |
| 圣安东 | 奥地利 | 中高级 | ★★★★ | ★★★ | ★★★★ | 1-3月 |
| 多洛米蒂 | 意大利 | 全段 | ★★★ | ★★★ | ★★★★★ | 12-3月 |
| 惠斯勒 | 加拿大 | 全段 | ★★★★ | ★★★ | ★★★★★ | 12-3月 |
| 帕克城 | 美国犹他 | 全段 | ★★★★ | ★★★ | ★★★★ | 12-3月 |
| 杰克逊霍尔 | 美国怀俄明 | 高级 | ★★★★★ | ★★★ | ★★★ | 1-3月 |
| 阿斯本 | 美国科罗拉多 | 全段 | ★★★★ | ★★ | ★★★★★ | 12-3月 |
| Cardrona | 新西兰 | 全段 | ★★★ | ★★★ | ★★★★ | 7-9月 |
| Treble Cone | 新西兰 | 中高级 | ★★★ | ★★★ | ★★★ | 7-9月 |
| Thredbo | 澳大利亚 | 全段 | ★★ | ★★★ | ★★★★ | 7-9月 |
| Perisher | 澳大利亚 | 全段 | ★★ | ★★★ | ★★★ | 7-9月 |

> 注：基础数据（规模/票价/雪道分布/交通费用等）均在 `resorts_db.json` 中，本表仅提供主观评分供快速参考。


path: references/travel-guide.md
content: # 滑雪出行攻略参考

本文件为 ski-assistant 的知识库，提供攻略输出模板结构和各区域专属补充模块。指令性内容（必须做什么、怎么做）在 `modules/trip-planning.md` 中定义。

---

## 攻略通常包含的信息维度

以下列出攻略输出时可包含的信息类别，agent 根据模块协议的要求选择性使用：

| 维度 | 必选 | 问题示例 |
|------|------|---------|
| 滑雪水平 | 是 | 你的滑雪水平大概是？（初学/中级/高级/发烧友） |
| 出发城市 | 是 | 你从哪个城市出发？ |
| 出行日期 | 是 | 计划什么时候去？待几天？ |
| 同行人数 | 是 | 几个人一起？朋友/家庭/情侣？ |
| 预算区间 | 否 | 大概预算多少？（可不限） |
| 偏好标签 | 否 | 有什么特别偏好吗？（粉雪/公园/陡坡/风景/夜滑/亲子/美食） |
| 装备情况 | 否 | 自带装备还是需要租赁？ |

---

## 攻略输出模板（国内版）

```markdown
# {目的地} 滑雪攻略 | {出行日期}

> 为 {用户画像简述} 定制

## 推荐雪场

### {雪场名}（首选推荐）
- **推荐理由**：{为什么适合该用户}
- **雪道概况**：共 {N} 条雪道，初级 {X}% / 中级 {Y}% / 高级 {Z}%
- **当前雪况**：{联网搜索获取}
- **票价**：全天 ¥{价格} | 半天 ¥{价格}

### {备选雪场}（备选）
- **推荐理由**：...

## 交通方案

### 方案一：{推荐方案}
{出发城市} → {中转} → {雪场}
- 耗时：约 {X} 小时
- 费用：约 ¥{价格}/人
- 详细步骤：
  1. ...
  2. ...

### 方案二：{备选}
...

## 住宿推荐

| 档位 | 推荐 | 价格/晚 | 距雪场 | 特点 |
|------|------|---------|--------|------|
| 经济 | {名称} | ¥{价格} | {距离} | ... |
| 中档 | {名称} | ¥{价格} | {距离} | ... |
| 高端 | {名称} | ¥{价格} | {距离} | ... |

## 装备清单

### 必备装备
- **穿着层**：速干内衣 → 抓绒中层 → 防水外壳（雪服）
- **防护**：头盔、雪镜、手套、面罩/脖套
- **滑行**：{根据用户装备情况建议自带或租赁}

### 租赁信息
- 雪场租赁：约 ¥{价格}/天（板 + 鞋）
- 镇上租赁店：{如有更优惠的选择}

## 保险建议

| 类型 | 推荐场景 | 保费参考 | 关键提醒 |
|------|---------|---------|---------|
| 雪场自带保险 | 雪场购买，覆盖基本意外 | ¥5-20/次 | 保额较低，通常仅限雪道内 |
| 滑雪专项险 | 建议所有滑雪者购买 | ¥30-80/次 | 覆盖滑雪意外、救援费用，确认含「滑雪」运动 |
| 年度运动险 | 高频滑雪者（5次+/季） | ¥200-500/年 | 覆盖全年多次滑雪及其他运动 |

> 普通意外险、旅行险通常不覆盖滑雪等高风险运动，务必确认保单条款。

## 美食推荐

### 雪场/目的地美食
- **雪场餐厅**：{雪场内主要餐饮选择，人均价格}
- **周边特色**：{当地特色菜品/餐厅推荐}
- **性价比选择**：{经济实惠的用餐方案，如自带干粮、便利店等}
- **餐饮预算参考**：早餐约 ¥{X}，午餐约 ¥{Y}，晚餐约 ¥{Z}

## 预算规划（{人数}人 {天数}天）

| 项目 | 人均费用 | 备注 |
|------|---------|------|
| 交通 | ¥{价格} | {方式} |
| 雪票 | ¥{价格} | {票种} |
| 住宿 | ¥{价格} | {档位}，{天数}晚 |
| 餐饮 | ¥{价格} | 约 ¥{X}/天 |
| 装备租赁 | ¥{价格} | {如需} |
| 保险 | ¥{价格} | 滑雪专项险 |
| 其他 | ¥{价格} | 教练等 |
| **合计** | **¥{总价}** | |

> 可调用 scripts/budget_calculator.py 生成详细预算拆分

## 建议行程

### Day 1：{日期}
- {上午}：...
- {下午}：...
- {晚上}：...

### Day 2：{日期}
...

## 实用贴士
- **安全提醒**：{根据目的地定制}
- **天气注意**：{当地气温和穿衣建议}
- **实用 APP**：{相关应用推荐}
- **教练建议**：{根据用户水平}
```

---

## 国际版增补模块

在国内版基础上，国际目的地攻略需额外包含以下模块：

```markdown
## 签证与入境

- **签证类型**：{所需签证类型}
- **办理方式**：{流程简述}
- **办理周期**：约 {X} 个工作日
- **所需材料**：{核心材料清单}
- **注意事项**：{如有免签/落地签等便利政策}

## 保险推荐（国际版）

| 保险类型 | 推荐产品 | 保费参考 | 覆盖范围 |
|---------|---------|---------|---------|
| 旅行综合险 | {产品名} | ¥{价格} | 旅行取消、行李延误、医疗 |
| 滑雪专项险 | {产品名} | ¥{价格} | 滑雪意外、高山救援、直升机救援 |
| 医疗保障 | {产品名} | ¥{价格} | 海外医疗（建议保额不低于 50 万） |

> 国际滑雪强烈建议购买包含「滑雪运动」和「高山救援」条款的专项保险。
> 欧洲部分雪场要求滑雪者持有有效保险才可购票（尤其瑞士）。
> 北美医疗费用高昂，建议保额不低于 USD 100,000。

## 通讯与支付

- **网络**：{当地 SIM 卡/eSIM/WiFi 方案}
- **支付**：{现金/信用卡/移动支付接受度}
- **汇率参考**：1 {当地货币} ≈ ¥{人民币}（联网获取实时汇率）

> 可调用 scripts/currency_converter.py 获取实时汇率换算

## 语言与文化

- **常用滑雪术语对照**：{当地语言的基本滑雪词汇}
- **文化注意事项**：{如有}
```

---

## 日本专属补充模块

```markdown
## 日本特色体验

### 温泉推荐
| 温泉 | 类型 | 距雪场 | 价格 | 特色 |
|------|------|--------|------|------|
| ... | 露天/室内 | ... | JPY {价格} | ... |

### 美食地图
- **雪场内**：{推荐餐厅和必点菜品}
- **小镇上**：{当地特色美食}
- **必吃推荐**：拉面、海鲜丼、成吉思汗烤肉（北海道）、信州荞麦面（长野）、温泉蛋
- **预算参考**：午餐约 JPY 1000-1500，晚餐约 JPY 2000-4000

### 交通卡与通票
- **推荐通票**：{如 JR Pass、区域通票}
- **是否划算**：{根据用户行程计算}
- **IC 卡**：建议购买 Suica/ICOCA，便利店和交通通用
```

---

## 欧洲专属补充模块

```markdown
## 欧洲滑雪特别事项

### 互联雪区与联票策略
- **目标区域**：{如三峡谷/Ski Arlberg/Dolomiti Superski}
- **联票类型与价格**：{多日票/单区域票/全区域票对比}
- **推荐策略**：{根据用户天数和水平建议最优联票}
- **注意**：欧洲大型互联雪区通常按区域售票，提前了解区域划分可避免重复购票

### 欧洲交通方案
- **飞行**：{推荐机场，如日内瓦/苏黎世/慕尼黑/因斯布鲁克}
- **火车**：{瑞士/奥地利铁路网发达，火车直达雪场}
- **接驳巴士**：{机场到雪场的 shuttle 预订建议}
- **自驾**：{欧洲冬季自驾须知，如奥地利需购买 Vignette 高速贴，冬胎法规，雪链}
- **欧洲租车提示**：多为手动挡，自动挡需提前预订且价格更高；注意各国高速收费规则不同

### 欧洲美食体验
- **法国**：fondue（奶酪火锅）、raclette（拉克莱特）、tartiflette（奶酪土豆焗）、vin chaud（热红酒）
- **瑞士**：rösti（瑞士薯饼）、fondue、巧克力热饮
- **奥地利**：Wiener Schnitzel（维也纳炸猪排）、Kaiserschmarrn（皇帝煎饼）、Glühwein（热红酒）
- **意大利（多洛米蒂）**：pizza、pasta、polenta、南蒂罗尔特色 Knödel（面疙瘩）
- **餐饮预算**：雪场午餐约 EUR 15-25，镇上晚餐约 EUR 25-50
- **小贴士**：欧洲雪场山顶餐厅风景绝佳，建议至少体验一次阳光露台午餐

### Après-Ski 文化
- **定义**：滑雪后社交活动，是欧洲滑雪文化的重要组成部分
- **代表地**：St. Anton（MooserWirt/Krazy Kanguruh）、Ischgl、Val d'Isère
- **形式**：雪场脚下酒吧，通常下午 3-4 点开始，热红酒/啤酒 + 音乐
- **费用参考**：啤酒约 EUR 5-8，热红酒约 EUR 4-6
```

---

## 北美专属补充模块

```markdown
## 北美滑雪特别事项

### 自驾与租车
- **租车**：{推荐租车公司，SUV/AWD 车型首选}
- **冬季驾驶**：{冬胎/AWD 要求，雪链规定因州而异}
- **加油**：美国加油站自助为主，建议了解操作流程
- **停车**：{雪场停车费用和预约制度，如部分雪场周末需提前预约停车位}
- **科罗拉多 I-70 提示**：周末/节假日严重拥堵，建议周五晚或周六早出发，周日下午避免返程

### Ikon/Epic Pass 策略
- **适用场景**：{根据用户行程天数判断}
- **Ikon vs Epic 对比**：

| 维度 | Ikon Pass | Epic Pass |
|------|----------|----------|
| 价格（早鸟） | USD 1200-1400 | USD 800-1000 |
| 核心雪场 | 杰克逊霍尔、大天空、阿斯本 | 惠斯勒、范尔、帕克城 |
| 日本覆盖 | 二世古（限定天数） | 白马谷（限定天数） |
| 南半球 | 新西兰 3 场 | 澳大利亚 Perisher |
| 单日票替代 | 滑 5 天以上通常划算 | 滑 4 天以上通常划算 |

- **购买时机**：每年 3-4 月开始预售次季 Pass，越早越便宜
- **注意**：部分 Pass 有限制日（节假日不可用），购买前确认日期匹配

### 北美美食体验
- **雪场餐饮**：Lodge 内通常有汉堡、三明治、披萨、汤类，人均 USD 15-25
- **镇上餐厅**：{如 Vail Village、Park City Main Street、Whistler Village 餐厅推荐}
- **特色推荐**：Colorado green chili（科罗拉多绿辣椒）、Utah 精酿啤酒、BC 省三文鱼
- **小费文化**：餐厅用餐通常需付 18-22% 小费
- **餐饮预算**：午餐约 USD 15-25，晚餐约 USD 30-60

### 北美时差与高海拔
- **时差**：美西（太平洋时间）比北京晚 16 小时，美山区晚 15 小时
- **高海拔**：科罗拉多雪场海拔通常 2500-3500m，初到注意高反
- **应对建议**：到达后第一天轻度滑行，多饮水，避免饮酒，如有症状可服用布洛芬
```

---

## 南半球专属补充模块

```markdown
## 南半球滑雪特别事项

### 反季节规划要点
- **雪季时间**：6 月 - 10 月（最佳 7-9 月）
- **适用人群**：北半球夏季想滑雪的爱好者、备赛运动员、Gap Year 旅行者
- **气候提醒**：南半球冬季气温波动大，新西兰山区天气多变，建议关注每日雪况报告

### 新西兰滑雪须知
- **签证**：中国公民需旅游签证，可网上申请，周期约 15-25 个工作日
- **驾照**：需携带中国驾照 + 英文翻译件（NZTA 认可），右舵左行
- **交通**：皇后镇/瓦纳卡为主要基地，雪场均需自驾或乘坐 shuttle
- **住宿**：皇后镇住宿选择丰富但旺季需提前预订，瓦纳卡更安静经济
- **特色体验**：蹦极、跳伞、米尔福德峡湾、萤火虫洞

### 澳大利亚滑雪须知
- **签证**：中国公民需旅游签证（600 类）
- **交通**：悉尼/墨尔本/堪培拉出发自驾前往，冬季山路需雪链
- **国家公园入园费**：进入 Kosciuszko National Park 需缴纳车辆入园费（约 AUD 29/天）
- **Skitube**：Perisher 可乘坐 Skitube 地下火车从 Bullocks Flat 进入，避免山路驾驶
```

---

## 攻略质量检查清单

生成攻略后，自查以下要点：

- [ ] 所有价格已标注币种和时效性
- [ ] 交通方案包含具体的出行步骤
- [ ] 住宿推荐有多个档位选择
- [ ] 包含安全提醒和保险建议（国内外均需）
- [ ] 包含美食/餐饮推荐和预算
- [ ] 国际目的地已包含签证和保险信息
- [ ] 欧洲目的地已包含联票策略和交通方案
- [ ] 北美目的地已包含自驾信息和 Pass 策略
- [ ] 南半球目的地已包含反季节规划要点
- [ ] 日本目的地已包含温泉和美食地图
- [ ] 行程安排合理（不过于紧凑或松散）
- [ ] 预算规划覆盖所有主要开支（含保险）
- [ ] 已提供后续引导问题


path: references/tutorial-curriculum/_index.md
content: # 滑雪教程索引

本文件定义滑雪教程的级别体系、适配规则和元数据索引。技能元数据按级别拆分在 `levels/` 目录中，训练/FAQ/装备框架在独立文件中。

> **架构说明**：v3.0 动态教程生成 — 规则控质量 + Agent 生成内容。Agent 基于本文件索引 + `curriculum-skeleton.md` 协议 + 对应级别技能包动态组装教程。

---

## 元数据

```yaml
_meta:
  created: 2026-04-11
  updated: 2026-04-11
  next_review: 2026-10-11
  version: 3.0
  framework: "PSIA-AASI 级别框架（主）+ CASI/CSIA 术语对照（辅）"
  scoring: "coaching-rubric.md"
  gear: "gear-guide.md"
  disclaimer: "AI 生成内容，不能替代专业教练指导"
  architecture: "动态教程生成 — 规则控质量 + Agent 生成内容"
```

---

## 级别定义

每个级别按板型分为两个独立技能包，用户只读取自己板型的教程。

| 级别 | 名称 | 单板技能包 | 双板技能包 | 定义 | 目标分数 | 预计掌握时间 |
|------|------|-----------|-----------|------|---------|------------|
| 0 | First Time | `levels/sb-0.md` | `levels/ski-0.md` | 从未滑过或只滑过 1-2 次 | posture 3-5, turning 2-4, overall 3-5 | 1-2 个雪日 |
| 1 | Novice | `levels/sb-1.md` | `levels/ski-1.md` | 能在绿道/缓坡滑行，但转弯不流畅 | posture 5-6.5, turning 4-6, overall 5-6.5 | 3-5 个雪日 |
| 2 | Intermediate | `levels/sb-2.md` | `levels/ski-2.md` | 能流畅滑行蓝道，开始尝试黑道 | posture 6.5-7.5, turning 6-7.5, overall 6.5-7.5 | 5-10 个雪日 |
| 3 | Advanced | `levels/sb-3.md` | `levels/ski-3.md` | 黑道流畅滑行，追求技术和风格 | posture 7.5-9, turning 7.5-9, overall 7.5-9 | 持续精进 |

---

## coaching-rubric 维度映射

| coaching-rubric 维度 | 子项 | Level 0 目标 | Level 1 目标 | Level 2 目标 | Level 3 目标 |
|---------------------|------|------------|------------|------------|------------|
| 基础姿态 posture | 重心位置、膝盖弯曲、上半身姿态、手臂位置、髋部对齐、踝关节屈曲 | 3-5 | 5-6.5 | 6.5-7.5 | 7.5-9 |
| 转弯技术 turning | 平行站姿、立刃角度、换刃时机、卡宾质量、弯型控制、点杖技术 | 2-4 | 4-6 | 6-7.5 | 7.5-9 |
| 综合滑行 overall | 速度控制、路线选择、地形适应、节奏感、自信度、安全意识 | 3-5 | 5-6.5 | 6.5-7.5 | 7.5-9 |
| 自由式 freestyle | 起跳、空中控制、落地、技巧完成度、风格表现（仅 Level 3 公园/地形公园场景） | — | — | — | 7.5-9 |

**评分标准**：所有分数 1-10 分，精确到 0.5。达到目标分数下限视为该级别达标。

---

## 板型适配规则

| 维度 | 单板（snowboard） | 双板（ski） |
|------|------------------|------------|
| 入门技能 | 后刃滑行、前刃滑行、落叶飘 | 犁式制动、犁式转弯、平行滑行 |
| 核心差异 | 双脚固定在一块板上，换刃是核心 | 双脚独立，平行是核心 |
| 护具重点 | 护腕（必戴）、护臀、护膝 | 护膝（蘑菇/陡坡推荐） |
| 转弯技术 | 换刃时机、立刃角度、弯型控制 | 平行站姿、点杖技术、弯型控制 |

---

## 风格适配规则（Level 2+ 生效）

| 风格 | 核心技能 | 对应 coaching-rubric 子项 |
|------|---------|------------------------|
| 刻滑（carving） | 立刃角度、弯型控制、压力管理 | turning: edge_angle, turn_shape, carving_quality |
| 公园/平花（park） | 起跳、空中控制、落地、道具 | freestyle: 全部子项 |
| 野雪（freeride） | 地形适应、粉雪浮力、路线选择 | overall: terrain_adaptation, line_choice |
| 蘑菇（mogul） | 点杖技术、节奏感、膝盖缓冲 | turning: pole_plant, overall: rhythm |

---

## 技能包索引

| 级别 | 单板文件 | 双板文件 | 技能数 | 约行数 |
|------|---------|---------|-------|-------|
| 0 | `levels/sb-0.md` | `levels/ski-0.md` | 5 + 5 | ~150 |
| 1 | `levels/sb-1.md` | `levels/ski-1.md` | 6 + 6 | ~180 |
| 2 | `levels/sb-2.md` | `levels/ski-2.md` | 9 + 10 | ~250-280 |
| 3 | `levels/sb-3.md` | `levels/ski-3.md` | 14 + 13 | ~350 |

## 框架文件索引

| 框架 | 文件 | 内容 | 约行数 |
|------|------|------|-------|
| 训练计划 | `training.md` | 各级别天数、时长、技能顺序（含权重）、休息规则 | ~200 |
| FAQ | `faq.md` | 各级别常见问题及回答要点 | ~200 |
| 装备决策 | `gear.md` | 按级别和板型定义 must_have / recommended / consider_buy | ~150 |

---

## 国际术语对照规则（方案 C：PSIA 为主，CASI/CSIA 为补充）

### 显示规则

- **Level 0-1**：不显示术语对照，只用中文 + 英文主术语
- **Level 2+**：在核心技能（转弯技术、姿态进阶）末尾添加一行术语对照
- 术语对照不超过 2 行，不展开讲解差异
- 差异讲解放在"国际术语速查表"，用户主动询问时输出

### 术语对照格式示例

```markdown
**术语对照**：
- PSIA-AASI：Short Radius Turn / Slalom
- CASI：Short Radius Pivoted Turn
- CSIA：Short Radius Steering Turn
```

### 核心术语对照表（Level 2+ 参考）

| 技术概念 | PSIA-AASI 术语 | CASI 术语（单板） | CSIA 术语（双板） |
|---------|--------------|-----------------|-----------------|
| 基础站姿 | Athletic Stance | Neutral Stance | Balanced Stance |
| 旋转引导 | Rotary Movement | Pivoting | Steering |
| 立刃 | Edging | Edging / Inclination vs Angulation | Edging |
| 压力管理 | Pressure Control | Fore/Aft + Lateral Pressure | Fore/Aft Balance |
| 节奏 | Rhythm | Timing | Coordination & Timing |
| 反弓 | Angulation | Angulation | Angulation |
| 卡宾 | Carving | Carving | Carving |
| 搓雪转弯 | Skidded Turns | Pivoted Turns | Steering Turns |
| 综合滑行 | Overall | Coordination & Timing | Coordination |

---

## 水平校准验证问题

### 单板验证问题

| 编号 | 问题 | Level 0 期望 | Level 1 期望 | Level 2 期望 |
|------|------|------------|------------|------------|
| Q1 | 你能在绿道上完成落叶飘（左右移动方向）吗？ | 不能/刚开始练 | 能 | 能，且流畅 |
| Q2 | 你能独立完成 S 弯转弯吗？转弯之间不停顿 | 不能 | 能，但不够流畅 | 能，且流畅 |
| Q3 | 上缆车时能自己穿脱雪板吗？ | 不能/需要帮助 | 能 | 能 |
| Q4 | 你能在蓝道上控制速度吗？ | 不能 | 基本能 | 能，且轻松 |

### 双板验证问题

| 编号 | 问题 | Level 0 期望 | Level 1 期望 | Level 2 期望 |
|------|------|------------|------------|------------|
| Q1 | 你能在绿道上完成犁式转弯吗？ | 不能/刚开始练 | 能 | 已过渡到平行 |
| Q2 | 你能在蓝道上完成平行转弯吗？双板保持平行 | 不能 | 能，但不够流畅 | 能，且流畅 |
| Q3 | 上缆车时能自己穿脱雪板吗？ | 不能/需要帮助 | 能 | 能 |
| Q4 | 你能控制转弯大小（大弯和小弯）吗？ | 不能 | 基本能 | 能，且切换自如 |

---

## 文件结构

```
references/tutorial-curriculum/
├── _index.md                    # 本文件（~100 行）：级别定义、适配规则、索引
├── curriculum-skeleton.md       # 动态生成协议
├── level-common.md              # 通用内容：安全须知、雪场礼仪
├── levels/                      # 技能包（按级别+板型拆分）
│   ├── sb-0.md                  # 单板 Level 0（5 技能）
│   ├── sb-1.md                  # 单板 Level 1（6 技能）
│   ├── sb-2.md                  # 单板 Level 2（9 技能）
│   ├── sb-3.md                  # 单板 Level 3（14 技能）
│   ├── ski-0.md                 # 双板 Level 0（5 技能）
│   ├── ski-1.md                 # 双板 Level 1（6 技能）
│   ├── ski-2.md                 # 双板 Level 2（10 技能）
│   └── ski-3.md                 # 双板 Level 3（13 技能）
├── training.md                  # 训练计划框架
├── faq.md                       # FAQ 框架
└── gear.md                      # 装备决策框架
```

**读取规则**：根据用户 `board_type` 和 `level` 读取对应技能包。单板用户读 `levels/sb-{X}.md`，双板用户读 `levels/ski-{X}.md`。

---

## 维护规则

1. **复核周期**：180 天（每年雪季前复核）
2. **触发条件**：coaching-rubric.md 更新时，自动触发教程复核
3. **用户反馈**：收集"这个教程对你有帮助吗？"的反馈，低分章节标记为需要复核
4. **术语同步**：PSIA-AASI 或 CASI/CSIA 官方更新术语时，同步更新对照表
5. **技能元数据更新**：新增或删除技能时，更新对应 `levels/*.md` 文件，并同步更新 `training.md`、`faq.md`、`gear.md`
6. **动态生成质量**：每次修改技能包或生成协议后，对比旧版教程内容确保质量不低于旧版本

---

## 动态生成规则摘要（来自 curriculum-skeleton.md）

> 以下为 curriculum-skeleton.md 核心规则摘要，足够覆盖常规教程生成。完整协议（含质量检查清单、个性化适配、维护说明）见 `curriculum-skeleton.md`。

### 教程结构（按顺序，不可变）

1. **免责声明** → `⚠️ 本教程由 AI 生成...不能替代专业滑雪教练的现场指导`
2. **版本标注** → `版本：v3.0 | 架构：动态教程生成`
3. **级别标题** → `## [板型] Level [X] — [级别名称]教程`
4. **本级别适合你吗** → 基于级别定义表的"定义"列生成 3-4 句自我评估
5. **训练计划** → 表格：| 阶段 | 技能 | 时长 | 权重 | 关键目标 |
6. **核心技能详解** → 每个技能必须含 5 子章节（见下）
7. **装备清单** → 按 must_have / recommended / consider_buy / 风格专精 分类
8. **常见问题** → 基于 faq.md 的 answer_key_points 展开为 3-5 句自然语言
9. **下一步** → 级别递进指引 + 历史记录提及

### 技能讲解 5 子章节（每个技能必须完整覆盖）

| 子章节 | 数据来源 | 要求 |
|--------|---------|------|
| **为什么重要** | `why_important` | 2-3 句自然语言，说明与整体滑行的关系 |
| **怎么做** | `action_guide_template` | 分步指导至少 3 步，含身体部位具体动作 |
| **常见错误** | `common_mistakes_template` | 每个错误：错误描述 + 后果 + 纠正方法 |
| **练习方法** | `practice_template` | 具体步骤，保留数量和组数 |
| **成功信号** | `success_signal` | 1-2 句可自检描述 |

### 语言风格

- 第二人称（你），友好专业鼓励性
- 技术术语首次出现标注英文（如：反弓 Angulation）
- Level 0-1 不显示术语对照，Level 2+ 核心技能末尾附加术语对照（从 `terms` 字段读取，不超过 2 行）

### Level 3 风格路线选择

按用户 `freestyle` 偏好选择：
- `carving` → 刻滑路线（单板 L3-SB-04/05/06，双板 L3-SK-05/06/07）
- `park` / `freestyle` → 公园路线（L3-SB-07/08/09，仅单板）
- `freeride` / `powder` → 野雪路线（单板 L3-SB-10/11/12，双板 L3-SK-11/12/13）
- `mogul` → 蘑菇路线（L3-SK-08/09/10，仅双板）
- 未指定 → 全部生成但标注优先级


path: references/tutorial-curriculum/curriculum-skeleton.md
content: # 教程动态生成协议

本文件定义 Agent 如何基于 `_index.md` 中的技能骨架动态组装教程内容。`modules/tutorial.md` 读取此协议后，按规则生成符合质量标准的教程。

---

## 架构总览

```
用户请求教程
    → modules/tutorial.md 读取用户 profile（板型、级别、风格偏好）
    → 读取 _index.md 获取级别定义、适配规则、技能包索引
    → 读取 levels/{board}-{level}.md 获取对应级别技能元数据
    → 按需读取 training.md / faq.md / gear.md 中对应级别部分
    → 读取 curriculum-skeleton.md（本文件）获取生成规则
    → 按本文件定义的模板和约束动态生成教程内容
    → 输出完整教程 Markdown
```

**核心原则**：规则控质量，Agent 生成内容。不预写全文，但严格控制输出格式和内容标准。

---

## 生成流程

### Step 1：确定输出范围

根据用户 `board_type` 和 `level` 确定：
- 读取 `levels/sb-{X}.md`（单板）或 `levels/ski-{X}.md`（双板）获取技能元数据
- 读取 `training.md` 中对应级别部分获取训练计划
- 读取 `faq.md` 中对应级别部分获取 FAQ 要点
- 读取 `gear.md` 中对应级别部分获取装备规则

### Step 2：生成教程结构

每个教程必须包含以下章节（按顺序）：

```markdown
# [板型] Level [X] — [名称] 教程

> 版本：v3.0 | 免责声明：AI 生成内容，不能替代专业教练指导

## 本级别适合你吗

[基于级别定义表生成自我评估引导]

## 训练计划

[基于 training_framework 生成天数、时长、技能顺序表格]

## 核心技能详解

[逐个技能生成，每个技能包含以下子章节]

### [技能名称]

**为什么重要**：[基于 why_important 展开为 2-3 句自然语言]

**怎么做**：[基于 action_guide_template 展开为可操作的分步指导]

**常见错误**：[基于 common_mistakes_template 展开，每个错误附带 1 句纠正建议]

**练习方法**：[基于 practice_template 展开为具体的练习步骤，包含数量和组数]

**成功信号**：[基于 success_signal 展开为 1-2 句可自检的描述]

[Level 2+ 核心技能附加术语对照（如果有 terms 字段）]

## 装备清单

[基于 gear_framework 生成按优先级分类的装备清单]

## 常见问题

[基于 faq_framework 生成自然语言问答，每个问题 3-5 句]

## 下一步

[基于级别递进关系生成进阶指引]
```

---

## 内容生成规则

### 规则 1：技能讲解必须完整覆盖模板

每个技能必须生成以下 5 个子章节，不可省略：
1. **为什么重要** — 将 `why_important` 展开为 2-3 句有说服力的自然语言，说明该技能与整体滑行能力的关系
2. **怎么做** — 将 `action_guide_template` 展开为分步指导（至少 3 步），包含身体部位的具体动作描述
3. **常见错误** — 将 `common_mistakes_template` 每个错误展开为「错误描述 + 后果 + 纠正方法」三段式
4. **练习方法** — 将 `practice_template` 每个练习展开为具体步骤，保留数量和组数信息
5. **成功信号** — 将 `success_signal` 展开为 1-2 句可自检的描述，让读者能明确判断是否达标

### 规则 2：语言风格

- 使用第二人称（你）直接对话
- 语气友好、专业、鼓励性，避免居高临下
- 技术术语首次出现时标注英文（如：反弓 Angulation）
- Level 0-1 不使用 CASI/CSIA 术语对照
- Level 2+ 核心技能在讲解末尾添加术语对照（从 `terms` 字段读取）

### 规则 3：训练计划表格格式

必须包含以下列：

| 阶段 | 技能 | 时长 | 权重 | 关键目标 |

- 阶段：Day 1 / Day 2 / ... 或 Phase 1 / Phase 2 / ...
- 技能：技能中文名称
- 时长：从 `duration_hours` 或 `duration_minutes` 读取
- 权重：从 `weight` 读取，显示为百分比
- 关键目标：基于技能 `why_important` 提炼为 1 句话

### 规则 4：装备清单格式

按优先级分类输出：
- **必须佩戴**（must_have）— 安全和基础体验必备
- **强烈推荐**（recommended）— 提升舒适度和安全性
- **考虑购买**（consider_buy / rental_or_buy）— Level 1+ 可考虑自购的装备
- **风格专精**（carving / freestyle / powder / mogul）— Level 3 按风格路线推荐

每个装备条目格式：`- [装备名称]：[1 句选择建议或注意事项]`

### 规则 5：FAQ 生成

- 基于 `answer_key_points` 展开为 3-5 句自然语言
- 语气共情，先肯定问题合理性，再给出具体建议
- 涉及安全风险的问题（如道外安全、摔倒）必须强调请专业教练
- 不涉及具体医疗建议，身体酸痛等问题给出一般性建议并注明"如持续不适请咨询医生"

### 规则 6：Level 3 风格路线处理

Level 3 教程按用户 `freestyle` 偏好（从 `user_profile.json` 读取）选择风格路线：
- `carving`：只生成刻滑路线技能（单板 L3-SB-04/05/06，双板 L3-SK-05/06/07）
- `park` / `freestyle`：只生成公园路线技能（L3-SB-07/08/09，仅单板）
- `freeride` / `powder`：只生成野雪路线技能（单板 L3-SB-10/11/12，双板 L3-SK-11/12/13）
- `mogul`：只生成蘑菇路线技能（L3-SK-08/09/10，仅双板）
- 未指定或 `all`：生成全部风格路线，但标注推荐优先级

---

## 质量检查清单

生成完成后必须自检：

- [ ] 所有技能都包含 5 个子章节（为什么重要、怎么做、常见错误、练习方法、成功信号）
- [ ] 技能顺序与 `skill_sequence` 一致
- [ ] 训练计划表格包含所有必需列
- [ ] 装备清单按优先级分类
- [ ] FAQ 覆盖该级别全部问题
- [ ] Level 2+ 核心技能包含术语对照
- [ ] 免责声明在文件顶部
- [ ] 版本标注在文件顶部
- [ ] 下一步章节指向正确的下一级别
- [ ] 全文无英文混用（除技术术语和术语对照外）

---

## 与旧版教程的对比要求

动态生成的教程内容质量不得低于旧版预写文件。具体标准：

1. **信息量**：每个技能的讲解不少于旧版对应技能的字数
2. **可操作性**：练习方法必须包含具体数量和组数（与旧版一致或更详细）
3. **安全性**：安全相关技能（安全摔倒、道外安全、缆车穿脱）的讲解不得简化
4. **术语准确性**：术语对照与旧版一致
5. **结构一致性**：8 个教程（4 级别 x 2 板型）结构完全一致

---

## 个性化适配

基于 `user_profile.json` 和 `records.json` 动态调整：

1. **级别匹配**：根据 `records.json` 最近一次评分的 `posture`、`turning`、`overall` 三项分数，自动匹配到对应级别
2. **弱项匹配**：找出评分最低的子项，通过技能的 `rubric_mapping` 字段映射到对应技能。例如用户 `turning: 刻滑质量 5.5/10`，映射到 L2-SB-04 刻滑入门
3. **风格偏好**：Level 3 根据 `freestyle` 字段选择风格路线
4. **历史进度**：如果有历史记录，在"下一步"中提及上次进度

### 弱项注入强制规则（有 records.json 时必执行）

当 `records.json` 存在且最近一次评分有任一维度低于当前级别目标分时，必须执行以下注入：

**Step 1：提取弱项数据**
- 从最近一条记录读取 `scores` 和 `issues` 数组
- 识别低于目标分的维度（对照 _index.md 各级别目标分数）
- 记录具体子项分数（如 `turning: 刻滑质量 5.5/10`）

**Step 2：匹配技能**
- 通过每个技能的 `rubric_mapping` 字段，将弱项子项映射到对应技能
- 一个弱项可能对应多个技能，优先匹配当前级别
- 如果当前级别无对应技能，向上或向下找最近级别

**Step 3：注入内容格式（在匹配技能的讲解中强制添加）**

在"为什么重要"之后、"怎么做"之前，插入以下个性化段落：

```markdown
> ⚡ **针对你的情况**：
> - 上次分析得分：[弱项维度] [子项名] [分数]/10，目标 ≥ [目标分]/10
> - 你的具体表现：[从 issues 数组中提取描述，如无则写"建议下次分析时关注此维度"]
> - 优先练这个：[说明该技能与弱项的因果关系，1-2 句]
```

**Step 4：训练计划标记**
- 弱项相关技能在训练计划表格中标注"⚡ 你的重点"
- 在训练计划末尾追加"重点突破路径"：说明从哪个基础技能练起、因果关系是什么

**Step 5：FAQ 优先展示**
- 与弱项相关的 FAQ 问题提前到最前面
- 在对应问题后标注"⚡ 你目前最需要关注的"

**无 records.json 时的降级**
- 跳过上述所有注入步骤
- 输出通用版教程，末尾提示"完成练习后发视频给 AI 教练打分，下次教程将基于你的实际表现个性化调整"

---

## 维护说明

1. 修改 `levels/*.md` 中的技能元数据后，无需修改本文件，生成内容自动更新
2. 修改 `training.md` / `faq.md` / `gear.md` 后，无需修改本文件
3. 如需调整生成格式（如增加新的子章节），修改本文件的「生成教程结构」部分
4. 如需新增质量检查项，修改「质量检查清单」部分
5. 每次修改本文件后，重新生成 8 个教程并对比旧版验证质量


path: references/tutorial-curriculum/faq.md
content: # FAQ 框架（FAQ Framework）

定义各级别常见问题和回答要点。Agent 基于这些要点动态生成自然语言答案。

## 单板 FAQ

```yaml
faq_snowboard:
  level_0:
    - question: 我应该请教练吗
      answer_key_points: [强烈建议第一次上雪请 1-2 小时教练, 教程是补充不能替代现场指导]
    - question: 穿什么衣服
      answer_key_points: [速干内衣加抓绒中间层加防水外套, 不要穿棉质出汗后变冷, 具体参考装备清单]
    - question: 需要买装备吗
      answer_key_points: [第一次不需要全部租用, 滑 3 天后再决定是否购买]
    - question: 摔了很多次正常吗
      answer_key_points: [完全正常第一天摔 50-100 次是标准体验, 关键是学会安全地摔]
    - question: 年龄大了或体力不好学得会吗
      answer_key_points: [滑雪没有年龄上限, 关键请教练第一天不要滑太久循序渐进]
    - question: Regular 和 Goofy 哪个更好
      answer_key_points: [没有好坏之分天生决定的, 约 60% 的人 Regular 左脚前 40% Goofy 右脚前]
    - question: 滑雪后身体酸痛正常吗
      answer_key_points: [完全正常大腿小腿臀部手腕酸痛是标准体验, 通常 2-3 天后自然消失滑雪后拉伸和泡热水有助于缓解]

  level_1:
    - question: 换刃时总是摔倒怎么办
      answer_key_points: [正常换刃是 Level 1 最难的技术, 放慢速度在极缓坡上练习, 重点是视线引导到肩膀带到重心转移的顺序]
    - question: S 弯不连贯中间有停顿怎么办
      answer_key_points: [出弯后立刻准备下一个弯不要等完全停止, 练习时喊口令左右左右帮助建立节奏]
    - question: 前刃换后刃比后刃换前刃难正常吗
      answer_key_points: [完全正常前刃换后刃更难因为视线方向改变更大, 多练前刃到后刃比例 2:1]
    - question: 滑了 3 天还是不会 S 弯是不是不适合滑雪
      answer_key_points: [不是 S 弯通常需要 3-5 个雪日才能掌握, 关键每天练习 2-3 小时不要超过肌肉疲劳会影响学习]
    - question: 滑雪后身体酸痛正常吗
      answer_key_points: [完全正常大腿小腿臀部酸痛是标准体验, 通常 2-3 天后自然消失滑雪后拉伸和泡热水有助于缓解]

  level_2:
    - question: 搓雪小半径弯总是弯太大怎么办
      answer_key_points: [加快换刃节奏视线快速切换方向, 练习时喊口令左右左右每秒 1 个弯]
    - question: 刻滑时板尾总是扫雪怎么办
      answer_key_points: [立刃角度不够, 尝试更陡的坡让重力帮你建立立刃角度或者减小速度给边刃更多时间抓雪]
    - question: 反弓姿态和倾斜有什么区别
      answer_key_points: [倾斜是整个身体一起倾斜, 反弓是髋部偏移上半身保持直立反弓更稳定适合高速]
    - question: 粉雪中总是沉板怎么办
      answer_key_points: [重心需要更靠后（10-15%）, 身体放松不要僵硬转弯半径放大不要用硬雪的方式]
    - question: 三种风格选哪个
      answer_key_points: [喜欢速度选刻滑喜欢技巧选公园喜欢自由选野雪, Level 2 可以先都体验 Level 3 再专精一种]

  level_3:
    - question: 如何提高立刃角度
      answer_key_points: [反弓姿态是关键髋部偏移上半身直立, 宽阔雪道练习逐渐加速, 请同伴拍照测量角度]
    - question: 公园总是害怕跳台怎么办
      answer_key_points: [从小跳台开始建立信心, 重点是起跳时机和落地缓冲, 不要一开始就尝试大跳台]
    - question: 道外安全怎么学
      answer_key_points: [参加雪崩安全课程 AIARE 1 或等效, 购买安全装备搜救仪探杆雪铲, 有经验者带领下进入]
    - question: Level 3 之后是什么
      answer_key_points: [Level 4 是专家级通常涉及教练认证, 对于大多数滑行者 Level 3 是持续精进的级别]
    - question: 每年雪季前需要重新练基础吗
      answer_key_points: [建议每年雪季前 1-2 天回顾 Level 2 核心技能搓雪弯刻滑入门反弓, 肌肉记忆还在但神经连接需要重新激活, 不要一上来就冲黑道]
    - question: 如何判断自己是否真的达到 Level 3 水平
      answer_key_points: [最可靠的方式是发一段黑道滑行视频给 AI 教练打分, 如果 posture turning overall 三项均达到 7.5 分以上且能稳定保持说明已达 Level 3 水平]
```

## 双板 FAQ

```yaml
faq_ski:
  level_0:
    - question: 我应该请教练吗
      answer_key_points: [强烈建议第一次上雪请 1-2 小时教练, 教程是补充不能替代现场指导]
    - question: 穿什么衣服
      answer_key_points: [速干内衣加抓绒中间层加防水外套, 不要穿棉质出汗后变冷]
    - question: 需要买装备吗
      answer_key_points: [第一次不需要全部租用, 滑 3 天后再决定是否购买]
    - question: 摔了很多次正常吗
      answer_key_points: [完全正常第一天摔 50-100 次是标准体验, 关键是学会安全地摔]
    - question: 我年龄大了体力不好学得会吗
      answer_key_points: [滑雪没有年龄上限, 关键请教练第一天不要滑太久循序渐进]
    - question: 滑雪后身体酸痛正常吗
      answer_key_points: [完全正常大腿小腿臀部酸痛是标准体验, 通常 2-3 天后自然消失滑雪后拉伸和泡热水有助于缓解]

  level_1:
    - question: 平行转弯时内侧板总是飘在外面怎么办
      answer_key_points: [内侧板没有参与转弯是因为重心偏向外侧板, 练习时有意将重心放在两脚中间感受内侧板的刃抓雪]
    - question: 搓雪小回转节奏不匀怎么办
      answer_key_points: [用口令 1-2-1-2 或点-转-点-转帮助建立节奏, 先在极缓坡上慢速练习逐渐加快]
    - question: 点杖时总是戳雪太深怎么办
      answer_key_points: [点杖是点不是戳手腕发力像用手指轻点桌面, 练习时在平地反复感受手腕发力的感觉]
    - question: 上蓝道很害怕怎么办
      answer_key_points: [正常第一次上蓝道都会害怕, 选择最宽缓的蓝道用犁式到平行过渡速度慢一点]
    - question: 我滑了 3 天还是不会平行转弯是不是不适合滑雪
      answer_key_points: [不是平行转弯通常需要 3-5 个雪日才能掌握, 关键每天练习 2-3 小时不要超过肌肉疲劳会影响学习]

  level_2:
    - question: 搓雪小回转总是弯太大怎么办
      answer_key_points: [加快点杖和转弯节奏, 练习时喊口令 1-2-1-2 每秒 1 个弯膝盖引导方向要快]
    - question: 卡宾时内侧板总是飘怎么办
      answer_key_points: [确保双板平行重心均匀分配, 内侧板要主动立刃不是被动跟着]
    - question: 反弓姿态和倾斜 Inclination 有什么区别
      answer_key_points: [倾斜是整个身体一起倾斜, 反弓是髋部偏移上半身保持直立反弓更稳定适合高速]
    - question: 蘑菇总是直冲上去怎么办
      answer_key_points: [膝盖弯曲更多像弹簧一样吸收, 线路选择走雪包之间不是正对着冲速度慢一点]
    - question: 三种风格选哪个
      answer_key_points: [喜欢速度选卡宾喜欢节奏选蘑菇喜欢自由选野雪, Level 2 可以先都体验 Level 3 再专精一种]

  level_3:
    - question: 如何提高立刃角度
      answer_key_points: [反弓姿态是关键髋部偏移上半身直立, 宽阔雪道练习逐渐加速请同伴拍照测量角度确保内侧板主动立刃]
    - question: 蘑菇总是越来越快怎么办
      answer_key_points: [每个雪包都要吸收和转弯减速, 点杖引导节奏不要被动跟随速度太大时增大转弯半径减速]
    - question: 道外安全怎么学
      answer_key_points: [参加雪崩安全课程 AIARE 1 或等效, 购买安全装备搜救仪探杆雪铲有经验者带领下进入]
    - question: Level 3 之后是什么
      answer_key_points: [Level 4 是专家级通常涉及教练认证 CSIA Level 4 或 PSIA Level 3, 对于大多数滑行者 Level 3 是持续精进的级别]
    - question: 每年雪季前需要重新练基础吗
      answer_key_points: [建议每年雪季前 1-2 天回顾 Level 2 核心技能搓雪回转卡宾入门反弓, 肌肉记忆还在但神经连接需要重新激活不要一上来就冲黑道]
    - question: 如何判断自己是否真的达到 Level 3 水平
      answer_key_points: [最可靠的方式是发一段黑道滑行视频给 AI 教练打分, 如果 posture turning overall 三项均达到 7.5 分以上且能稳定保持说明已达 Level 3 水平]
```


path: references/tutorial-curriculum/gear.md
content: # 装备决策框架（Gear Framework）

按级别和板型定义装备决策规则。Agent 基于这些规则动态生成装备清单。

```yaml
gear_framework:
  level_0:
    snowboard:
      must_have: [头盔（必戴）, 护腕（必戴）, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤]
      recommended: [护臀, 护膝, 防晒霜, 暖宝宝]
      rental: [雪板, 雪鞋, 固定器]
      note: 第一次不需要购买装备全部租用滑 3 天后再决定
    ski:
      must_have: [头盔（必戴）, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤]
      recommended: [护膝, 防晒霜, 暖宝宝]
      rental: [雪板, 雪鞋, 雪杖]
      note: 第一次不需要购买装备全部租用滑 3 天后再决定

  level_1:
    snowboard:
      must_have: [头盔, 护腕, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤, 护臀]
      recommended: [护膝, 面罩, 防晒霜]
      rental_or_buy: 滑 3 天后可考虑购买雪鞋和固定器雪板继续租用
    ski:
      must_have: [头盔, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤]
      recommended: [护膝, 面罩, 防晒霜]
      rental_or_buy: 滑 3 天后可考虑购买雪鞋雪板和雪杖继续租用

  level_2:
    snowboard:
      must_have: [头盔, 护腕, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤, 护臀, 护膝]
      recommended: [备用雪镜片, 面罩, 随身工具包]
      consider_buy: [自有雪板（根据风格选择板型）, 自有固定器, 自有雪鞋]
      carving: [选择 Camber 板型腰宽 245-255mm]
      freestyle: [选择 Twin Tip 板型更短更软]
      freeride: [选择 Directional 板型更宽浮力更好]
    ski:
      must_have: [头盔, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤]
      recommended: [护膝, 备用雪镜片, 面罩]
      consider_buy: [自有雪板（根据风格选择）, 自有雪鞋, 自有固定器]

  level_3:
    snowboard:
      must_have: [头盔, 护腕, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤, 护臀, 护膝]
      recommended: [备用装备, 随身工具包, 雪崩安全装备（道外必带）]
      carving: [Camber 高性能刻滑板腰宽 250-260mm 硬度 7-9]
      freestyle: [Twin Tip 公园板长度下巴到鼻子之间硬度 5-7]
      freeride: [Directional 野雪板腰宽 105mm 以上长度 +3-5cm]
      powder: [雪崩搜救仪探杆雪铲（道外必带）]
    ski:
      must_have: [头盔, 雪镜, 防水手套, 速干内衣, 抓绒中间层, 防水外套, 防水裤]
      recommended: [备用装备, 随身工具包]
      carving: [Camber 高性能卡宾板腰宽 68-80mm 硬度 7-9]
      mogul: [更短更软的蘑菇板长度鼻尖到眉毛之间]
      freeride: [野雪板腰宽 100mm 以上长度 +5cm]
      powder: [雪崩搜救仪探杆雪铲（道外必带）]
```


path: references/tutorial-curriculum/level-common.md
content: # 滑雪通用内容

本文件包含所有级别通用的基础知识：安全须知、雪场礼仪、穿衣法则、第一天清单。

---

## 安全须知（所有级别必读）

### 1. 头盔必戴

无论水平高低，头盔是最重要的安全装备。选择 CE 或 ASTM 认证产品。

### 2. 滑雪专项保险必买

普通旅游险通常不含滑雪运动。国际滑雪需购买含紧急救援和医疗转运的保险。

### 3. 国际雪联十大行为准则

1. 尊重他人：不要危及或伤害他人
2. 控制速度：根据地形、雪况和人流调整速度
3. 选择路线：前方滑行者有优先权，后方需保持距离
4. 超车：可以从上方或下方超车，但要留出足够空间
5. 进入雪道前：观察上方和下方，确认安全后进入
6. 停车：不要在狭窄处或视线不佳处停车
7. 徒步上山：必须靠雪道边缘行走
8. 遵守标志：注意雪道难度标识和警告标志
9. 事故处理：发生事故时留在现场，通知雪场巡逻队
10. 身份交换：事故涉及人员交换联系方式

### 4. 雪场礼仪

- 在雪道上不要横穿，要靠边
- 停车时靠雪道一侧，不要挡在中间
- 摔倒后尽快起身，移到雪道边
- 尊重雪场工作人员和其他滑雪者

---

## 穿衣三层法则

### 内层（排汗层）

- 材质：聚酯纤维或美利奴羊毛
- **不要穿棉质**：棉质吸汗后变冷，失去保暖功能
- 贴身穿着，负责将汗水排出体外

### 中间层（保暖层）

- 材质：抓绒或轻薄羽绒
- 负责保暖，厚度根据气温选择
- 崇礼/东北（-15°C 以下）需要厚抓绒 + 轻薄羽绒

### 外层（防水层）

- 材质：防水透气面料（防水 10000mm+，透气 8000g+）
- 负责防风防水
- 颜色建议选鲜艳的（方便辨认）

---

## 第一天上雪清单

| 类别 | 物品 | 必须/可选 | 备注 |
|------|------|---------|------|
| 安全 | 头盔 | 必须 | 租用或购买，CE/ASTM 认证 |
| 安全 | 滑雪专项险 | 必须 | 普通旅游险不含滑雪 |
| 安全 | 滑雪镜 | 必须 | 租用即可，阴天选增光镜片（黄色） |
| 护具（单板） | 护腕 | 必须 | **单板初学者必戴**，大幅降低手腕骨折风险 |
| 护具（单板） | 护臀/小乌龟 | 推荐 | 减少摔跤痛苦，提高练习信心 |
| 护具（单板） | 护膝 | 推荐 | 单板摔膝盖概率高 |
| 服装 | 速干内衣 | 必须 | 不要穿棉质，选聚酯纤维或美利奴羊毛 |
| 服装 | 防水滑雪外套 | 必须 | 可租用 |
| 服装 | 防水滑雪裤 | 必须 | 可租用，背带裤防雪效果更好 |
| 服装 | 保暖中间层 | 必须 | 抓绒或轻薄羽绒 |
| 服装 | 滑雪手套 | 必须 | 防水保暖，连指比五指更暖 |
| 服装 | 滑雪袜 | 必须 | 长筒压缩款，不要穿两双（影响血循环） |
| 服装 | 围脖/面罩 | 必须（崇礼/东北） | 防风防寒 |
| 配件 | 防晒霜 SPF50+ | 必须 | 高海拔+雪地反射紫外线极强 |
| 配件 | 暖宝宝 | 推荐（极寒天气） | 贴手套和鞋里 |
| 配件 | 唇膏 | 推荐 | 防风防冻 |

---

## 常见心态问题

### "我怕摔，不敢滑"

正常。第一天滑雪怕摔是本能反应。解决方案：
1. 先学会安全摔倒（教程里有教）
2. 知道怎么摔不疼，就不怕了
3. 在极缓坡上练习，几乎不会摔疼

### "我年龄大了/体力不好，学得会吗？"

当然。滑雪没有年龄上限，60 岁开始学的人很多。关键：
1. 请教练（1-2 小时足够入门）
2. 第一天不要滑太久（2-3 小时足够，肌肉会疲劳）
3. 循序渐进，不要和别人比

### "单板好学还是双板好学？"

- **单板**：第一天难（容易摔），第 3 天开始进步快
- **双板**：第一天容易（能站稳），但平行转弯需要更长时间
- 长期来看，两者难度相当，选你喜欢的

### "我需要请教练吗？"

强烈建议第一次上雪请 1-2 小时教练。教程是补充，不能替代：
1. 教练能现场纠正你的动作（教程做不到）
2. 教练能给你安全感（知道有人保护你就不怕了）
3. 教练能根据你的进度调整教学

---

## 雪道难度标识

| 颜色 | 难度 | 说明 |
|------|------|------|
| 绿道 | 初级 | 缓坡（< 25°），适合新手 |
| 蓝道 | 中级 | 中坡（25-40°），需要平行转弯能力 |
| 黑道 | 高级 | 陡坡（> 40°），需要良好的技术和控制力 |
| 双黑/三黑 | 专家 | 极陡、野雪、有障碍物 |

**注意**：不同国家的标准有差异。崇礼的黑道可能只相当于日本/欧洲的蓝道。

---

## 装备租用 vs 购买建议

| 物品 | 建议 | 原因 |
|------|------|------|
| 雪板/雪鞋/固定器 | 先租后买 | 初学者不知道自己适合什么，滑 3 天后再决定 |
| 头盔 | 购买 | 卫生考虑，头盔贴合头型很重要 |
| 雪镜 | 购买 | 卫生考虑，且价格不贵 |
| 速干内衣/袜子 | 购买 | 卫生考虑，且是贴身衣物 |
| 滑雪服/裤 | 可租可买 | 如果不常滑，租用更划算 |
| 护具（单板） | 购买 | 价格便宜，且是贴身护具 |

**经济性判断**：
- 季内滑 1-3 天：全部租用
- 季内滑 5 天+：考虑购买核心装备（板、鞋、头盔、雪镜）
- 季内滑 10 天+：建议购买全套装备

---

## 滑雪后身体酸痛正常吗？

完全正常。第一次滑雪后以下部位酸痛是标准体验：
- 大腿前侧（股四头肌）：滑雪主要发力部位
- 小腿前侧（胫骨前肌）：压雪鞋舌导致
- 臀部：摔倒和蹲姿导致
- 手腕（单板）：摔倒时撑地导致

**缓解方法**：
- 滑雪后拉伸 10 分钟
- 泡热水澡或温泉
- 第二天如果还酸痛，休息一天再滑
- 通常 2-3 天后自然消失


path: references/tutorial-curriculum/levels/sb-0.md
content: # 单板 Level 0 技能包

> 板型：snowboard | 级别：0 | 技能数：5

## 技能列表

### L0-SB-01: 前脚确认与基础站姿
- name_en: Stance Determination & Athletic Stance
- category: stance
- rubric_mapping:
    posture: [重心位置, 膝盖弯曲]
- why_important: 一切的基础，不知道哪只脚在前后所有技能都无法正确练习
- action_guide_template: 膝盖 15-25 度弯曲，重心在两脚之间，想象坐在隐形椅子上。双手自然前伸，目视前方。通过推背测试确认 Regular（左脚前）或 Goofy（右脚前）
- common_mistakes_template: [重心后坐（坐在脚跟上）容易后摔, 膝盖完全伸直失去缓冲能力]
- practice_template: [在平地穿好前脚固定器后脚不固定用后脚蹬地行走 10 分钟, 在平地双脚都固定扶着同伴或栏杆感受站立平衡 5 分钟, 松开手尝试不扶东西站立 30 秒练 5 组]
- success_signal: 能不扶东西稳稳站立 30 秒膝盖自然微弯不觉得往后倒

### L0-SB-02: 安全摔倒和站起
- name_en: Safe Fall & Get Up
- category: safety
- rubric_mapping:
    overall: [安全意识]
- why_important: 一定会摔学会安全地摔比学会不摔更重要是首要安全技能
- action_guide_template: 后向摔倒时握拳向侧后方坐下双手收胸前下巴收向胸口。站起时翻身侧躺雪板转到与坡面垂直方向用山下侧手撑地借力站起
- common_mistakes_template: [向前扑倒手掌撑地（手腕骨折的主因）, 站起来时雪板没有转到山下侧刚站起就滑走]
- practice_template: [在缓坡上故意摔倒 5 次练习向侧后方坐下的动作, 练习从侧躺站起左右各练 5 次, 计时从摔倒到站起目标 10 秒以内]
- success_signal: 摔倒时不恐慌能主动向侧后方坐站起后雪板稳定不会立刻滑走

### L0-SB-03: 后刃滑行与刹车
- name_en: Heelside Traverse & Stop
- category: edge
- rubric_mapping:
    overall: [速度控制]
- why_important: 第一次感受到滑行的同时最重要的安全技能能停得住
- action_guide_template: 雪板横对坡面身体面向山下用后刃（脚后跟侧）卡住雪面。慢慢放松后刃压力让雪板下滑想停时脚趾上抬脚跟下压增加后刃角度
- common_mistakes_template: [身体后仰（越怕越往后仰后刃反而更抓不住雪）, 膝盖弯曲不够脚踝没有前压]
- practice_template: [在极缓坡（坡度小于 10 度）上练习滑停滑停每次滑行 3-5 米 10 组, 逐渐增加滑行距离到 10 米 20 米, 找同伴在下方 10 米处慢慢滑向他在到达前停住]
- success_signal: 能控制滑行速度想停就停不会越滑越快失控

### L0-SB-04: 前刃滑行与刹车
- name_en: Toeside Traverse & Stop
- category: edge
- rubric_mapping:
    posture: [重心位置]
- why_important: 前刃是换刃和 S 弯的基础只学后刃是不够的
- action_guide_template: 身体面向山上用前刃（脚趾侧）卡住雪面。脚尖下压脚跟抬起让前刃接触雪面保持向后坐椅子的姿势但重心不要过度后移
- common_mistakes_template: [重心过度后移坐在板上, 脚尖下压不够前刃抓不住雪]
- practice_template: [在平地穿好固定器面朝山上练习脚尖下压脚跟抬起的感觉 5 分钟, 在极缓坡上练习前刃横向移动向左向右各 5 米, 练习前刃滑停每次滑行 3-5 米 10 组]
- success_signal: 能用前刃横向移动和刹车不会脚尖或脚后跟卡雪摔倒

### L0-SB-05: 落叶飘
- name_en: Falling Leaf
- category: turning
- rubric_mapping:
    overall: [路线选择]
- why_important: 第一次方向控制体验是 S 弯的前置技能
- action_guide_template: 在后刃滑行基础上通过重心偏移让雪板向一侧横向移动呈之字形下山。重心偏向前脚向 toeside 方向移动重心偏向后脚向 heelside 方向移动
- common_mistakes_template: [重心偏移不够雪板直直往下滑, 重心偏移过大变成转弯而不是横向移动]
- practice_template: [在后刃滑行基础上尝试重心偏向前脚感受雪板向 toeside 方向移动 10 次, 尝试重心偏向后脚感受雪板向 heelside 方向移动 10 次, 练习之字形向左飘一段停向右飘一段停 5 组]
- success_signal: 能在缓坡上呈之字形下山方向可控速度可控


path: references/tutorial-curriculum/levels/sb-1.md
content: # 单板 Level 1 技能包

> 板型：snowboard | 级别：1 | 技能数：6

## 技能列表

### L1-SB-01: 换刃入门
- name_en: Edge Change
- category: edge
- rubric_mapping:
    turning: [换刃时机]
- why_important: S 弯的基础不会换刃就谈不上连续转弯
- action_guide_template: 后刃换前刃时视线看向山上方向肩膀带动身体旋转重心从前脚过渡到两脚之间同时换刃。前刃换后刃时视线看向山下方向膝盖引导身体旋转
- common_mistakes_template: [换刃时身体后仰（害怕前刃导致的本能反应）, 只转上半身下半身没跟着转]
- practice_template: [在缓坡上后刃滑行减速停止翻身到前刃前刃滑行减速停止 5 组, 逐渐减少停顿时间让换刃更连贯 5 组, 在缓坡上尝试不停顿直接后刃前刃换刃 10 次]
- success_signal: 换刃时不摔倒换完后能稳定滑行 3-5 米

### L1-SB-02: C 弯体验
- name_en: C-Turn / Garland
- category: turning
- rubric_mapping:
    turning: [弯型控制]
- why_important: 不完整的 S 弯只练入弯和出弯是连续 S 弯的前置技能
- action_guide_template: 在后刃滑行状态下通过重心偏移让雪板向一侧转弯形成 C 形弧线然后减速停止。只练半个弯不连起来
- common_mistakes_template: [转弯半径太大（变成直滑降）, 出弯时不会减速停止]
- practice_template: [后刃滑行重心偏左左转弯停止 5 次, 后刃滑行重心偏右右转弯停止 5 次, 逐渐增加转弯弧度滑出更圆的 C 形 5 组]
- success_signal: 能滑出清晰的 C 形弧线出弯时能稳定停止

### L1-SB-03: 连续 S 弯入门
- name_en: Linked Turns Introduction
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [节奏感]
- why_important: 第一次完整转弯体验是单板滑行的里程碑
- action_guide_template: 在 C 弯基础上出弯后立刻换刃进入下一个弯。顺序为入弯时视线引导弯中重心转移出弯时换刃准备然后进入下一个弯
- common_mistakes_template: [换刃时身体后仰, 转弯之间有明显停顿]
- practice_template: [在缓坡上练习 2 个连续 S 弯 5 组, 逐渐增加到 3 个连续 S 弯 5 组, 练习时喊口令左右左右帮助建立节奏]
- success_signal: 能在缓坡上完成 3 个连续 S 弯方向可控速度可控

### L1-SB-04: 搓雪 S 弯
- name_en: Skidded S-Turns
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [速度控制]
- why_important: 最实用的转弯方式板尾扫雪减速适合道内控制速度
- action_guide_template: 在连续 S 弯基础上通过立刃角度控制板尾扫雪量。立刃角度小则扫雪多减速强立刃角度大则扫雪少速度快
- common_mistakes_template: [扫雪太多（变成 Z 字形不流畅）, 扫雪太少（速度失控）]
- practice_template: [缓坡练习单个搓雪弯感受扫雪量 5 次左 5 次右, 连续 3 个搓雪 S 弯控制扫雪量一致 5 组, 逐渐增加到 5 个连续搓雪 S 弯]
- success_signal: 能在缓坡上完成 5 个连续搓雪 S 弯弯型一致速度可控

### L1-SB-05: 速度控制
- name_en: Speed Control
- category: turning
- rubric_mapping:
    overall: [速度控制]
- why_important: 蓝道必备技能不会控速就无法安全滑行
- action_guide_template: 根据地形和人流选择合适的弯型。C 弯流畅弧线速度快减速少 Z 弯急转弯速度慢减速多
- common_mistakes_template: [弯型选择不当导致速度失控, 不会根据人流密度调整弯型]
- practice_template: [缓坡练习快慢快慢节奏 C 弯加速后 Z 弯减速 5 组, 在人流密集区练习 Z 弯减速, 在开阔区练习 C 弯加速]
- success_signal: 能根据需要调整速度不会越滑越快失控

### L1-SB-06: 缆车穿脱
- name_en: Lift Loading and Unloading
- category: safety
- rubric_mapping:
    overall: [安全意识]
- why_important: 独立滑行必备技能
- action_guide_template: 上车时在等待区单脚滑行到入口后脚放到两脚之间缆车来时坐下雪板放在脚下滑槽。下车时快到终点抬起雪板前端滑出缆车后脚着地
- common_mistakes_template: [下缆车时后脚没着地导致摔倒, 下缆车后不会滑行挡住后面的人]
- practice_template: [在魔毯练习 5 次上下, 再上初级缆车练习上下, 独立完整上下缆车不摔倒不挡路]
- success_signal: 能独立上下缆车不摔倒不挡路


path: references/tutorial-curriculum/levels/sb-2.md
content: # 单板 Level 2 技能包

> 板型：snowboard | 级别：2 | 技能数：9

## 技能列表

### L2-SB-01: 搓雪小半径弯
- name_en: Short Radius Turn
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [节奏感]
- why_important: 黑道和陡坡必备技能弯半径 5-8 米可快速减速
- action_guide_template: 在搓雪 S 弯基础上加快换刃节奏减小弯半径。视线快速切换转弯方向膝盖引导换刃重心保持在前脚
- common_mistakes_template: [弯半径太大大于 10 米失去减速效果, 换刃时重心后仰]
- practice_template: [蓝道缓坡练习单个小半径弯半径 5-8 米 10 次左 10 次右, 连续 5 个小半径弯用口令控制节奏 5 组, 逐渐增加到 10 个连续小半径弯]
- success_signal: 能在蓝道上连续完成 10 个小半径弯弯半径 5-8 米节奏均匀
- terms:
    psia: Short Radius Turn / Slalom
    casi: Short Radius Pivoted Turn
    csi: Short Radius Steering Turn

### L2-SB-02: 搓雪中半径弯
- name_en: Medium Radius Turn
- category: turning
- rubric_mapping:
    turning: [弯型控制]
- why_important: 蓝道标准弯型弯半径 8-15 米流畅与控制平衡
- action_guide_template: 比小半径弯更圆滑的弧线换刃节奏稍慢。入弯时重心偏前脚弯中重心均匀出弯时准备下一个弯。立刃角度 20-30 度
- common_mistakes_template: [弯型不圆滑（呈 Z 字形）, 左右弯不对称]
- practice_template: [蓝道练习单个中半径弯感受圆滑弧线 10 次左 10 次右, 连续 5 个中半径弯保持弯型一致 5 组, 与小半径弯交替练习 2 个小弯加 2 个中弯循环]
- success_signal: 能在蓝道上完成 5 个连续中半径弯弯型圆滑对称
- terms:
    psia: Medium Radius Turn
    casi: Medium Radius Pivoted Turn
    csi: Medium Radius Steering Turn

### L2-SB-03: 搓雪大半径弯
- name_en: Large Radius Turn
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [路线选择]
- why_important: 流畅弧线速度快追求滑行美感
- action_guide_template: 弯半径 15-25 米的长弧线。入弯时身体倾斜更多立刃角度 25-35 度。压力管理为入弯前脚弯中均匀出弯后脚
- common_mistakes_template: [弯半径太小变成中半径弯, 压力管理不当（重心前后乱移）]
- practice_template: [宽阔蓝道练习单个大半径弯感受长弧线 5 次左 5 次右, 连续 3 个大半径弯保持弧线流畅 3 组, 与小中半径弯混合练习 1 大加 2 中加 3 小循环]
- success_signal: 能在宽阔蓝道上完成 3 个连续大半径弯弧线流畅速度可控
- terms:
    psia: Large Radius Turn
    casi: Large Radius Pivoted Turn
    csi: Large Radius Steering Turn

### L2-SB-04: 刻滑入门
- name_en: Carving Introduction
- category: carving
- rubric_mapping:
    turning: [卡宾质量, 立刃角度]
- why_important: 纯立刃走弧线不扫雪是高级技术的基础
- action_guide_template: 在缓坡上尝试纯立刃滑行板尾不扫雪。立刃角度 30-45 度重心在两脚之间。感受雪板边刃抓雪雪面留下清晰弧线
- common_mistakes_template: [立刃角度不够变成搓雪, 重心偏移导致板尾扫雪]
- practice_template: [缓坡练习单刃滑行感受边刃抓雪左脚单刃 5 次右脚单刃 5 次, 尝试短距离刻滑弯 3-5 米弧线板尾不扫雪 10 次, 逐渐增加刻滑距离到 10 米]
- success_signal: 能在缓坡上完成 10 米刻滑弯雪面留下清晰弧线板尾不扫雪
- terms:
    psia: Carving / Carved Turn
    casi: Carving
    csi: Carving

### L2-SB-05: 反弓姿态入门
- name_en: Angulation Introduction
- category: stance
- rubric_mapping:
    posture: [髋部对齐, 上半身姿态]
- why_important: 高速转弯中的身体控制保持上半身稳定
- action_guide_template: 髋部向山下侧偏移上半身保持面向山下呈 C 形姿态。膝盖和踝关节协同立刃肩膀保持直立
- common_mistakes_template: [整个身体一起倾斜（Inclination）不是反弓, 上半身跟着转弯方向转]
- practice_template: [平地练习反弓站姿髋部向左向右偏移上半身保持直立 10 次, 缓坡滑行中尝试反弓姿态感受边刃抓雪 10 次, 对着手机录像检查姿态或请同伴拍照]
- success_signal: 滑行中髋部偏移上半身保持面向山下边刃抓雪稳定
- terms:
    psia: Angulation
    casi: Angulation
    csi: Angulation

### L2-SB-06: 压力管理
- name_en: Pressure Control
- category: stance
- rubric_mapping:
    posture: [重心位置]
- why_important: 前后脚压力分配决定转弯质量
- action_guide_template: 入弯重心偏前脚（60% 前 40% 后）弯中重心均匀（50/50）出弯重心偏后脚（40% 前 60% 后）
- common_mistakes_template: [重心一直在后脚（害怕导致的本能）, 重心前后乱移没有规律]
- practice_template: [缓坡练习入弯时身体前压感受前脚抓雪 10 次, 练习出弯时重心转移到后脚 10 次, 完整转弯练习关注压力分配 10 次]
- success_signal: 转弯中重心从前脚到均匀到后脚流畅过渡转弯质量明显提升
- terms:
    psia: Pressure Control / Pressure Distribution
    casi: Fore/Aft Pressure + Lateral Pressure
    csi: Fore/Aft Balance

### L2-SB-07: 蓝道流畅滑行
- name_en: Blue Run Fluency
- category: terrain
- rubric_mapping:
    overall: [节奏感, 路线选择]
- why_important: 蓝道连续转弯不停顿是中级滑行的核心标志
- action_guide_template: 在蓝道上连续转弯不停顿。根据坡度调整弯大小陡坡用小弯缓坡用大弯。速度可控路线合理
- common_mistakes_template: [转弯之间出现停顿, 不会根据坡度调整弯大小]
- practice_template: [选择宽阔蓝道连续 10 个转弯不停顿 5 组, 尝试不同弯型混合 2 小加 2 中加 1 大循环, 在人流密集区练习避让和路线选择]
- success_signal: 能在蓝道上流畅滑行 5 分钟不停顿速度可控路线合理

### L2-SB-08: 基础粉雪体验
- name_en: Beginner Powder
- category: powder
- rubric_mapping:
    overall: [地形适应]
- why_important: 粉雪滑行是拓展滑行场景的第一步
- action_guide_template: 粉雪中重心后移 10-15% 增加板头浮力。身体放松不要僵硬转弯半径比硬雪大 20-30%
- common_mistakes_template: [重心太靠后导致板尾下沉, 身体僵硬不会吸收地形]
- practice_template: [第一次粉雪在粉雪区尝试重心后移滑行 5 次, 练习粉雪转弯感受浮力变化 5 次左 5 次右, 与硬雪交替练习感受差异]
- success_signal: 能在粉雪中滑行不沉板转弯流畅

### L2-SB-09: 不平整雪面入门
- name_en: Uneven Terrain Introduction
- category: terrain
- rubric_mapping:
    overall: [地形适应]
- why_important: 适应不平整雪面是提升全地形能力的关键
- action_guide_template: 膝盖弯曲更多像弹簧一样吸收冲击。视线看前方 3-5 米提前判断地形不要盯着脚下
- common_mistakes_template: [膝盖不够弯曲无法有效缓冲, 盯着脚下而不是看前方]
- practice_template: [在烂雪区尝试滑行关注膝盖缓冲 5 次, 练习冰面滑行减小立刃角度 5 次, 混合雪面练习硬雪到烂雪到硬雪交替]
- success_signal: 能在不平整雪面上滑行不摔倒膝盖有效缓冲


path: references/tutorial-curriculum/levels/sb-3.md
content: # 单板 Level 3 技能包

> 板型：snowboard | 级别：3 | 技能数：14

## 技能列表

### L3-SB-01: 动态反弓
- name_en: Dynamic Angulation
- category: stance
- rubric_mapping:
    posture: [髋部对齐, 上半身姿态]
- why_important: 高速转弯中的身体控制是高级技术的基础
- action_guide_template: 在 Level 2 反弓基础上增加动态元素。入弯时髋部快速偏移弯中保持反弓出弯时快速释放。上半身始终面向山下
- common_mistakes_template: [反弓释放太慢影响下一个弯, 上半身跟着转动]
- practice_template: [黑道缓坡练习动态反弓关注入弯弯中出弯的髋部变化 10 次, 连续小弯练习快速反弓释放 10 次, 对着手机录像或请同伴拍照检查]
- success_signal: 高速转弯中上半身稳定面向山下髋部快速偏移和释放转弯质量高
- terms:
    psia: Dynamic Angulation
    casi: Dynamic Angulation
    csi: Dynamic Angulation

### L3-SB-02: 上半身分离
- name_en: Upper-Lower Body Separation
- category: stance
- rubric_mapping:
    posture: [上半身姿态, 髋部对齐]
- why_important: 下半身转弯上半身稳定是高级滑行的标志
- action_guide_template: 下半身（膝盖、髋部、脚踝）负责转弯和立刃上半身（肩膀、头部、手臂）保持面向山下
- common_mistakes_template: [肩膀跟着转弯方向转, 头部低垂看板]
- practice_template: [黑道滑行时双手前伸指向山下保持不动 10 次, 肩膀始终面向山下只用下半身转弯 10 次, 请同伴从正面拍照检查上半身是否稳定]
- success_signal: 滑行中上半身稳定面向山下只有下半身在转动

### L3-SB-03: 地形阅读
- name_en: Terrain Reading
- category: terrain
- rubric_mapping:
    overall: [路线选择, 地形适应]
- why_important: 提前判断雪况调整技术是安全滑行的关键
- action_guide_template: 视线看前方 5-10 米而不是脚下。提前识别雪质变化坡度变化障碍物和人流
- common_mistakes_template: [视线只关注脚下而非前方, 不会提前调整技术应对地形变化]
- practice_template: [黑道滑行时提前 5 米判断地形调整弯型 10 次, 混合雪面练习硬雪到粉雪到烂雪提前调整 5 组, 人流密集区练习路线选择和避让 5 次]
- success_signal: 能提前 3-5 秒判断地形变化流畅地调整技术不慌乱

### L3-SB-04: 高立刃刻滑
- name_en: High-Edge Carving
- category: carving
- rubric_mapping:
    turning: [卡宾质量, 立刃角度]
- why_important: 立刃角度 60 度以上是刻滑专精的核心标志
- action_guide_template: 立刃角度 45-70 度反弓姿态最大化髋部接近雪面。压力管理精细入弯前脚 65% 弯中均匀出弯后脚 65%
- common_mistakes_template: [立刃角度不足无法实现纯刻滑, 压力管理不当导致弧线不稳定]
- practice_template: [宽阔黑道练习高立刃刻滑关注立刃角度 10 次, 逐渐增加速度保持弧线质量 5 组, 请同伴从侧面拍照测量立刃角度]
- success_signal: 立刃角度 60 度以上雪面留下清晰弧线高速稳定
- terms:
    psia: High-Performance Carving
    casi: High Angle Carving
    csi: Carving Development

### L3-SB-05: 动态刻滑
- name_en: Dynamic Carving
- category: carving
- rubric_mapping:
    turning: [卡宾质量, 弯型控制]
- why_important: 高速刻滑是道内滑行的终极目标
- action_guide_template: 高速刻滑身体大幅倾斜核心力量控制雪板反馈感知。入弯和出弯快速转换没有中间阶段
- common_mistakes_template: [核心力量不足导致高速失控, 入弯出弯转换不够迅速]
- practice_template: [宽阔黑道练习高速刻滑逐渐加速 5 组, 连续刻滑弯关注入弯出弯转换 10 次, 核心力量训练（陆地）平板支撑和侧桥]
- success_signal: 高速刻滑稳定身体倾斜大但不失控弧线流畅

### L3-SB-06: 短弯刻滑
- name_en: Short Radius Carving
- category: carving
- rubric_mapping:
    turning: [卡宾质量, 换刃时机]
- why_important: 小半径刻滑弯结合了刻滑质量和敏捷性
- action_guide_template: 小半径刻滑弯快速换刃立刃角度 45-60 度弯半径 5-8 米。换刃时无停顿直接从一个刃翻到另一个刃
- common_mistakes_template: [换刃时有停顿破坏流畅性, 弯半径无法控制到 5-8 米范围]
- practice_template: [黑道缓坡练习短弯刻滑半径 5-8 米 10 次, 连续短弯刻滑关注换刃质量 5 组, 与搓雪小弯对比感受差异]
- success_signal: 能在黑道上完成连续短弯刻滑弧线清晰半径小

### L3-SB-07: 中跳
- name_en: Medium Jumps
- category: freestyle
- rubric_mapping:
    freestyle: [起跳技术, 空中控制, 落地稳定性]
- why_important: 2-3 米跳台是公园进阶的核心跳台高度
- action_guide_template: 到达跳台边缘时腿部伸展起跳。空中控制身体收紧视线看落地。落地时膝盖弯曲吸收冲击重心在两脚之间
- common_mistakes_template: [起跳时机不准确（过早或过晚）, 落地时膝盖不弯曲缓冲]
- practice_template: [从小跳台 1 米开始练习起跳和落地 10 次, 逐渐增加到 2 米跳台 5 次, 空中尝试 180 度旋转 5 次]
- success_signal: 起跳时机准确空中稳定落地缓冲好不摔倒

### L3-SB-08: 360 度旋转
- name_en: 360 Degree Rotation
- category: freestyle
- rubric_mapping:
    freestyle: [旋转控制, 空中控制]
- why_important: 第一个完整旋转动作是公园表现力的里程碑
- action_guide_template: 起跳时肩膀带动旋转空中收紧身体像球一样落地前展开。视线引导旋转方向全程看落地
- common_mistakes_template: [起跳时旋转发力不足, 落地前没有展开身体]
- practice_template: [平地练习 360 度旋转动作 10 次, 小跳台练习 180 度熟练后尝试 360 度 5 次, 中跳台完成第一个 360 度 3 次]
- success_signal: 空中完成完整 360 度落地稳定方向正确

### L3-SB-09: 道具进阶
- name_en: Boxes and Rails Advanced
- category: freestyle
- rubric_mapping:
    freestyle: [平衡控制, 道具技术]
- why_important: 道具滑行是公园技术的核心组成
- action_guide_template: 低速接近道具起跳上道具。保持平衡重心在两脚之间膝盖弯曲视线看前方。落地时膝盖缓冲
- common_mistakes_template: [接近道具速度过快导致失控, 道具上重心偏移摔倒]
- practice_template: [低矮 Box 练习滑行 10 次, 增加高度和长度 5 次, 尝试 Rail 5 次]
- success_signal: 能在 Box 或 Rail 上稳定滑行不摔倒落地好

### L3-SB-10: 粉雪进阶
- name_en: Powder Advanced
- category: powder
- rubric_mapping:
    overall: [地形适应, 路线选择]
- why_important: 深粉雪滑行是野雪体验的核心
- action_guide_template: 重心后移 15-20%（比 Level 2 更多）。身体放松像冲浪一样。转弯半径更大弧线更长
- common_mistakes_template: [重心后移不足导致沉板, 用硬雪方式转弯（半径太小）]
- practice_template: [深粉雪区膝盖深度练习滑行 10 次, 粉雪中练习大半径弯 5 次左 5 次右, 粉雪中练习速度控制 5 组]
- success_signal: 深粉雪中不沉板转弯流畅速度可控

### L3-SB-11: 陡坡滑行
- name_en: Steep Slope Riding
- category: terrain
- rubric_mapping:
    overall: [速度控制, 自信度]
- why_important: 陡坡滑行能力是高级滑行者的重要标志
- action_guide_template: 坡度大于 35 度时小弯控速身体前压不要后仰。快速换刃不让速度积累视线看前方选择路线
- common_mistakes_template: [身体后仰导致失控, 换刃不够快导致速度积累]
- practice_template: [选择 30-35 度陡坡小弯滑行 5 次, 逐渐增加坡度到 40 度 3 次, 陡坡中练习紧急停止 5 次]
- success_signal: 陡坡上速度可控不慌乱能随时停止

### L3-SB-12: 道外安全
- name_en: Backcountry Safety
- category: safety
- rubric_mapping:
    overall: [安全意识, 地形适应]
- why_important: 道外滑行存在雪崩等严重风险安全知识是生命线
- action_guide_template: 识别危险地形和雪层测试必须携带雪崩搜救仪探杆雪铲。避开 30-45 度雪崩高发坡度
- common_mistakes_template: [不带安全装备进入道外, 不关注雪崩风险评估]
- practice_template: [学习雪崩安全知识（课程或在线）, 练习使用搜救仪探杆雪铲, 有经验者带领下进入道外]
- success_signal: 能识别基本雪崩风险正确使用安全装备规划安全路线

### L3-SB-13: Switch 滑行
- name_en: Riding Switch
- category: switch
- rubric_mapping:
    overall: [自信度]
- why_important: 反脚滑行提升平衡和对称性是所有高级技术的基础能力
- action_guide_template: 后脚变成前脚反脚滑行。重心视线转弯方向全部反转。从缓坡开始慢慢建立信心
- common_mistakes_template: [重心不敢放到反脚, 视线方向没有正确反转]
- practice_template: [缓坡练习 Switch 直线滑行 10 次, Switch 落叶飘 5 次左 5 次右, Switch 小弯 5 次]
- success_signal: 反脚能完成基本滑行和转弯不摔倒

### L3-SB-14: 单脚滑行感知
- name_en: One-Footed Awareness
- category: stance
- rubric_mapping:
    posture: [重心位置]
- why_important: 提升平衡和重心感知增强本体感觉
- action_guide_template: 后脚脱开固定器单脚滑行。重心完全在前脚感受平衡点
- common_mistakes_template: [重心不敢完全放到前脚, 速度过快失去单脚平衡]
- practice_template: [平地练习单脚滑行 10 米, 缓坡单脚滑行 5 次, 单脚落叶飘 5 次]
- success_signal: 单脚能完成基本滑行和刹车平衡好


path: references/tutorial-curriculum/levels/ski-0.md
content: # 双板 Level 0 技能包

> 板型：ski | 级别：0 | 技能数：5

## 技能列表

### L0-SK-01: 基础站姿与平地行走
- name_en: Athletic Stance & Flat Terrain Walking
- category: stance
- rubric_mapping:
    posture: [重心位置, 膝盖弯曲]
- why_important: 一切的基础适应双板的长度和重量才能在雪上移动
- action_guide_template: 双脚与肩同宽膝盖微弯 15-25 度小腿轻贴雪鞋前壁双手自然前伸目视前方重心在双脚中间。平地行走时小步企鹅走抬起雪板前端
- common_mistakes_template: [犁式站立时角度过大, 身体后仰重心不在脚上]
- practice_template: [平地穿好雪板感受站立 5 分钟, 小步企鹅走前进 10 米, 侧向和后向行走各 10 米]
- success_signal: 能不扶东西稳稳站立和行走雪板保持平行不交叉

### L0-SK-02: 安全摔倒和站起
- name_en: Safe Fall & Recovery
- category: safety
- rubric_mapping:
    overall: [安全意识]
- why_important: 学会安全地摔比学会不摔更重要这是最重要的安全技能
- action_guide_template: 感觉失控时向侧方倒下双手收在胸前雪板保持平行不交叉。站起时将雪板移到山下侧与坡面垂直用山下侧手撑地
- common_mistakes_template: [摔倒时雪板交叉容易扭伤膝盖, 站起时雪板方向不对平行于坡面刚站起就滑走]
- practice_template: [在缓坡上故意摔倒 5 次练习向侧方倒下, 练习从侧躺站起左右各 5 次, 计时从摔倒到站起目标 10 秒以内]
- success_signal: 摔倒时不恐慌雪板保持平行站起后雪板稳定不会立刻滑走

### L0-SK-03: 犁式制动
- name_en: Snowplow / Pizza
- category: turning
- rubric_mapping:
    overall: [速度控制]
- why_important: 第一次感受我在滑也是最重要的安全技能能停得住
- action_guide_template: 雪板前端靠拢不交叉后端分开呈 V 字形膝盖内扣用内刃卡住雪面。V 字越大刹车越强
- common_mistakes_template: [雪板前端交叉容易摔倒, 身体后仰重心不在脚上刹不住]
- practice_template: [在极缓坡（坡度小于 10 度）上练习犁式滑行加大 V 字停住每次 3-5 米共 10 组, 逐渐增加滑行距离到 10 米 20 米, 用 V 字大小调节速度]
- success_signal: 能控制滑行速度想停就停雪板前端不交叉 V 字大小能自如调节

### L0-SK-04: 犁式转弯
- name_en: Snowplow Turn
- category: turning
- rubric_mapping:
    overall: [路线选择]
- why_important: 第一次方向控制体验是平行转弯的前置技能
- action_guide_template: 在犁式制动基础上想向左转就加重右脚压力右膝更多内扣想向右转就加重左脚
- common_mistakes_template: [转弯时身体后仰, 只靠脚转身体不跟着转]
- practice_template: [在缓坡上练习犁式左弯右弯交替每个弯滑行 5 米共 10 组, 逐渐增加弯的连贯性减少弯之间的停顿, 练习画 C 字每个转弯滑出 C 形弧线]
- success_signal: 能在缓坡上连续完成左弯和右弯方向可控速度可控

### L0-SK-05: 连续犁式转弯
- name_en: Linked Snowplow Turns
- category: turning
- rubric_mapping:
    overall: [节奏感]
- why_important: 为平行转弯打基础建立转弯节奏感
- action_guide_template: 在单个犁式转弯基础上出弯后立刻准备下一个弯转弯之间不停顿保持连贯节奏
- common_mistakes_template: [转弯之间有明显停顿, 左右转弯不对称一边好一边差]
- practice_template: [在缓坡上练习连续 5 个犁式转弯转弯之间不停顿共 5 组, 逐渐增加到 10 个连续转弯, 用口令 1-2-1-2 控制转弯节奏]
- success_signal: 能在缓坡上连续完成 5 个以上犁式转弯方向可控速度可控节奏连贯


path: references/tutorial-curriculum/levels/ski-1.md
content: # 双板 Level 1 技能包

> 板型：ski | 级别：1 | 技能数：6

## 技能列表

### L1-SK-01: 犁式到平行过渡
- name_en: Stem Christie
- category: turning
- rubric_mapping:
    turning: [平行站姿]
- why_important: 从新手到中级的标志减少 V 字体验平行感觉
- action_guide_template: 在犁式转弯出弯时逐渐收拢雪板后端减少 V 字角度让双板短暂保持平行
- common_mistakes_template: [强行并板导致失控, 出弯时收板太快失去平衡]
- practice_template: [缓坡练习犁式到半平行到犁式交替每个弯尝试短暂并板 10 次, 逐渐增加平行时间从 1 秒到 2 秒共 5 组, 练习出弯收板犁式入弯弯中保持 V 字出弯收板平行 10 次]
- success_signal: 出弯时能短暂保持双板平行 1-2 秒不失控

### L1-SK-02: 平行转弯入门
- name_en: Basic Parallel Turn
- category: turning
- rubric_mapping:
    turning: [平行站姿, 弯型控制]
- why_important: 蓝道必备技能双板保持平行转弯是中级滑行的基础
- action_guide_template: 双板保持与肩同宽膝盖引导转弯方向重心在两脚中间不前不后
- common_mistakes_template: [重心后仰坐在脚跟上失去对板头的控制, 内侧板飘在外面没有参与转弯]
- practice_template: [缓坡练习单个平行转弯重点感受双板平行左右各 10 次, 连续 3 个平行转弯转弯之间不停顿共 5 组, 逐渐增加到 5 个连续平行转弯]
- success_signal: 能在缓坡上完成 3-5 个连续平行转弯双板保持平行方向可控

### L1-SK-03: 搓雪小回转入门
- name_en: Short Radius Turn Intro
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [节奏感]
- why_important: 快速连续小弯黑道陡坡必备弯半径 8-10 米适合新手
- action_guide_template: 在平行转弯基础上加快转弯节奏减小弯半径。点杖引导转弯手腕发力点在脚尖前方 10-15 厘米
- common_mistakes_template: [弯太大大于 10 米失去小回转的意义, 点杖太重用力戳雪导致身体晃动]
- practice_template: [缓坡练习单个小弯半径 8-10 米共 10 组, 连续 3 个小弯节奏 1-2-3 共 5 组, 连续 10 个小弯用口令控制节奏共 3 组]
- success_signal: 能在缓坡上连续完成 10 个小回转弯半径 8-10 米节奏均匀

### L1-SK-04: 点杖技术入门
- name_en: Pole Plant Introduction
- category: turning
- rubric_mapping:
    turning: [点杖技术]
- why_important: 节奏感和平衡的关键点杖引导转弯帮助建立节奏
- action_guide_template: 杖尖轻点雪面点在入弯点前方脚尖前方 10-15 厘米。手腕发力不是手臂动作轻巧像点而不是戳
- common_mistakes_template: [用力戳雪导致身体晃动, 点杖位置太靠后应该在入弯点前方]
- practice_template: [平地练习点杖动作手腕发力杖尖轻点地面 20 次, 缓坡犁式转弯每弯点杖一次左右各 10 次, 平行转弯每弯点杖一次练 10 次]
- success_signal: 点杖轻盈不戳雪点杖后能顺利入弯

### L1-SK-05: 蓝道体验
- name_en: Blue Run Experience
- category: terrain
- rubric_mapping:
    overall: [地形适应]
- why_important: 第一次中级道体验检验技术水平
- action_guide_template: 选择宽缓蓝道用犁式到平行过渡或平行转弯。弯型控制 C 弯加速 Z 弯减速速度可控不失控
- common_mistakes_template: [速度过快失去控制, 转弯半径太大直冲下去]
- practice_template: [选择最宽缓的蓝道用犁式到平行过渡滑行 3 次, 逐渐增加平行转弯比例共 5 次, 在蓝道完成 3 个连续转弯共 5 组]
- success_signal: 能在宽缓蓝道上完成 3 个连续转弯速度可控

### L1-SK-06: 缆车穿脱
- name_en: Lift Loading & Unloading
- category: safety
- rubric_mapping:
    overall: [安全意识]
- why_important: 独立滑行必备技能
- action_guide_template: 上车时缆车来后坐下雪板放在脚下凹槽里放下安全杆。下车时快到终点抬起雪板前端滑出后用犁式制动减速
- common_mistakes_template: [下缆车时不会犁式制动摔倒, 下缆车后不会滑行挡住后面的人]
- practice_template: [在魔毯练习 5 次上下, 再上初级缆车练习, 练习犁式制动离开缆车区域]
- success_signal: 能独立上下缆车不摔倒不挡路


path: references/tutorial-curriculum/levels/ski-2.md
content: # 双板 Level 2 技能包

> 板型：ski | 级别：2 | 技能数：10

## 技能列表

### L2-SK-01: 搓雪小回转
- name_en: Short Radius Turn / Slalom
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [节奏感]
- why_important: 黑道陡坡必备弯半径 5-8 米快速减速
- action_guide_template: 在平行转弯基础上加快转弯节奏减小弯半径。点杖引导转弯手腕发力点在入弯点前方 10-15 厘米
- common_mistakes_template: [弯太大大于 10 米失去小回转的意义, 点杖太重用力戳雪导致身体晃动]
- practice_template: [蓝道缓坡练习单个小回转半径 5-8 米左右各 10 次, 连续 10 个小回转用口令控制节奏共 5 组, 逐渐增加坡度保持弯半径不变]
- success_signal: 能在蓝道上连续完成 10 个小回转弯半径 5-8 米节奏均匀
- terms:
    psia: Short Radius Turn / Slalom
    casi: Short Radius Pivoted Turn
    csi: Short Radius Steering Turn

### L2-SK-02: 搓雪中回转
- name_en: Medium Radius Turn
- category: turning
- rubric_mapping:
    turning: [弯型控制]
- why_important: 蓝道标准弯型弯半径 8-15 米流畅与控制平衡
- action_guide_template: 比小回转更圆滑的弧线点杖节奏稍慢。入弯时重心微前弯中均匀出弯准备下一个弯立刃角度 20-30 度
- common_mistakes_template: [弯型不圆滑呈 Z 字形, 左右弯不对称]
- practice_template: [蓝道练习单个中回转感受圆滑弧线左右各 10 次, 连续 5 个中回转保持弯型一致共 5 组, 与小回转交替练习 2 个小弯加 2 个中弯循环]
- success_signal: 能在蓝道上完成 5 个连续中回转弯型圆滑对称

### L2-SK-03: 搓雪大回转
- name_en: Giant Slalom
- category: turning
- rubric_mapping:
    turning: [弯型控制]
    overall: [路线选择]
- why_important: 流畅弧线速度快追求滑行美感
- action_guide_template: 弯半径 15-25 米长弧线。入弯时身体倾斜更多立刃角度 25-35 度。压力管理入弯前脚弯中均匀出弯后脚
- common_mistakes_template: [弯半径太小变成中回转, 压力管理不当]
- practice_template: [宽阔蓝道练习单个大回转感受长弧线左右各 5 次, 连续 3 个大回转保持弧线流畅共 3 组, 与小中回转混合练习 1 大加 2 中加 3 小循环]
- success_signal: 能在宽阔蓝道上完成 3 个连续大回转弧线流畅速度可控

### L2-SK-04: 卡宾入门
- name_en: Carving Introduction
- category: carving
- rubric_mapping:
    turning: [卡宾质量, 立刃角度]
- why_important: 纯立刃走弧线不搓雪是高级技术的基础
- action_guide_template: 在缓坡上尝试纯立刃滑行双板平行板尾不扫雪。立刃角度 30-45 度重心在两脚中间
- common_mistakes_template: [立刃角度不够变成搓雪, 双板不平行内侧板飘]
- practice_template: [缓坡练习单刃滑行感受边刃抓雪左右各 5 次, 尝试短距离卡宾弯 3-5 米弧线板尾不扫雪共 10 次, 逐渐增加卡宾距离到 10 米]
- success_signal: 能在缓坡上完成 10 米卡宾弯雪面留下清晰弧线板尾不扫雪
- terms:
    psia: Carving / Carved Turn
    casi: Carving
    csi: Carving

### L2-SK-05: 反弓姿态
- name_en: Angulation
- category: stance
- rubric_mapping:
    posture: [髋部对齐, 上半身姿态]
- why_important: 高速转弯中的身体控制保持上半身稳定
- action_guide_template: 髋部向弯内偏移上半身保持面向山下像 C 形姿态髋部突出肩膀直立
- common_mistakes_template: [整个身体一起倾斜 Inclination 而不是反弓, 上半身跟着转弯方向转]
- practice_template: [平地练习反弓站姿髋部向左右偏移上半身保持直立 10 次, 缓坡滑行中尝试反弓姿态感受边刃抓雪 10 次, 对着手机录像检查姿态或请同伴拍照]
- success_signal: 滑行中髋部偏移上半身保持面向山下边刃抓雪稳定
- terms:
    psia: Angulation
    casi: Angulation
    csi: Angulation

### L2-SK-06: 点杖技术精进
- name_en: Pole Plant Mastery
- category: turning
- rubric_mapping:
    turning: [点杖技术]
- why_important: 节奏感和平衡的关键引导转弯时机
- action_guide_template: 杖尖轻点雪面点在入弯点前方脚尖前方 10-15 厘米。手腕发力不是手臂动作轻巧
- common_mistakes_template: [用力戳雪导致身体晃动, 点杖位置太靠后]
- practice_template: [平地练习点杖动作手腕发力杖尖轻点地面 20 次, 蓝道小回转每弯点杖一次练 20 次, 延迟点杖练习先转再点体验重心转移 10 次]
- success_signal: 点杖轻盈不戳雪点杖后能顺利入弯节奏稳定

### L2-SK-07: 压力管理
- name_en: Pressure Control
- category: stance
- rubric_mapping:
    posture: [重心位置]
- why_important: 前后脚压力分配决定转弯质量
- action_guide_template: 入弯重心偏前脚 60% 前 40% 后弯中重心均匀 50% 前 50% 后出弯重心偏后脚 40% 前 60% 后
- common_mistakes_template: [重心一直在后脚害怕导致的本能, 重心前后乱移没有规律]
- practice_template: [缓坡练习入弯时身体前压感受前脚抓雪 10 次, 练习出弯时重心转移到后脚 10 次, 完整转弯练习关注压力分配 10 次]
- success_signal: 转弯中重心从前脚到均匀到后脚流畅过渡转弯质量明显提升
- terms:
    psia: Pressure Control / Pressure Distribution
    casi: Fore/Aft Pressure + Lateral Pressure
    csi: Fore/Aft Balance

### L2-SK-08: 蓝道流畅滑行
- name_en: Blue Run Fluency
- category: terrain
- rubric_mapping:
    overall: [路线选择, 地形适应]
- why_important: 在蓝道上连续转弯不停顿是中级水平的标志
- action_guide_template: 在蓝道上连续转弯不停顿。根据坡度调整弯大小陡坡用小弯缓坡用大弯速度可控路线合理
- common_mistakes_template: [在蓝道上速度失控, 转弯节奏不一致忽快忽慢]
- practice_template: [选择宽阔蓝道连续 10 个转弯不停顿共 5 组, 尝试不同弯型混合 2 小加 2 中加 1 大循环, 在人流密集区练习避让和路线选择]
- success_signal: 能在蓝道上流畅滑行 5 分钟不停顿速度可控路线合理

### L2-SK-09: 蘑菇入门
- name_en: Mogul Introduction
- category: mogul
- rubric_mapping:
    overall: [地形适应]
- why_important: 体验蘑菇道滑行建立吸收技术和节奏感
- action_guide_template: 在慢速蘑菇道上体验。点杖在每个雪包顶部膝盖弯曲吸收冲击线路选择走雪包之间
- common_mistakes_template: [直冲雪包不吸收, 点杖位置不对]
- practice_template: [选择最慢的蘑菇道用犁式体验 3 次, 尝试平行转弯过蘑菇膝盖吸收 5 次, 点杖配合每包点一次 5 次]
- success_signal: 能在慢速蘑菇道上滑行不摔倒膝盖有效缓冲

### L2-SK-10: 基础粉雪体验
- name_en: Beginner Powder
- category: powder
- rubric_mapping:
    overall: [地形适应]
- why_important: 体验粉雪浮力控制为道外滑行打基础
- action_guide_template: 粉雪中重心后移 10-15% 增加板头浮力。身体放松不要僵硬转弯半径比硬雪大 20-30%
- common_mistakes_template: [重心太靠后板尾下沉, 身体僵硬不会吸收地形]
- practice_template: [第一次粉雪在粉雪区尝试重心后移滑行 5 次, 练习粉雪转弯感受浮力变化左右各 5 次, 与硬雪交替练习感受差异]
- success_signal: 能在粉雪中滑行不沉板转弯流畅


path: references/tutorial-curriculum/levels/ski-3.md
content: # 双板 Level 3 技能包

> 板型：ski | 级别：3 | 技能数：13

## 技能列表

### L3-SK-01: 动态反弓
- name_en: Dynamic Angulation
- category: stance
- rubric_mapping:
    posture: [髋部对齐, 上半身姿态]
- why_important: 高速转弯中的身体控制高级技术的基础
- action_guide_template: 在反弓基础上增加动态元素。入弯时髋部快速偏移弯中保持反弓出弯时快速释放上半身始终面向山下
- common_mistakes_template: [反弓释放太慢影响下一个弯, 上半身跟着转动]
- practice_template: [黑道缓坡练习动态反弓关注入弯弯中出弯的髋部变化 10 次, 连续小弯练习快速反弓释放 10 次, 对着手机录像或请同伴拍照检查]
- success_signal: 高速转弯中上半身稳定面向山下髋部快速偏移和释放转弯质量高
- terms:
    psia: Dynamic Angulation
    casi: Dynamic Angulation
    csi: Dynamic Angulation

### L3-SK-02: 上半身分离
- name_en: Upper-Lower Body Separation
- category: stance
- rubric_mapping:
    posture: [上半身姿态, 髋部对齐]
- why_important: 下半身转弯上半身稳定高级滑行的标志
- action_guide_template: 下半身膝盖髋部脚踝负责转弯和立刃上半身肩膀头部手臂保持面向山下
- common_mistakes_template: [肩膀跟着转弯方向转, 头部低垂看板]
- practice_template: [黑道滑行时双手前伸指向山下保持不动 10 次, 肩膀始终面向山下只用下半身转弯 10 次, 请同伴从正面拍照检查上半身是否稳定]
- success_signal: 滑行中上半身稳定面向山下只有下半身在转动

### L3-SK-03: 地形阅读
- name_en: Terrain Reading
- category: terrain
- rubric_mapping:
    overall: [路线选择, 地形适应]
- why_important: 提前判断雪况调整技术安全滑行的关键
- action_guide_template: 视线看前方 5-10 米不是脚下。提前识别雪质变化坡度变化障碍物流人
- common_mistakes_template: [只看脚下不提前判断, 遇到变化时慌乱失重心]
- practice_template: [黑道滑行时提前 5 米判断地形调整弯型 10 次, 混合雪面练习硬雪到粉雪到烂雪提前调整共 5 组, 蘑菇道练习提前判断线路 5 次]
- success_signal: 能提前 3-5 秒判断地形变化流畅地调整技术不慌乱

### L3-SK-04: 单脚滑行
- name_en: One-Legged Skiing
- category: freestyle
- rubric_mapping:
    posture: [重心位置]
- why_important: 提升平衡和重心感知
- action_guide_template: 抬起一只脚单脚滑行。重心完全在支撑脚感受平衡点提升本体感觉和核心力量
- common_mistakes_template: [重心不稳摔倒, 抬起的脚触雪干扰平衡]
- success_signal: 单脚能完成基本滑行和转弯平衡好

### L3-SK-05: 高立刃卡宾
- name_en: High-Edge Carving
- category: carving
- rubric_mapping:
    turning: [立刃角度, 卡宾质量]
- why_important: 立刃角度 60 度以上高速卡宾雪面留下清晰弧线
- action_guide_template: 立刃角度 45-70 度反弓姿态最大化髋部接近雪面。压力管理精细入弯前脚 65% 弯中均匀出弯后脚 65%
- common_mistakes_template: [立刃不够导致搓雪非卡宾, 反弓不足身体外侧倾斜]
- success_signal: 立刃角度 60 度以上雪面留下清晰弧线高速稳定双板平行
- terms:
    psia: High-Performance Parallel
    casi: Carving Development
    csi: Carving / Performance Parallel

### L3-SK-06: 动态卡宾
- name_en: Dynamic Carving
- category: carving
- rubric_mapping:
    turning: [卡宾质量]
- why_important: 高速卡宾身体大幅倾斜是卡宾的终极追求
- action_guide_template: 高速卡宾身体大幅倾斜核心力量控制雪板反馈感知。入弯和出弯快速转换没有中间阶段
- common_mistakes_template: [速度过快失控, 核心力量不足身体变形]
- success_signal: 高速卡宾稳定身体倾斜大但不失控弧线流畅

### L3-SK-07: 短弯卡宾
- name_en: Short Radius Carving
- category: carving
- rubric_mapping:
    turning: [卡宾质量, 弯型控制]
- why_important: 小半径卡宾弯快速换刃展现精确控制
- action_guide_template: 小半径卡宾弯快速换刃立刃角度 45-60 度弯半径 5-8 米。换刃时无停顿直接从一个刃翻到另一个刃
- common_mistakes_template: [换刃时有停顿变成搓雪, 弯半径控制不一致]
- success_signal: 能在黑道上完成连续短弯卡宾弧线清晰半径小

### L3-SK-08: 蘑菇节奏
- name_en: Mogul Rhythm
- category: mogul
- rubric_mapping:
    turning: [点杖技术]
    overall: [节奏感]
- why_important: 在蘑菇道上建立稳定节奏是蘑菇滑行的核心
- action_guide_template: 在蘑菇道上建立稳定节奏。转吸转吸每个雪包转弯加吸收。点杖在每个雪包顶部引导转弯
- common_mistakes_template: [节奏不稳忽快忽慢, 点杖时机不准确]
- success_signal: 蘑菇道上节奏稳定不快不慢 20 个雪包不停顿

### L3-SK-09: 吸收技术进阶
- name_en: Absorption & Extension Advanced
- category: mogul
- rubric_mapping:
    overall: [地形适应]
- why_important: 膝盖和髋部双弹簧吸收是蘑菇道的核心技术
- action_guide_template: 膝盖和髋部像双弹簧。上雪包时弯曲吸收压缩下雪包时伸展释放。上半身保持平稳高度不上下颠簸
- common_mistakes_template: [只屈膝不配合髋部, 上半身跟着上下颠簸]
- success_signal: 上半身平稳膝盖和髋部有效吸收冲击不颠簸

### L3-SK-10: 连续蘑菇道
- name_en: Continuous Mogul Run
- category: mogul
- rubric_mapping:
    overall: [地形适应, 节奏感]
- why_important: 完整蘑菇道从头滑到尾检验蘑菇综合能力
- action_guide_template: 完整蘑菇道从头滑到尾。线路选择走雪包之间不是正对。点杖每个包顶吸收每个包
- common_mistakes_template: [线路选择错误正对雪包滑行, 中途停顿失去动量]
- success_signal: 能完成高级蘑菇道全程节奏稳定不失控

### L3-SK-11: 粉雪进阶
- name_en: Powder Advanced
- category: powder
- rubric_mapping:
    overall: [地形适应]
- why_important: 深粉雪中双板不沉转弯流畅需要精确的浮力控制
- action_guide_template: 重心后移 15-20% 比 Level 2 更多。身体放松像冲浪一样转弯半径更大弧线更长
- common_mistakes_template: [重心太后导致板尾沉雪, 转弯时身体僵硬不流畅]
- success_signal: 深粉雪中双板不沉转弯流畅速度可控

### L3-SK-12: 陡坡滑行
- name_en: Steep Slope Skiing
- category: terrain
- rubric_mapping:
    overall: [地形适应, 速度控制]
- why_important: 坡度大于 35 度的陡坡上保持速度可控
- action_guide_template: 坡度大于 35 度小弯控速身体前压不要后仰。快速换刃不让速度积累点杖引导每个弯
- common_mistakes_template: [身体后仰失控, 速度积累过快不敢换刃]
- success_signal: 陡坡上速度可控不慌乱能随时停止

### L3-SK-13: 道外安全
- name_en: Backcountry Safety
- category: safety
- rubric_mapping:
    overall: [安全意识]
- why_important: 道外滑行必须掌握雪崩安全知识和装备使用
- action_guide_template: 雪崩基础识别危险地形和雪层测试。必须携带雪崩搜救仪探杆雪铲。路线规划避开 30-45 度雪崩高发坡度
- common_mistakes_template: [无装备进入道外, 不识别雪崩危险地形]
- success_signal: 能识别基本雪崩风险正确使用安全装备规划安全路线


path: references/tutorial-curriculum/training.md
content: # 训练计划框架（Training Framework）

定义各级别训练天数、时长、技能顺序和休息规则。

## 单板训练计划

```yaml
training_framework_snowboard:
  level_0:
    total_days: 1
    daily_hours: 2.5
    skill_sequence:
      - skill_ids: [L0-SB-02, L0-SB-03]
        duration_minutes: 45
        weight: 0.30
      - skill_ids: [L0-SB-03]
        duration_minutes: 30
        weight: 0.20
      - skill_ids: [L0-SB-04, L0-SB-05]
        duration_minutes: 35
        weight: 0.23
    rest_rule: 第一天不要超过 3 小时肌肉会疲劳
    day1_focus: [L0-SB-02, L0-SB-03, L0-SB-04, L0-SB-05]

  level_1:
    total_days: 3
    daily_hours: 2.2
    skill_sequence:
      - skill_ids: [L1-SB-01, L1-SB-02]
        duration_hours: 2
        weight: 0.30
        day: 1
      - skill_ids: [L1-SB-03]
        duration_hours: 2
        weight: 0.30
        day: 2
      - skill_ids: [L1-SB-04, L1-SB-05]
        duration_hours: 2.5
        weight: 0.38
        day: 3
    rest_rule: 每天练习 2-3 小时不要超过肌肉疲劳会影响学习
    day1_focus: [L1-SB-01, L1-SB-02]

  level_2:
    total_days: 5
    daily_hours: 2.7
    skill_sequence:
      - skill_ids: [L2-SB-01, L2-SB-02]
        duration_hours: 2.5
        weight: 0.18
        day: 1
      - skill_ids: [L2-SB-03, L2-SB-06]
        duration_hours: 2.5
        weight: 0.18
        day: 2
      - skill_ids: [L2-SB-04, L2-SB-05]
        duration_hours: 2.5
        weight: 0.18
        day: 3
      - skill_ids: [L2-SB-07]
        duration_hours: 3
        weight: 0.22
        day: 4
      - skill_ids: [L2-SB-08, L2-SB-09]
        duration_hours: 3
        weight: 0.22
        day: 5
    rest_rule: 每天 2.5-3 小时第 4-5 天可适当延长到 3 小时
    day1_focus: [L2-SB-01, L2-SB-02]

  level_3:
    is_continuous: true
    style_tracks:
      carving:
        skills: [L3-SB-04, L3-SB-05, L3-SB-06]
        description: 刻滑路线：高立刃刻滑、动态刻滑、短弯刻滑
      freestyle:
        skills: [L3-SB-07, L3-SB-08, L3-SB-09]
        description: 公园路线：中跳、360 度旋转、道具进阶
      powder:
        skills: [L3-SB-10, L3-SB-11, L3-SB-12]
        description: 野雪路线：粉雪进阶、陡坡滑行、道外安全
    rest_rule: 持续精进级别建议每年雪季设定一个技术目标雪季前 1-2 天回顾 Level 2 核心技能
```

## 双板训练计划

```yaml
training_framework_ski:
  level_0:
    total_days: 1
    daily_hours: 2.5
    skill_sequence:
      - skill_id: L0-SK-01
        weight: 0.15
      - skill_id: L0-SK-02
        weight: 0.15
      - skill_id: L0-SK-03
        weight: 0.20
      - skill_id: L0-SK-04
        weight: 0.15
      - skill_id: L0-SK-05
        weight: 0.15
    rest_rule: 第一天不要超过 3 小时肌肉会疲劳
    day1_focus: [L0-SK-01, L0-SK-02, L0-SK-03, L0-SK-04, L0-SK-05]

  level_1:
    total_days: 3
    daily_hours: 2.0
    skill_sequence:
      - skill_id: L1-SK-01
        weight: 0.18
      - skill_id: L1-SK-02
        weight: 0.18
      - skill_id: L1-SK-03
        weight: 0.18
      - skill_id: L1-SK-04
        weight: 0.18
      - skill_id: L1-SK-05
        weight: 0.14
      - skill_id: L1-SK-06
        weight: 0.14
    rest_rule: 每天练习 2-3 小时不要超过肌肉疲劳会影响学习
    day1_focus: [L1-SK-01, L1-SK-02]

  level_2:
    total_days: 5
    daily_hours: 2.5
    skill_sequence:
      - skill_id: L2-SK-01
        weight: 0.15
      - skill_id: L2-SK-02
        weight: 0.12
      - skill_id: L2-SK-03
        weight: 0.10
      - skill_id: L2-SK-04
        weight: 0.10
      - skill_id: L2-SK-05
        weight: 0.12
      - skill_id: L2-SK-06
        weight: 0.10
      - skill_id: L2-SK-07
        weight: 0.12
      - skill_id: L2-SK-08
        weight: 0.08
      - skill_id: L2-SK-09
        weight: 0.06
      - skill_id: L2-SK-10
        weight: 0.05
    rest_rule: 每天 2.5-3 小时避免肌肉疲劳
    day1_focus: [L2-SK-01, L2-SK-02]

  level_3:
    is_continuous: true
    style_tracks:
      carving:
        skills: [L3-SK-05, L3-SK-06, L3-SK-07]
        description: 卡宾路线：高立刃卡宾、动态卡宾、短弯卡宾
      mogul:
        skills: [L3-SK-08, L3-SK-09, L3-SK-10]
        description: 蘑菇路线：蘑菇节奏、吸收技术进阶、连续蘑菇道
      powder:
        skills: [L3-SK-11, L3-SK-12, L3-SK-13]
        description: 野雪路线：粉雪进阶、陡坡滑行、道外安全
    rest_rule: 持续精进每雪季 10 天以上每年雪季前 1-2 天回顾 Level 2 核心技能
```


path: tools/card_generator.py
content: #!/usr/bin/env python3
"""
小红书分享卡片生成器（纯本地操作，无任何网络请求）
用法:
  python tools/card_generator.py score-card '<json>'
  python tools/card_generator.py progress-card '<json>'
  python tools/card_generator.py milestone-card '<json>'

安全说明:
  - 纯本地图片生成，不发起任何网络请求
  - 仅在 ~/.ski-assistant/exports/ 目录写入图片文件
  - 不读取用户隐私数据，仅使用用户提供的卡片参数
  - 不执行 shell、subprocess 或访问外部 API

依赖: pip install Pillow（可选，缺失时提示安装）
"""

import json
import os
import sys
from datetime import datetime
from typing import Tuple, Dict

# 数据目录
_DATA_DIR = os.environ.get("SKI_ASSISTANT_DATA_DIR",
                           os.path.join(os.path.expanduser("~"), ".ski-assistant"))
_EXPORTS_DIR = os.path.join(_DATA_DIR, "exports")

# 小红书图片规格
XHS_WIDTH = 1080
XHS_HEIGHT = 1440

# 配色方案
COLORS = {
    "bg_top": (25, 55, 95),
    "bg_bottom": (60, 120, 160),
    "accent": (255, 140, 60),
    "accent_light": (255, 200, 120),
    "white": (255, 255, 255),
    "text_primary": (40, 40, 40),
    "text_light": (255, 255, 255),
    "card_bg": (255, 255, 255, 230),
    "score_high": (80, 180, 120),
    "score_mid": (255, 180, 60),
    "score_low": (230, 100, 100),
}

DIM_LABELS = {"posture": "基础姿态", "turning": "转弯技术",
              "freestyle": "自由式", "overall": "综合滑行"}


def _check_pillow():
    try:
        from PIL import Image, ImageDraw, ImageFont
        return True, (Image, ImageDraw, ImageFont)
    except ImportError:
        return False, None


def _get_font(ImageFont, size: int, bold: bool = False):
    paths = (["/System/Library/Fonts/PingFang.ttc",
              "/usr/share/fonts/truetype/noto/NotoSansCJK-Bold.ttc",
              "C:/Windows/Fonts/simhei.ttf"] if bold else
             ["/System/Library/Fonts/PingFang.ttc",
              "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
              "C:/Windows/Fonts/msyh.ttc"])
    for p in paths:
        if os.path.exists(p):
            try:
                return ImageFont.truetype(p, size)
            except Exception:
                pass
    try:
        return ImageFont.load_default()
    except Exception:
        return None


def _score_color(score: float) -> Tuple[int, int, int]:
    if score >= 8:
        return COLORS["score_high"]
    elif score >= 6:
        return COLORS["score_mid"]
    return COLORS["score_low"]


def _gradient_bg(Image, w, h):
    img = Image.new("RGB", (w, h))
    px = img.load()
    t, b = COLORS["bg_top"], COLORS["bg_bottom"]
    for y in range(h):
        r = y / h
        for x in range(w):
            px[x, y] = (int(t[0]*(1-r)+b[0]*r), int(t[1]*(1-r)+b[1]*r), int(t[2]*(1-r)+b[2]*r))
    return img


def generate_score_card(params: dict) -> str:
    ok, pil = _check_pillow()
    if not ok:
        return json.dumps({"error": "缺少 Pillow 依赖，请运行: pip install Pillow"}, ensure_ascii=False)

    Image, ImageDraw, ImageFont = pil
    resort = params.get("resort", "未知雪场")
    run_name = params.get("run_name", "")
    date = params.get("date", datetime.now().strftime("%Y-%m-%d"))
    scores = params.get("scores", {})
    highlights = params.get("highlights", [])
    style = params.get("style", "casual")

    valid = [v for v in scores.values() if isinstance(v, (int, float)) and v > 0]
    total = sum(valid) / len(valid) if valid else 0

    img = _gradient_bg(Image, XHS_WIDTH, XHS_HEIGHT)
    draw = ImageDraw.Draw(img)
    ft = _get_font(ImageFont, 48, True)
    fb = _get_font(ImageFont, 32)
    fs = _get_font(ImageFont, 24)
    fsc = _get_font(ImageFont, 120, True)

    y = 60
    draw.text((XHS_WIDTH//2, y), "🏂 滑雪日记", font=ft, fill=COLORS["text_light"], anchor="mm")
    y += 80
    draw.text((XHS_WIDTH//2, y), resort, font=fb, fill=COLORS["accent_light"], anchor="mm")
    y += 50
    if run_name:
        draw.text((XHS_WIDTH//2, y), f"{run_name} | {date}", font=fs, fill=COLORS["text_light"], anchor="mm")
        y += 60

    y += 40
    draw.text((XHS_WIDTH//2, y), f"{total:.1f}", font=fsc, fill=_score_color(total), anchor="mm")
    draw.text((XHS_WIDTH//2+120, y+20), "/10", font=fb, fill=COLORS["text_light"], anchor="mm")
    y += 140

    margin = 80
    cw = XHS_WIDTH - margin*2
    y += 20
    for dim, label in DIM_LABELS.items():
        s = scores.get(dim, 0)
        if s <= 0:
            continue
        draw.text((margin+20, y+10), label, font=fs, fill=COLORS["text_light"])
        bar_bg = Image.new("RGBA", (cw-200, 24), (230, 230, 230, 180))
        img.paste(bar_bg, (margin+120, y+8), bar_bg)
        fw = int((cw-200)*min(s/10, 1.0))
        bar = Image.new("RGBA", (fw, 24), (*_score_color(s), 220))
        img.paste(bar, (margin+120, y+8), bar)
        draw.text((XHS_WIDTH-margin-20, y+10), f"{s}", font=fs, fill=COLORS["text_light"], anchor="rm")
        y += 50
    y += 30

    if highlights:
        y += 20
        ch = min(80+len(highlights)*50, 300)
        ov = Image.new("RGBA", (cw, ch), COLORS["card_bg"])
        img.paste(ov, (margin, y), ov)
        cy = y+20
        draw.text((XHS_WIDTH//2, cy), "✨ AI教练点评", font=fb, fill=COLORS["accent"], anchor="mm")
        cy += 50
        for h in highlights[:3]:
            draw.text((margin+30, cy), f"• {h}", font=fs, fill=COLORS["text_primary"])
            cy += 45

    y = XHS_HEIGHT-100
    tags = f"#滑雪  #{resort.replace('滑雪场','').replace('滑雪','')}"
    draw.text((XHS_WIDTH//2, y), tags, font=fs, fill=COLORS["text_light"], anchor="mm")

    os.makedirs(_EXPORTS_DIR, exist_ok=True)
    ts = datetime.now().strftime("%Y%m%d_%H%M%S")
    out = os.path.join(_EXPORTS_DIR, f"xhs_score_{ts}.jpg")
    img.save(out, "JPEG", quality=95)

    return json.dumps({"success": True, "output_path": out, "total_score": round(total, 1), "style": style},
                      ensure_ascii=False, indent=2)


def generate_progress_card(params: dict) -> str:
    return json.dumps({"error": "进步对比卡片尚未实现，请使用 score-card"}, ensure_ascii=False)


def generate_milestone_card(params: dict) -> str:
    return json.dumps({"error": "里程碑卡片尚未实现，请使用 score-card"}, ensure_ascii=False)


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(__doc__)
        sys.exit(1)

    cmd = sys.argv[1]
    params = json.loads(sys.argv[2])

    funcs = {"score-card": generate_score_card,
             "progress-card": generate_progress_card,
             "milestone-card": generate_milestone_card}
    if cmd not in funcs:
        print(json.dumps({"error": f"未知命令: {cmd}"}, ensure_ascii=False))
        sys.exit(1)

    print(funcs[cmd](params))


path: tools/exchange_rate.py
content: #!/usr/bin/env python3
"""
实时汇率换算工具（只读网络请求，不修改任何文件）
用法:
  python tools/exchange_rate.py <amount> <from> <to>
  python tools/exchange_rate.py '{"amount":7800,"from":"JPY","to":"CNY"}'

安全说明:
  - 仅向 exchangerate-api.com 发起 GET 请求，不发送任何用户数据
  - 不执行 shell、subprocess 或文件写入操作
  - 联网失败时自动降级为内置静态汇率（标注"参考汇率"）
  - 仅用户显式运行命令时触发，无后台自动联网

支持币种: CNY, JPY, KRW, CHF, EUR, CAD, USD, NZD, AUD, GBP
"""

import json
import sys
import time
import urllib.request

# 备用静态汇率（联网失败时使用）
_FALLBACK_RATES_TO_CNY = {
    "CNY": 1.0, "JPY": 0.048, "KRW": 0.0053, "CHF": 8.2,
    "EUR": 7.9, "CAD": 5.3, "USD": 7.25, "NZD": 4.4,
    "AUD": 4.8, "GBP": 9.2,
}


def get_live_rate(from_cur: str, to_cur: str):
    """获取实时汇率，返回 (rate, is_live)"""
    url = f"https://api.exchangerate-api.com/v4/latest/{from_cur}"
    for attempt in range(3):
        try:
            req = urllib.request.Request(url, headers={"User-Agent": "ski-assistant/5.1"})
            with urllib.request.urlopen(req, timeout=5) as resp:
                data = json.loads(resp.read().decode())
                rate = data.get("rates", {}).get(to_cur)
                if rate:
                    return rate, True
        except Exception:
            if attempt < 2:
                time.sleep(0.5 * (attempt + 1))
    return None, False


def convert(amount: float, from_cur: str, to_cur: str) -> dict:
    from_cur, to_cur = from_cur.upper(), to_cur.upper()
    rate, is_live = get_live_rate(from_cur, to_cur)

    if rate is None:
        fr = _FALLBACK_RATES_TO_CNY.get(from_cur)
        tr = _FALLBACK_RATES_TO_CNY.get(to_cur)
        if fr and tr:
            rate, is_live = fr / tr, False
        else:
            return {"error": f"不支持的币种: {from_cur} 或 {to_cur}"}

    return {
        "from": {"amount": amount, "currency": from_cur},
        "to": {"amount": round(amount * rate, 2), "currency": to_cur},
        "rate": round(rate, 6),
        "is_live": is_live,
        "note": "实时汇率" if is_live else "参考汇率（离线备用值）",
    }


if __name__ == "__main__":
    if len(sys.argv) == 4:
        result = convert(float(sys.argv[1]), sys.argv[2], sys.argv[3])
    elif len(sys.argv) == 2:
        p = json.loads(sys.argv[1])
        result = convert(p["amount"], p["from"], p["to"])
    else:
        print(__doc__)
        sys.exit(1)

    if "error" in result:
        print(f"错误: {result['error']}")
        sys.exit(1)
    f, t = result["from"], result["to"]
    print(f"{f['currency']} {f['amount']:,.2f} = {t['currency']} {t['amount']:,.2f}")
    print(f"汇率: 1 {f['currency']} = {result['rate']} {t['currency']}")
    print(f"来源: {result['note']}")


path: tools/price_api.py
content: #!/usr/bin/env python3
"""
flyai CLI 桥接工具（仅调用预定义的 flyai 子命令，不执行任意 shell）
用法:
  python tools/price_api.py search-flight '<json>'
  python tools/price_api.py search-hotel '<json>'
  python tools/price_api.py search-poi '<json>'
  python tools/price_api.py keyword-search '<json>'
  python tools/price_api.py check

安全说明:
  - 仅通过 subprocess.run() 调用 'flyai' 可执行文件 + 固定参数
  - 不执行 shell（shell=False），不拼接用户输入到命令字符串
  - 所有参数通过独立的 argv 列表传递，无命令注入风险
  - 不发送任何数据到外部服务器（仅 flyai CLI 自身联网查询）
  - 仅用户显式运行命令时触发，无后台自动执行
"""

import json
import subprocess
import sys


def flyai_available() -> bool:
    """检测 flyai CLI 是否已安装"""
    try:
        r = subprocess.run(["flyai", "--help"], capture_output=True, timeout=5)
        return r.returncode == 0
    except Exception:
        return False


def run_flyai(args: list, timeout: int = 20) -> dict:
    """运行 flyai 命令并返回解析后的 JSON"""
    try:
        r = subprocess.run(["flyai"] + args, capture_output=True, text=True, timeout=timeout)
        if r.returncode != 0:
            return {"error": f"flyai 返回错误码 {r.returncode}", "stderr": r.stderr[:500]}
        data = json.loads(r.stdout)
        if data.get("status") == 0:
            return data
        return {"error": f"flyai 返回状态异常: {data.get('status')}", "raw": r.stdout[:500]}
    except subprocess.TimeoutExpired:
        return {"error": f"flyai 执行超时（{timeout}s）"}
    except json.JSONDecodeError:
        return {"error": "flyai 输出非 JSON 格式", "raw": r.stdout[:500]}
    except FileNotFoundError:
        return {"error": "flyai 未安装，请先安装 flyai CLI"}
    except Exception as e:
        return {"error": str(e)}


def search_flight(params: dict) -> dict:
    """搜索机票"""
    args = ["search-flight",
            "--origin", params.get("from_city", ""),
            "--destination", params.get("to_city", ""),
            "--dep-date", params.get("date", ""),
            "--sort-type", "3"]
    return run_flyai(args)


def search_hotel(params: dict) -> dict:
    """搜索酒店"""
    args = ["search-hotel",
            "--dest-name", params.get("destination", ""),
            "--check-in-date", params.get("check_in", ""),
            "--check-out-date", params.get("check_out", ""),
            "--sort", params.get("sort", "price_asc")]
    if params.get("poi_name"):
        args += ["--poi-name", params["poi_name"]]
    if params.get("max_price"):
        args += ["--max-price", str(params["max_price"])]
    return run_flyai(args)


def search_poi(params: dict) -> dict:
    """搜索景点/门票/滑雪相关POI"""
    args = ["search-poi",
            "--city-name", params.get("city", "")]
    if params.get("category"):
        args += ["--category", params["category"]]
    if params.get("keyword"):
        args += ["--keyword", params["keyword"]]
    return run_flyai(args)


def keyword_search(params: dict) -> dict:
    """关键词搜索（飞猪平台雪票/套餐/当地游）"""
    args = ["keyword-search",
            "--keyword", params.get("keyword", "")]
    if params.get("category"):
        args += ["--category", params["category"]]
    if params.get("destination"):
        args += ["--destination", params["destination"]]
    if params.get("start_date"):
        args += ["--start-date", params["start_date"]]
    if params.get("end_date"):
        args += ["--end-date", params["end_date"]]
    return run_flyai(args)


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(__doc__)
        sys.exit(1)

    cmd = sys.argv[1]

    if cmd == "check":
        available = flyai_available()
        print(json.dumps({"available": available}))
    elif cmd in ("search-flight", "search-hotel", "search-poi", "keyword-search"):
        params = json.loads(sys.argv[2]) if len(sys.argv) > 2 else json.load(sys.stdin)
        funcs = {
            "search-flight": search_flight,
            "search-hotel": search_hotel,
            "search-poi": search_poi,
            "keyword-search": keyword_search,
        }
        result = funcs[cmd](params)
        print(json.dumps(result, ensure_ascii=False, indent=2))
    else:
        print(f"未知命令: {cmd}")
        print(__doc__)
        sys.exit(1)


path: tools/strategy_maint.py
content: #!/usr/bin/env python3
"""
search_strategies.json 维护工具

用法:
  python tools/strategy_maint.py check          # 检查数据健康度
  python tools/strategy_maint.py verify         # 验证官方渠道名称（手动）
  python tools/strategy_maint.py report          # 生成维护报告
  python tools/strategy_maint.py add-channel     # 添加官方渠道
  python tools/strategy_maint.py review          # 季度复核流程

安全说明:
  - 仅读写本地 JSON 文件
  - 不执行任何网络请求
  - 不修改 resorts_db.json
"""

import json
import os
import sys
from datetime import datetime, timedelta
from collections import Counter

STRATEGY_FILE = os.path.join(os.path.dirname(__file__), '..', 'data', 'search_strategies.json')
RESORTS_FILE = os.path.join(os.path.dirname(__file__), '..', 'data', 'resorts_db.json')


def load_json(path):
    with open(path, 'r', encoding='utf-8') as f:
        return json.load(f)


def save_json(path, data):
    with open(path, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def check_health():
    """检查数据健康度"""
    strategies = load_json(STRATEGY_FILE)
    resorts = load_json(RESORTS_FILE)

    print('=== Search Strategies 健康度检查 ===\n')

    # 1. region_strategies 覆盖度
    rs = strategies['region_strategies']
    total_resorts = len([k for k in resorts if not k.startswith('_')])

    # 构建 region -> resort 映射
    resort_regions = Counter()
    for name, info in resorts.items():
        if name.startswith('_'):
            continue
        region = info.get('region', 'Unknown')
        resort_regions[region] += 1

    # 区域映射
    region_mapping = {
        '崇礼': ['河北'],
        '东北': ['吉林', '黑龙江', '辽宁'],
        '新疆': ['新疆'],
        '北京': ['北京'],
        '国内其他': ['山东', '河南', '山西', '湖北', '四川', '江苏', '浙江', '安徽', '湖南', '内蒙古', '陕西', '广东', '云南', '贵州', '福建', '重庆', '天津', '江西', '广西', '海南', '青海', '宁夏', '上海', '甘肃'],
        '日本': ['日本', '长野县', '北海道', '岩手县', '新潟县', '群马县', '长野', '青森县', '山形县', '秋田县'],
        '韩国': ['韩国', '江原道·平昌', '江原道·旌善', '江原道', '全罗北道', '京畿道', '江原道·洪川'],
        '欧洲': ['法国', '瑞士', '奥地利', '意大利', '安道尔', '德国·巴伐利亚', '法国·萨瓦', '法国·上萨瓦', '瑞士·格劳宾登州', '瑞士·瓦莱', '奥地利·蒂罗尔', '意大利·特伦蒂诺', '法国·萨瓦省', '奥地利·蒂罗尔州', '法国·伊泽尔', '法国·上阿尔卑斯省', '法国·上萨瓦省', '奥地利·萨尔茨堡州', '芬兰', '西班牙', '瑞士·格劳宾登', '瑞士·上瓦尔登', '奥地利·萨尔茨堡', '法国·上阿尔卑斯', '瑞士·伯尔尼', '瑞士·乌里', '法国·伊泽尔省', '瑞士·上瓦尔登州', '瑞士·施维克州', '奥地利·施蒂利亚州', '意大利·伦巴第', '斯洛文尼亚·戈伦尼斯卡', '斯洛伐克·日利纳州', '捷克·赫拉德茨克拉洛韦州', '罗马尼亚·布拉索夫县', '西班牙·加泰罗尼亚', '意大利·瓦莱达奥斯塔', '法国·杜省', '瑞士·瓦莱州', '瑞士·伯尔尼州', '瑞士·提契诺州', '奥地利·福拉尔贝格州', '意大利·威尼托', '意大利·皮埃蒙特'],
        '北美': ['美国', '加拿大', '美国·科罗拉多', '科罗拉多州', '加拿大·BC', '美国·加州', '加拿大·阿尔伯塔', '加利福尼亚州', '佛蒙特州', '犹他州', '不列颠哥伦比亚省', '魁北克省', '爱达荷州', '艾伯塔省', '美国·佛蒙特', '加拿大·魁北克', '美国·加州/内华达', '美国·犹他', '美国·怀俄明州', '美国·蒙大拿州', '美国·犹他州'],
        '南半球': ['新西兰', '澳大利亚', '阿根廷', '智利', '新西兰·瓦纳卡', '新西兰·皇后镇', '澳大利亚·新南威尔士', '圣地亚哥大区', '瓦尔帕莱索大区', '内格罗河省', '门多萨省']
    }

    covered = 0
    for strategy_name, mapped_regions in region_mapping.items():
        count = sum(resort_regions.get(r, 0) for r in mapped_regions)
        covered += count
        status = rs.get(strategy_name, {}).get('priority', 'unknown')
        print(f'  {strategy_name}: {count} resorts (priority: {status})')

    print(f'\n  总覆盖: {covered}/{total_resorts} ({covered/total_resorts*100:.1f}%)')
    print(f'  未覆盖: {total_resorts - covered} (由 default 策略兜底)')

    # 2. official_channels 复核状态
    oc = strategies['official_channels']
    meta = {k: v for k, v in oc.items() if k.startswith('_')}
    channels = {k: v for k, v in oc.items() if not k.startswith('_')}

    verification_date = meta.get('_verification_status', 'unknown')
    print(f'\n  官方渠道: {len(channels)} 个')
    print(f'  上次复核: {verification_date}')

    # 计算是否超期
    if 'next_review_' in verification_date:
        next_review = verification_date.split('next_review_')[1]
        try:
            review_date = datetime.strptime(next_review, '%Y-%m-%d')
            days_until = (review_date - datetime.now()).days
            if days_until < 0:
                print(f'  状态: 超期 {-days_until} 天，需要复核')
            elif days_until < 30:
                print(f'  状态: {days_until} 天后到期，建议提前复核')
            else:
                print(f'  状态: 正常 ({days_until} 天后复核)')
        except:
            print(f'  状态: 无法解析复核日期')

    # 3. 必填字段检查
    print(f'\n  必填字段检查:')
    required_fields = ['description', 'flyai_params', 'websearch_keywords', 'priority', 'season']
    issues = []
    for region, strategy in rs.items():
        missing = [f for f in required_fields if f not in strategy]
        if missing:
            issues.append(f'{region}: missing {missing}')

    if issues:
        for issue in issues:
            print(f'    FAIL: {issue}')
    else:
        print(f'    PASS: 所有 region_strategies 包含必填字段')

    # 4. 关键词质量
    print(f'\n  关键词质量:')
    empty_keywords = 0
    placeholder_count = 0
    for region, strategy in rs.items():
        for kw_type in ['websearch_keywords', 'fliggy_keywords']:
            kws = strategy.get(kw_type, [])
            for kw in kws:
                if not kw.strip():
                    empty_keywords += 1
                if '{' in kw:
                    placeholder_count += 1

    if empty_keywords > 0:
        print(f'    WARN: {empty_keywords} 个空关键词')
    else:
        print(f'    PASS: 无空关键词')
    print(f'    NOTE: {placeholder_count} 个占位符关键词（正常）')

    print(f'\n=== 检查完成 ===')


def generate_report():
    """生成维护报告"""
    strategies = load_json(STRATEGY_FILE)
    resorts = load_json(RESORTS_FILE)

    report = []
    report.append('# Search Strategies 维护报告')
    report.append(f'生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M")}\n')

    rs = strategies['region_strategies']
    total_resorts = len([k for k in resorts if not k.startswith('_')])

    report.append('## 1. 区域策略覆盖')
    for region, strategy in sorted(rs.items(), key=lambda x: x[1].get('resort_count', 0), reverse=True):
        count = strategy.get('resort_count', 0)
        priority = strategy.get('priority', 'unknown')
        season = strategy.get('season', 'unknown')
        report.append(f'- **{region}**: {count} resorts, priority={priority}, season={season}')

    oc = {k: v for k, v in strategies['official_channels'].items() if not k.startswith('_')}
    report.append(f'\n## 2. 官方渠道 ({len(oc)} 个)')
    for name, info in sorted(oc.items()):
        verified = '✅' if info.get('verified') else '⏳'
        report.append(f'- {verified} {name}: {info.get("note", "")}')

    report.append(f'\n## 3. 维护建议')
    report.append('- region_strategies: 无需定期更新，事件驱动调整')
    report.append('- official_channels: 季度复核微信公众号名称')
    report.append('- fliggy_platform: 每年雪季前（9月）验证一次')

    report_path = os.path.join(os.path.dirname(__file__), '..', 'docs', 'strategies_maintenance_report.md')
    os.makedirs(os.path.dirname(report_path), exist_ok=True)
    with open(report_path, 'w', encoding='utf-8') as f:
        f.write('\n'.join(report))

    print(f'报告已生成: {report_path}')


def add_channel():
    """交互式添加官方渠道"""
    print('添加官方渠道（输入空值取消）:')
    name = input('雪场名称: ').strip()
    if not name:
        return

    wechat_name = input('微信公众号名称: ').strip()
    if not wechat_name:
        print('取消：微信公众号名称不能为空')
        return

    note = input('备注（可选）: ').strip()

    strategies = load_json(STRATEGY_FILE)
    strategies['official_channels'][name] = {
        'type': 'wechat',
        'name': name,
        'value': f'{wechat_name} (WeChat MP)',
        'url': '',
        'verified': False,
        'note': note or f'微信搜索公众号：{wechat_name}'
    }

    save_json(STRATEGY_FILE, strategies)
    print(f'已添加: {name} -> {wechat_name}')


def review():
    """季度复核流程"""
    strategies = load_json(STRATEGY_FILE)
    oc = strategies['official_channels']
    channels = {k: v for k, v in oc.items() if not k.startswith('_')}

    print('=== 季度复核官方渠道 ===\n')
    print('请在微信中搜索以下公众号，确认名称是否有效:\n')

    for i, (name, info) in enumerate(channels.items(), 1):
        expected = info.get('note', '')
        print(f'{i:2d}. {name}')
        print(f'    预期: {expected}')
        confirm = input(f'    有效? (y/n/skip): ').strip().lower()

        if confirm == 'n':
            new_name = input(f'    新名称: ').strip()
            if new_name:
                info['value'] = f'{new_name} (WeChat MP)'
                info['note'] = f'微信搜索公众号：{new_name}'
                info['verified'] = True
                info['last_reviewed'] = datetime.now().strftime('%Y-%m-%d')
                print(f'    已更新: {new_name}')
            else:
                print(f'    跳过')
        elif confirm == 'y':
            info['verified'] = True
            info['last_reviewed'] = datetime.now().strftime('%Y-%m-%d')
            print(f'    已标记为已验证')
        else:
            print(f'    跳过')
        print()

    # 更新复核日期
    next_review = (datetime.now() + timedelta(days=90)).strftime('%Y-%m-%d')
    oc['_verification_status'] = f'reviewed_{datetime.now().strftime("%Y-%m-%d")}_next_review_{next_review}'

    save_json(STRATEGY_FILE, strategies)
    print(f'\n复核完成！下次复核日期: {next_review}')


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print(__doc__)
        sys.exit(1)

    cmd = sys.argv[1]
    cmds = {
        'check': check_health,
        'report': generate_report,
        'add-channel': add_channel,
        'review': review,
    }

    if cmd in cmds:
        cmds[cmd]()
    elif cmd == 'verify':
        print('验证需要手动在微信中搜索公众号名称')
        print('请运行: python tools/strategy_maint.py review')
    else:
        print(f'未知命令: {cmd}')
        print(__doc__)
        sys.exit(1)


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)