Files
claw/docs/superpowers/specs/2026-04-16-scene-skill-generator-design.md
木炎 ea6be128e7 feat: scene skill generator — complete implementation
Adds a web-based UI for generating scene skill packages:
- Node.js HTTP server (zero npm dependencies) on port 3210
- HTML page with glass-morphism UI, dual-panel layout, settings modal
- LLM-powered scene-id/scene-name auto-extraction from directory contents
- Real-time SSE progress streaming during skill generation
- Spawns sg_scene_generate CLI with configurable parameters
- Windows-compatible startup scripts (serve.sh + serve.cmd)
- Rust integration tests for server files and HTML structure

Architecture:
  Browser (HTML/JS) → Node.js server → LLM API + cargo run → sg_scene_generate

Files:
  frontend/scene-generator/{server.js,config-loader.js,llm-client.js,generator-runner.js,sg_scene_generator.html,serve.sh,serve.cmd}
  tests/{scene_generator_server_test.rs,scene_generator_html_test.rs,scene_generator_llm_test.js}
  docs/superpowers/{plans,specs}/2026-04-16-scene-skill-generator*

🤖 Generated with [Qoder][https://qoder.com]
2026-04-16 22:27:41 +08:00

16 KiB
Raw Blame History

Scene Skill Generator — Design Document

Date: 2026-04-16 Status: Draft — awaiting review Author: Qoder


1. Goal

提供一个可视化界面,让用户选择场景目录后,自动通过大模型提取 scene-id 和 scene-name配置输出路径和 lessons 文件,一键调用 sg_scene_generate 生成完整的 skill 包,并实时查看生成日志。


2. Architecture

┌─────────────────────────────────────────────────────────────────┐
│  sg_scene_generator.html (浏览器)                                │
│  ┌───────────────────┐        ┌───────────────────────────────┐ │
│  │ 左侧:操作面板      │        │ 右侧:实时日志流                  │ │
│  │                   │        │                               │ │
│  │  📂 选择场景目录   │───────│  [状态卡片 + 实时滚动日志]        │ │
│  │                   │        │                               │ │
│  │  自动填充字段:     │        │  分析场景目录...                 │ │
│  │  - scene-id       │        │  调用大模型提取场景信息...        │ │
│  │  - scene-name     │        │  scene-id: tq-lineloss-report   │ │
│  │                   │        │  scene-name: 台区线损报表         │ │
│  │  可编辑字段:       │        │  生成 skill 包...               │ │
│  │  - 输出根路径       │        │  写入 SKILL.toml...            │ │
│  │  - lessons 路径    │        │  写入 browser_script...         │ │
│  │                   │        │  ✅ 生成完成                      │ │
│  │  [⚙ 设置]          │        └───────────────────────────────┘ │
│  │  [🚀 生成 Skill]   │                                          │
│  └───────────────────┘                                          │
└─────────────────────────────────────────────────────────────────┘
         │
         │  1. POST /analyze  (选择目录后自动触发)
         │     → 发送目录路径 + 文件内容
         │  2. SSE /generate (点击生成按钮后触发)
         │     → 推送实时进度
         ▼
┌─────────────────────────────────────────────────────────────────┐
│  server.js (Node.js, 默认端口 3210)                              │
│                                                                  │
│  POST /analyze                                                   │
│    1. 读取 source-dir 下的关键文件                                │
│       - scene.toml (如果存在)                                     │
│       - *.js 脚本文件                                            │
│       - SKILL.md / SKILL.toml (如果存在)                          │
│       - 目录结构树                                                │
│    2. 构造 prompt调用 LLM API                                   │
│       - baseUrl + apiKey + model 来自 sgclaw_config.json          │
│    3. 返回 JSON: { sceneId, sceneName }                          │
│                                                                  │
│  POST /generate                                                  │
│    1. 接收 { sourceDir, sceneId, sceneName, outputRoot, lessons } │
│    2. spawn: cargo run --bin sg_scene_generate \                  │
│         --source-dir <sourceDir> \                               │
│         --scene-id <sceneId> \                                   │
│         --scene-name <sceneName> \                               │
│         --output-root <outputRoot> \                             │
│         --lessons <lessons>                                      │
│    3. 通过 SSE 实时推送 stdout/stderr                             │
│    4. 推送完成/失败事件                                           │
│                                                                  │
│  GET /health                                                     │
│    → { status: "ok", pid: 12345 }                                │
│                                                                  │
│  GET /                                                           │
│    → 服务 sg_scene_generator.html 静态文件                         │
└─────────────────────────────────────────────────────────────────┘
         │
         │  LLM API (OpenAI-compatible format)
         │  POST {baseUrl}/v1/chat/completions
         ▼
┌──────────────────────┐
│  LLM (DeepSeek)       │
│                      │
│  System: 你是一个场景 │
│  信息提取助手...       │
│  User: 以下是场景目录  │
│  内容... 请提取        │
│  scene-id 和          │
│  scene-name           │
└──────────────────────┘

3. File Map

新建文件

文件 说明
frontend/scene-generator/sg_scene_generator.html 主页面,内联 CSS + JS复用 service-console 设计风格
frontend/scene-generator/server.js Node.js 轻量 HTTP 服务器(零外部依赖)
frontend/scene-generator/serve.sh 一键启动脚本Windows 兼容)
frontend/scene-generator/serve.cmd Windows 一键启动脚本
frontend/scene-generator/config-loader.js 读取并解析 sgclaw_config.json
frontend/scene-generator/llm-client.js 封装 LLM API 调用OpenAI-compatible 格式)
frontend/scene-generator/generator-runner.js 封装 sg_scene_generate 子进程调用 + SSE 推送

引用文件(不修改)

文件 用途
src/bin/sg_scene_generate.rs 被 server.js 通过 cargo run 调用
src/generated_scene/generator.rs 理解生成逻辑和输出结构
sgclaw_config.json 读取 LLM 连接配置apiKey, baseUrl, model
docs/superpowers/references/tq-lineloss-lessons-learned.toml 默认 lessons 路径
frontend/service-console/sg_claw_service_console.html UI 风格参考

4. UI Design

4.1 整体布局

复用 service-console 的双栏布局:

  • 外层容器 (.shell):圆角玻璃拟态面板,与 service-console 共享 CSS 变量
  • 顶部 (.hero):标题 "场景 Skill 生成器" + 简短说明
  • 内容区 (.content)grid 双栏,左侧操作面板 + 右侧日志流

4.2 左侧操作面板

场景目录选择区

📂 场景目录
[ 粘贴或输入路径 ____________________________ ] [ 浏览 📁 ]
当前D:\data\ideaSpace\rust\sgClaw\claw-new\examples\generated_scene_platform\scenarios\tq-lineloss-report

使用文本输入框 + "浏览" 按钮。点击 "浏览" 时,前端调用 POST /browse,由 Node.js 弹出系统目录选择对话框(通过 electron 风格的 open-dialog 不可行 — 改为用户在输入框中粘贴/输入路径,服务端通过 fs.stat 校验路径合法性)。

为简化实现,采用更务实的方案:

  • 主输入框:用户粘贴或手动输入场景目录的绝对路径
  • 输入路径后按回车或点击 "分析" 按钮,触发 /analyze 请求
  • 服务端通过 fs.statSync(sourceDir).isDirectory() 校验路径

可选增强:如果 Node.js 安装了 electron,可通过 dialog.showOpenDialog 弹出系统选择框,但这会增加依赖。默认不采用。

自动提取结果(只读展示,可手动修正)

scene-id
tq-lineloss-report

scene-name
台区线损报表

分析中显示 loading 状态,分析失败时可手动输入。

设置按钮

点击弹出模态框,包含以下字段:

字段 默认值 说明
输出根路径 D:/data/ideaSpace/rust/sgClaw/claw-new/examples/generated_scene_platform skill 包输出根目录,实际输出到 <output-root>/skills/<scene-id>/
Lessons 路径 D:/data/ideaSpace/rust/sgClaw/claw-new/docs/superpowers/references/tq-lineloss-lessons-learned.toml lessons TOML 文件路径
LLM 服务地址 来自 sgclaw_config.jsonbaseUrl 可覆盖
LLM 模型 来自 sgclaw_config.jsonmodel 可覆盖
Node 服务端口 3210 server.js 监听端口

生成按钮

[ 🚀 生成 Skill ]  (disabled 直到选择了目录且提取完成)

4.3 右侧日志流

与 service-console 一致的流式日志展示:

  • 空状态:显示提示 "选择场景目录开始生成"
  • status 行:关键阶段标记("开始分析", "提取完成", "开始生成", "生成成功"
  • log 行cargo run 的 stdout 输出
  • error 行stderr 输出或错误信息
  • complete 行:最终结果,包含生成的 skill 包路径

4.4 状态卡片

左侧面板顶部显示当前状态:

[●] 就绪 / 分析中 / 生成中 / 完成 / 错误

颜色编码:

  • 就绪:灰色
  • 分析中:橙色
  • 生成中青色accent
  • 完成:绿色
  • 错误:红色

5. API Design

5.1 POST /analyze

请求体:

{
  "sourceDir": "D:/data/ideaSpace/rust/sgClaw/claw-new/examples/generated_scene_platform/scenarios/tq-lineloss-report"
}

服务端自行读取目录内容:

  • 校验路径是否存在且为目录
  • 读取 scene.toml(如果存在)
  • 读取 *.js 脚本文件
  • 读取 SKILL.md / SKILL.toml(如果存在)
  • 生成目录结构树

响应:

{
  "sceneId": "tq-lineloss-report",
  "sceneName": "台区线损报表"
}

LLM Prompt 设计:

System: 你是一个场景信息提取助手。根据场景目录的内容,提取 scene-id 和 scene-name。

scene-id 规则:
- 使用英文短横线连接,如 tq-lineloss-report
- 全小写,有业务含义

scene-name 规则:
- 使用中文,简短描述性名称
- 如 "台区线损报表"、"知乎热榜导出"

User: 以下是场景目录的内容:

=== scene.toml ===
[scene content here]

=== 脚本文件 ===
[script content here]

=== 目录结构 ===
[file tree here]

请以 JSON 格式返回:{"sceneId": "...", "sceneName": "..."}

5.2 POST /generate (SSE)

请求体:

{
  "sourceDir": "/path/to/scenario/dir",
  "sceneId": "tq-lineloss-report",
  "sceneName": "台区线损报表",
  "outputRoot": "/path/to/output/root",
  "lessons": "/path/to/lessons.toml"
}

SSE 事件流:

event: status
data: {"message": "开始生成 skill 包..."}

event: status
data: {"message": "调用 sg_scene_generate..."}

event: log
data: {"message": "generated scene package: ..."}

event: complete
data: {"success": true, "skillRoot": "/path/to/skills/tq-lineloss-report"}

或

event: error
data: {"message": "生成失败: ..."}

5.3 GET /health

响应:

{
  "status": "ok",
  "pid": 12345,
  "configLoaded": true,
  "configPath": "D:/data/ideaSpace/rust/sgClaw/sgclaw_config.json"
}

6. Server Design (server.js)

6.1 模块结构

server.js              — HTTP 路由入口SSE 连接管理
config-loader.js       — 读取 sgclaw_config.json暴露 LLM 配置 + projectRoot
llm-client.js          — 调用 LLM API返回 JSON 提取结果
generator-runner.js    — spawn 子进程,通过 SSE 推送输出

6.1.1 projectRoot 配置

cargo run --bin sg_scene_generate 需要在项目根目录下执行。projectRoot 的确定优先级:

  1. 环境变量 SGCLAW_PROJECT_ROOT(最高优先级)
  2. sgclaw_config.json 同级目录(常见情况:配置文件在项目根目录)
  3. 启动脚本所在目录

6.2 零依赖原则

仅使用 Node.js 内置模块:

  • http — HTTP 服务器
  • fs — 文件读取
  • path — 路径处理
  • child_process — 子进程调用
  • events — 事件发射

6.3 启动流程

1. 读取 sgclaw_config.json (路径通过环境变量 SGCLAW_CONFIG_PATH 或默认 ../sgclaw_config.json)
2. 验证必需字段: apiKey, baseUrl, model
3. 启动 HTTP 服务器,监听 0.0.0.0:3210
4. 打印启动信息,包含访问地址

6.4 错误处理

场景 处理方式
sgclaw_config.json 不存在 启动失败,提示用户设置环境变量
LLM API 调用失败 返回 502 + 错误信息,前端允许手动输入
cargo run 失败 SSE 推送 error 事件,显示 stderr
source-dir 不存在 返回 400
端口被占用 启动失败,提示更换端口

7. Security Considerations

  1. 仅监听 localhostserver.js 默认绑定 127.0.0.1,不暴露到外部网络
  2. API Key 不暴露给前端LLM API 调用完全在 Node.js 服务端完成,前端不接触 API Key
  3. 路径校验sourceDiroutputRoot 需做基本路径合法性检查,防止路径遍历攻击
  4. 子进程超时cargo run 设置 5 分钟超时,防止挂起

8. Default Configuration

配置项 默认值 来源
LLM apiKey sgclaw_config.json 中的 apiKey 启动时读取
LLM baseUrl sgclaw_config.json 中的 baseUrl 启动时读取
LLM model sgclaw_config.json 中的 model 启动时读取
默认 lessons 路径 docs/superpowers/references/tq-lineloss-lessons-learned.toml 项目约定
默认输出根路径 examples/generated_scene_platform 项目约定
Node 服务端口 3210 硬编码,可配置

9. User Flow

1. 用户运行 bash serve.sh (或 node server.js)
2. 浏览器打开 http://127.0.0.1:3210
3. 页面加载,显示 "就绪" 状态
4. 用户在 "场景目录" 输入框中粘贴或输入绝对路径
5. 用户点击 "分析" 按钮(或输入框回车),触发 /analyze 请求
6. server.js 读取目录内容,调用 LLM 提取 scene-id/name
7. 页面自动填充 scene-id 和 scene-name 字段
8. 用户确认/修改字段,点击 "设置" 检查输出路径和 lessons
9. 用户点击 "生成 Skill"
10. server.js 通过 SSE 推送实时进度
11. 页面右侧日志流展示生成过程
12. 生成完成,显示 skill 包路径
13. 用户可前往输出目录查看生成的 skill

10. Windows Compatibility

由于目标平台是 Windows

  • serve.sh 同时提供 serve.cmd 替代方案
  • 路径分隔符统一使用 /Node.js path 模块自动处理)
  • cargo run 命令在 Windows 上同样可用
  • 路径输入框支持 Windows 格式路径(如 D:\data\ideaSpace\...
  • 服务端自动将 \ 转换为 / 以兼容 Rust CLI 参数

11. Future Extensions (Not in Scope)

  • 批量生成:一次选择多个场景目录
  • 生成后自动注册到 scene.toml manifest
  • 生成后自动运行 skill 测试
  • 历史记录:保存之前的生成记录
  • 生成参数模板:保存常用的输出路径/lessons 组合