@optima-chat/dev-skills 0.16.3 → 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env python3
2
+ """比对 vendored 文件与上游是否漂移。上游 repo 不在本机则跳过(不破坏自包含)。"""
3
+ import os, subprocess
4
+
5
+ # adapted=True 的文件在上游基础上有本地改动/追加,diff 必然 ≠0 → ⚠️ 是「去看上游有无新变更」而非缺陷;
6
+ # adapted=False 是逐字 vendored,应与上游一致,⚠️ 才是真漂移。
7
+ VENDORED = [
8
+ {"file": "chat_driver.py", "repo": "store-skills", "adapted": False,
9
+ "upstream": "~/optima-store-skills/.claude/skills/operating-yzsgo-chat/chat_driver.py"},
10
+ {"file": "pull_wire.py", "repo": "store-skills", "adapted": True, # 追加了 emit_conversation_index/locate_conversation
11
+ "upstream": "~/optima-store-skills/.claude/skills/pulling-yzsgo-session-wire/pull_wire.py"},
12
+ {"file": "prep_conversation.py", "repo": "gateway", "adapted": True,
13
+ "upstream": "~/optima-gateway/.claude/skills/conversation-iq/prep_session.py"},
14
+ {"file": "judge_workflow.js", "repo": "gateway", "adapted": True,
15
+ "upstream": "~/optima-gateway/.claude/skills/conversation-iq/workflow.js"},
16
+ ]
17
+
18
+ def plan_drift_checks(present: dict) -> list:
19
+ out = []
20
+ for v in VENDORED:
21
+ out.append({"file": v["file"], "upstream": v["upstream"],
22
+ "adapted": v.get("adapted", False),
23
+ "checkable": bool(present.get(v["repo"], False))})
24
+ return out
25
+
26
+ def _present() -> dict:
27
+ return {"store-skills": os.path.isdir(os.path.expanduser("~/optima-store-skills")),
28
+ "gateway": os.path.isdir(os.path.expanduser("~/optima-gateway"))}
29
+
30
+ if __name__ == "__main__":
31
+ here = os.path.dirname(os.path.abspath(__file__))
32
+ for c in plan_drift_checks(_present()):
33
+ if not c["checkable"]:
34
+ print(f"⏭ {c['file']}:上游不在本机,跳过"); continue
35
+ up = os.path.expanduser(c["upstream"])
36
+ r = subprocess.run(["diff", "-q", os.path.join(here, c["file"]), up], capture_output=True, text=True)
37
+ if r.returncode == 0:
38
+ print(f"✅ {c['file']} 与上游一致")
39
+ elif c.get("adapted"):
40
+ print(f"⚠️(改编·预期) {c['file']}:与上游有差异属正常,去看上游有无值得同步的新变更")
41
+ else:
42
+ print(f"⚠️ 漂移 {c['file']} vs {c['upstream']}(逐字 vendored,应一致 → 去同步)")
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: "yzsgo-e2e"
3
+ description: "当用户请求端到端测试鸭嘴兽、e2e 测 yzsgo 对话、用浏览器真机测鸭嘴兽整个流程、驱动对话再拉 wire 核对前后端、测网关/agent 端到端有没有问题时,使用此技能。playwright attach 调试端口 Chrome 驱 www.yzsgo.com 对话 → 拉 gateway wire → conversation-iq 语义管线判定 → confirmed 自动提 issue。"
4
+ allowed-tools: ["Bash", "Read", "Write", "Agent", "Workflow"]
5
+ ---
6
+
7
+ # yzsgo-e2e — 鸭嘴兽通用端到端测试
8
+
9
+ 用浏览器真机驱动鸭嘴兽完成一段对话,同时拿浏览器侧结果 + 拉 gateway wire,判前后端一致性与网关缺陷,confirmed 自动提 issue。
10
+
11
+ ## 何时用
12
+ - 「端到端测一下鸭嘴兽」「e2e 测这段对话」「用浏览器真机测整个流程有没有问题」
13
+
14
+ ## 用户说人话 → 我怎么映射(用户不敲 CLI)
15
+ - 用户给的对话内容 → 逐轮 `--message`(按序)。
16
+ - 用户提到「遇到它问 X 就答 Y / 测某个反问」→ `--answer "X=Y"`。
17
+ - 用户说「重点看有没有 Z」→ `--expect "Z"`。
18
+
19
+ ## 环境自举(第一步,自包含——别外链别的仓库)
20
+ 脚本都在本 skill 目录(记为 `$S`,就是本 SKILL.md 所在目录)。托管 venv = `~/.cache/yzsgo-e2e/venv`(记 `$VENV`),不碰系统 python。
21
+
22
+ 1. **体检**:`python3 $S/preflight.py <env>`。缺项分两类:
23
+ - 🅰️ **auto(能自动装)**:`venv+playwright`、`sshpass`。
24
+ - ✋ **manual(凭据/登录,装不了)**:`chrome-9222`(登了测试账号的调试 Chrome)、`buildbox-pw`、`test-user-id`。
25
+ 2. **逐个补缺**(🔴 全绿才往下;不绿就停下、别硬跑半残):
26
+ - 每个 🅰️ 缺项:**先问用户「要我装 `<name>` 吗?」,用户同意了**再跑 `python3 $S/bootstrap.py setup`(装 venv+playwright)或 `python3 $S/bootstrap.py install-sshpass`。别不问就装。
27
+ - 每个 ✋ 缺项:引导用户——`chrome-9222`:`python3 $S/bootstrap.py launch-chrome` 起窗口、让用户**手动登测试账号**(登一次长期免登);`buildbox-pw`:让用户把口令放 `~/.buildbox_pw`(内部拉 wire 用,向团队要);`test-user-id`:让用户登录 Optima(run_e2e 自动从 `~/.optima/token.json` 读 userId)。
28
+ - 补完 `python3 $S/preflight.py <env>` 复检,直到全 ✅ 才进四段。
29
+
30
+ ## 四段流程
31
+ 1. **preflight + 自举**:见上「环境自举」,**全绿**才继续。
32
+ 2. **驱动 + 拉 wire + 备料**:`$VENV/bin/python $S/run_e2e.py --env <env> --message ... [--answer k=v] [--expect ...] --out <dir>` → 出 `prepped.md` + `meta.json`。🔑 用 **venv 的 python**(playwright 在那儿);`--user` 不给则自动读 `~/.optima/token.json`。
33
+ 3. **判定**:`gh issue list --repo Optima-Chat/optima-gateway --state open --json number,title` 拉已知 issue 文本,`Workflow({scriptPath:"<skill>/judge_workflow.js", args:{base:"<dir>", sids:["prepped"], knownIssues:"<文本>"}})`。
34
+ 4. **报告 + 提 issue**:
35
+ 判定跑完后,先把 judge_workflow 输出 + meta.json 组装成 render_report 的入参(两者字段形状不同,别直接传):
36
+ - `confirmed` = 各 sid 的 `confirmed` 里取 `finding` → `{what, evidence}`,跨 sid 合并
37
+ - `needs_review` = 各 sid 的 `needsReview` 里取 `finding` → `{what, evidence}`
38
+ - `env` / `started_ts` / `first_message` 从 `<out>/meta.json` 读
39
+ - `blocked` = 环境类阻断原因(浏览器 state=service_error / 积分不足 / 桌面没连…),否则 None
40
+ - `coverage` = 本次覆盖边界(单次对话 / skeptic 读源码 / 去重挡已知 等,如实写)
41
+ 再调 `run_e2e.render_report(result)` 出报告。**confirmed 直接 `gh issue create --repo Optima-Chat/optima-gateway --label needs-triage`**(证据=前端输出+wire transcript+repro 对话),提错可改可删;判定为纯前端缺陷(前端渲染问题、非 agent/网关逻辑)→ 提到对应前端 repo(而非 gateway);拿不准就默认 gateway。**needs_review 不自动提**,报告单列待人工;**环境类标 blocked 不提**。
42
+
43
+ ## 诚实边界(照搬 conversation-iq)
44
+ - 「0 confirmed」≠「没问题」;needs_review 绝不静默毙。
45
+ - 对抗验证必须让 skeptic 读**真实 runtime 源码**,默认判假。
46
+ - 报告固定含「覆盖边界」+「判断修正」两节。
47
+
48
+ ## 前后端对照(本 skill 独有)
49
+ 判定要核对**前端渲染的** vs **wire 里 agent 真实产出的**:前端丢内容/半截/报错但 wire 成功(或反之)= 缺陷。
50
+
51
+ ## vendor 同步纪律
52
+ `chat_driver.py`/`pull_wire.py` 上游权威 = optima-store-skills;`prep_conversation.py`/`judge_workflow.js` 改编自 optima-gateway conversation-iq。见 `SYNC.md`。驱动异常先怀疑前端 DOM 漂移 → 去上游同步。可跑 `python3 verify_drift.py` 比对。只有 `chat_driver.py` 是逐字 vendored、应与上游一致;`pull_wire.py`(在上游基础上追加了 emit_conversation_index/locate_conversation)、`prep_conversation.py`、`judge_workflow.js` 都是改编,`verify_drift.py` 对它们标「⚠️(改编·预期)」是提醒去看上游有无新变更,非「必须一致」。
53
+
54
+ ## 两环境
55
+ `--env cn-prod`(已打通)/ `cn-stage`(wire 取法待核实,脚本会告警)。
56
+
57
+ ## 真机 smoke(改完先跑这个验管道通)
58
+ ```bash
59
+ python3 $S/preflight.py cn-prod # 先体检,缺项按「环境自举」补齐到全绿
60
+ $VENV/bin/python $S/run_e2e.py --env cn-prod --message "你好" --out /tmp/yzsgo-smoke
61
+ # 期望:/tmp/yzsgo-smoke/prepped.md 含「前端所见」节 + wire transcript;meta.json 的 located 命中本次对话。
62
+ # 只验四段接线通,不追判定质量。(--user 自动读 token.json)
63
+ ```
@@ -0,0 +1,10 @@
1
+ # vendored 文件上游台账
2
+
3
+ | 本文件 | 上游 repo · 路径 | commit | 同步日期 |
4
+ |---|---|---|---|
5
+ | chat_driver.py | optima-store-skills · .claude/skills/operating-yzsgo-chat/chat_driver.py | 7a1685a | 2026-08-31 |
6
+ | pull_wire.py | optima-store-skills · .claude/skills/pulling-yzsgo-session-wire/pull_wire.py | 7a1685a | 2026-08-31 |
7
+ | prep_conversation.py | optima-gateway · .claude/skills/conversation-iq/prep_session.py(改编:+浏览器证据合并) | b75f575c | 2026-08-31 |
8
+ | judge_workflow.js | optima-gateway · .claude/skills/conversation-iq/workflow.js(改编:+前后端一致性维度) | b75f575c | 2026-08-31 |
9
+
10
+ > 注:judge_workflow.js 内联的 decideOutcome 是 judge_outcome.js(有 node 单测)的副本,改逻辑需同步两处。
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env python3
2
+ """yzsgo-e2e 自举:把「能装的」依赖装好。**征得用户同意由 SKILL.md/Claude 负责问**,
3
+ 本脚本只在被调用时执行对应动作。托管 venv 放 ~/.cache/yzsgo-e2e/venv——不碰系统 python
4
+ (macOS/发行版的系统 python 常是外部管理,pip install 会被拒),最稳、可复现、不污染。"""
5
+ import os, subprocess, sys
6
+
7
+ VENV = os.path.expanduser("~/.cache/yzsgo-e2e/venv")
8
+
9
+
10
+ def venv_python(base: str = VENV) -> str:
11
+ return os.path.join(base, "bin", "python")
12
+
13
+
14
+ def plan_actions(missing_names: list, base: str = VENV) -> list:
15
+ """纯函数:把缺项名映射成要执行的命令序列。供单测 + 让 Claude/用户预知会跑什么。
16
+ 返回 [(动作名, [[argv...], ...]), ...]。只覆盖 auto 类缺项(manual 类装不了,不在此)。"""
17
+ plan = []
18
+ for n in missing_names:
19
+ if n == "venv+playwright":
20
+ plan.append(("setup", [
21
+ [sys.executable, "-m", "venv", base],
22
+ [venv_python(base), "-m", "pip", "install", "-q", "playwright"],
23
+ [venv_python(base), "-m", "playwright", "install", "chromium"],
24
+ ]))
25
+ elif n == "sshpass":
26
+ plan.append(("install-sshpass", [["brew", "install", "hudochenkov/sshpass/sshpass"]]))
27
+ elif n == "chrome-9222":
28
+ plan.append(("launch-chrome", [[
29
+ "open", "-na", "Google Chrome", "--args",
30
+ "--remote-debugging-port=9222", "--user-data-dir=/tmp/yzsgo-chrome",
31
+ "https://www.yzsgo.com"]]))
32
+ return plan
33
+
34
+
35
+ def _run(cmds: list) -> bool:
36
+ for c in cmds:
37
+ print("+", " ".join(c))
38
+ if subprocess.run(c).returncode != 0:
39
+ print(f"[bootstrap] 命令失败:{' '.join(c)}", file=sys.stderr)
40
+ return False
41
+ return True
42
+
43
+
44
+ def _do(name: str) -> bool:
45
+ plan = plan_actions([name])
46
+ if not plan:
47
+ print(f"[bootstrap] 无法自动处理 {name}(可能是 manual 类,需人工准备)", file=sys.stderr)
48
+ return False
49
+ return _run([c for _, cmds in plan for c in cmds])
50
+
51
+
52
+ # 动作名 → 触发它的缺项名
53
+ _CMD_TO_MISSING = {"setup": "venv+playwright", "install-sshpass": "sshpass", "launch-chrome": "chrome-9222"}
54
+
55
+ if __name__ == "__main__":
56
+ cmd = sys.argv[1] if len(sys.argv) > 1 else "setup"
57
+ miss = _CMD_TO_MISSING.get(cmd)
58
+ if not miss:
59
+ print(f"未知命令 {cmd};可用:{' / '.join(_CMD_TO_MISSING)}", file=sys.stderr)
60
+ sys.exit(2)
61
+ ok = _do(miss)
62
+ if cmd == "launch-chrome" and ok:
63
+ print("已起调试端口 Chrome;请在弹出的窗口里手动登录测试账号(登一次即长期免登)。")
64
+ sys.exit(0 if ok else 1)