Files
rrweb-skill/docs/superpowers/plans/2026-06-12-sgrobot-adapter.md

151 lines
6.7 KiB
Markdown

# SGrobot Adapter Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build a reusable generator that turns one rrweb semantic trace into SGrobot-compatible `PlanTemplate.toml` and runtime `SKILL.toml` artifacts without changing SGrobot core.
**Architecture:** Keep this repository as a Codex skill plus deterministic generator. The generator writes one business-specific plan and one business-specific sgBrowser runtime skill per recording, with the semantic trace baked into the generated page script and saved beside it as evidence.
**Tech Stack:** Node.js ESM, `node:test`, SGrobot `PlanTemplate.toml`, SGrobot runtime `SKILL.toml`, sgBrowser `sgBrowserExcuteJsCodeByDomain`.
---
### Task 1: Generator Contract
**Files:**
- Create: `tests/generate_sgrobot_flow.test.mjs`
- Create: `scripts/generate_sgrobot_flow.mjs`
- Create: `package.json`
- [ ] **Step 1: Write the failing tests**
```js
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { generateSgRobotArtifacts, writeArtifacts } from "../scripts/generate_sgrobot_flow.mjs";
const trace = {
id: "expense-approval",
name: "费用审批",
description: "打开审批页,填写意见并点击同意。",
startUrl: "https://oa.example.test/expense/123",
steps: [
{ type: "assertText", text: "费用审批", label: "确认在审批页" },
{ type: "fill", selector: "textarea[name='comment']", value: "同意", label: "填写审批意见" },
{ type: "click", selector: "button[data-action='approve']", label: "点击同意", risk: "write" }
]
};
test("generates SGrobot plan and runtime skill artifacts", () => {
const result = generateSgRobotArtifacts(trace, { defaultMode: "execute" });
assert.equal(result.summary.planId, "rrweb-expense-approval");
assert.equal(result.summary.skillName, "rrweb-expense-approval-execute");
assert.equal(result.summary.requiresApproval, true);
assert.equal(result.files.get("plan_templates/rrweb-expense-approval/PlanTemplate.toml").includes('skills = ["rrweb-expense-approval-execute"]'), true);
assert.equal(result.files.get(".sgclaw-workspace/skills/rrweb-expense-approval-execute/SKILL.toml").includes('command = "sgBrowserExcuteJsCodeByDomain"'), true);
assert.equal(result.files.get(".sgclaw-workspace/skills/rrweb-expense-approval-execute/SKILL.toml").includes('expected_domain = "oa.example.test"'), true);
assert.equal(result.files.get(".sgclaw-workspace/skills/rrweb-expense-approval-execute/scripts/execute_trace.js").includes('"default_mode": "execute"'), true);
});
test("writes generated artifacts under a SGrobot repository root", async () => {
const root = await mkdtemp(path.join(tmpdir(), "rrweb-sgrobot-"));
try {
const result = generateSgRobotArtifacts(trace);
await writeArtifacts(root, result.files);
const plan = await readFile(path.join(root, "plan_templates/rrweb-expense-approval/PlanTemplate.toml"), "utf8");
const skill = await readFile(path.join(root, ".sgclaw-workspace/skills/rrweb-expense-approval-execute/SKILL.toml"), "utf8");
const evidence = await readFile(path.join(root, ".sgclaw-workspace/skills/rrweb-expense-approval-execute/trace.semantic.json"), "utf8");
assert.match(plan, /skills = \["browser\.open_url"\]/);
assert.match(skill, /script_path = "scripts\/execute_trace.js"/);
assert.equal(JSON.parse(evidence).id, "expense-approval");
} finally {
await rm(root, { recursive: true, force: true });
}
});
```
- [ ] **Step 2: Run test to verify it fails**
Run: `node --test tests/generate_sgrobot_flow.test.mjs`
Expected: FAIL with `Cannot find module '../scripts/generate_sgrobot_flow.mjs'`.
- [ ] **Step 3: Implement the generator**
Create `scripts/generate_sgrobot_flow.mjs` exporting `generateSgRobotArtifacts(trace, options)` and `writeArtifacts(root, files)`. The generator must validate `id`, `name`, `startUrl`, and `steps`, derive `expected_domain` from `startUrl`, emit SGrobot paths, and support `defaultMode` of `dry-run` or `execute`.
- [ ] **Step 4: Add package metadata**
Create `package.json` with:
```json
{
"name": "rrweb-sgrobot-skill",
"version": "0.1.0",
"type": "module",
"private": true,
"scripts": {
"test": "node --test tests/*.test.mjs",
"generate:sgrobot": "node scripts/generate_sgrobot_flow.mjs"
}
}
```
- [ ] **Step 5: Run test to verify it passes**
Run: `npm test`
Expected: PASS with both generator tests green.
### Task 2: Codex Skill Wrapper
**Files:**
- Create: `SKILL.md`
- Create: `references/sgrobot-adapter.md`
- Create: `examples/basic-trace.json`
- [ ] **Step 1: Write the skill instructions**
Create a concise `SKILL.md` that tells Codex to use `scripts/generate_sgrobot_flow.mjs` when adapting rrweb semantic traces for SGrobot. It must state that `.agents/skills/**/SKILL.md` is only an agent helper, while SGrobot runtime artifacts are `PlanTemplate.toml` and `.sgclaw-workspace/skills/**/SKILL.toml`.
- [ ] **Step 2: Add focused SGrobot mapping reference**
Create `references/sgrobot-adapter.md` with the SGrobot-specific mapping rules: one generated plan per recording, one generated runtime skill per recording, `browser.open_url` first, generated sgBrowser execution skill second, optional `json.save_result` third, and step-level approval when execute mode includes mutating actions.
- [ ] **Step 3: Add a realistic example trace**
Create `examples/basic-trace.json` using the same schema covered by the test: `id`, `name`, `description`, `startUrl`, and `steps`.
- [ ] **Step 4: Validate the skill folder**
Run: `python3 /Users/zhaoyilun/.codex/skills/.system/skill-creator/scripts/quick_validate.py /Users/zhaoyilun/Documents/rrweb-skill`
Expected: PASS.
### Task 3: Verification Against SGrobot Shape
**Files:**
- Read-only check: `/Users/zhaoyilun/projects/sgrobot-architecture-design/docs/concepts/skill-and-plan-template.md`
- Read-only check: `/Users/zhaoyilun/projects/sgrobot-architecture-design/docs/how-to/add-skill.md`
- [ ] **Step 1: Generate sample output to a temp directory**
Run: `node scripts/generate_sgrobot_flow.mjs --trace examples/basic-trace.json --out /tmp/rrweb-sgrobot-sample --default-mode dry-run --force`
Expected: the command prints paths for the plan, skill, runtime script, and trace evidence.
- [ ] **Step 2: Inspect generated files**
Run: `find /tmp/rrweb-sgrobot-sample -type f | sort`
Expected: files exist under `plan_templates/rrweb-expense-approval/` and `.sgclaw-workspace/skills/rrweb-expense-approval-execute/`.
- [ ] **Step 3: Re-run tests**
Run: `npm test`
Expected: PASS.