product-planning(同步 26 改 65 新)
- 目录约定:docs/pm/<项目>/ ⇒ <工作区>/项目/<产品slug>/ 为产品根,下分 产品规划/ 与 产品原型/{designs,pages}
- ④段骨架六节 ⇒ 七节(新增「原型地址」;后两节改「页面导航」「原型状态取值」)
- ③段新增真机组件库;结案「源站只有暗色主题」,tokens.css(亮色)标为不可用于生产
- ③段改版规则反转为「一个产品只用一套原型、只留当前态」;②段新增 产品规划模板.md(表头唯一定义处)
- scripts:产品根定位重写(含 .registry/current-project 指针),新增 check_terms.py 与 selftest_product_root.py
session-mechanism(同步 3 改 2 新)
- references/06-技能优化规程.md 新增 §5「要求落在生成时看得见的面上」,总表 16 ⇒ 17 条;SKILL.md 同步
- scripts/collabctl.py 取回 _find_board() 候选定位(旧版写死 scripts/board.py,而看板已搬进 boards/会话看板/ ⇒ 旧版本就是坏的)
element-picker(新装)
- 按用户口径作「独立功能加入 product-planning」,非独立全局技能
- 修掉它自身三处路径漂移(技能根写法 ⇒ 同目录;README 两处旧落点;剪贴板示例文案与代码对齐)
工具归拢到技能级 assets/
- diagram-design / design-capture / element-picker / video-capture 从各段 assets/ 移到技能包 assets/
- 新增红线:本包有两处 assets/(技能级工具箱 vs 段内资产),引工具一律写「技能级 assets/<工具名>/」
- 路径口径由两类改三类(技能级工具箱 / 本段自带资产 / 同根技能)
不入库(磁盘保留)
- design-system-tiaoyue 整个目录(用户 2026-10-16 令):git rm -r --cached + .gitignore,理由=14 MB 且可 CDP 重采;
已在 ③段 SKILL.md 注明「取仓后这一层是空的属正常,用自带套需另取或重采」
- element-picker 的运行期存档 marks/(服务自己会建目录)
100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""产品根定位自检:造临时夹具验 `_common.find_product_root()` 的三态行为。
|
||
|
||
为什么要有它:目录口径换成「工作区根 / 项目 / 产品根{产品规划, 产品原型{designs, pages}}」之后,
|
||
**认错产品根**会让产物落到别的产品目录下(事后极难拆干净)。
|
||
本脚本只造临时夹具、**绝不碰任何真实工作区**,跑完自动清理。
|
||
|
||
用法:
|
||
python scripts/selftest_product_root.py
|
||
退出码:0 = 全过;1 = 有用例没过。
|
||
"""
|
||
import importlib.util
|
||
import io
|
||
import os
|
||
import shutil
|
||
import sys
|
||
import tempfile
|
||
|
||
try:
|
||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||
except Exception:
|
||
pass
|
||
|
||
SK = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
COMMON = os.path.join(SK, "references", "stage-delivery", "scripts", "_common.py")
|
||
|
||
|
||
def load_common():
|
||
spec = importlib.util.spec_from_file_location("_sm_common", COMMON)
|
||
mod = importlib.util.module_from_spec(spec)
|
||
sys.modules["_sm_common"] = mod
|
||
spec.loader.exec_module(mod)
|
||
return mod
|
||
|
||
|
||
def mkproot(p):
|
||
"""按新结构造一个产品根:产品规划/ + 产品原型/{designs,pages}/"""
|
||
for d in ("产品规划",
|
||
os.path.join("产品原型", "designs"),
|
||
os.path.join("产品原型", "pages")):
|
||
os.makedirs(os.path.join(p, d), exist_ok=True)
|
||
|
||
|
||
def main():
|
||
C = load_common()
|
||
fix = tempfile.mkdtemp(prefix="proot-selftest-")
|
||
out = []
|
||
|
||
def build_single():
|
||
mkproot(os.path.join(fix, "ws1", "项目", "only"))
|
||
|
||
def build_multi(pointer=""):
|
||
for nm in ("a", "b"):
|
||
mkproot(os.path.join(fix, "ws2", "项目", nm))
|
||
reg = os.path.join(fix, "ws2", ".registry")
|
||
os.makedirs(reg, exist_ok=True)
|
||
if pointer:
|
||
io.open(os.path.join(reg, "current-project"), "w", encoding="utf-8").write(pointer)
|
||
|
||
cases = [
|
||
("单产品·给工作区根", build_single, os.path.join(fix, "ws1"),
|
||
os.path.join(fix, "ws1", "项目", "only")),
|
||
("单产品·给产品根本身", build_single, os.path.join(fix, "ws1", "项目", "only"),
|
||
os.path.join(fix, "ws1", "项目", "only")),
|
||
("单产品·从子目录向上认", build_single,
|
||
os.path.join(fix, "ws1", "项目", "only", "产品原型", "pages"),
|
||
os.path.join(fix, "ws1", "项目", "only")),
|
||
("多产品·无指针·不许猜", build_multi, os.path.join(fix, "ws2"), ""),
|
||
("多产品·有指针·认指针", lambda: build_multi("b"), os.path.join(fix, "ws2"),
|
||
os.path.join(fix, "ws2", "项目", "b")),
|
||
]
|
||
try:
|
||
nfail = 0
|
||
for name, build, arg, expect in cases:
|
||
shutil.rmtree(fix, ignore_errors=True)
|
||
os.makedirs(fix, exist_ok=True)
|
||
build()
|
||
got = C.find_product_root(arg)
|
||
ok = os.path.normcase(os.path.abspath(got)) == os.path.normcase(os.path.abspath(expect))
|
||
out.append("%s %-26s 期望=%s | 实得=%s" % (
|
||
"[过]" if ok else "[FAIL]", name,
|
||
os.path.relpath(expect, fix) if expect else "(空)",
|
||
os.path.relpath(got, fix) if got else "(空)"))
|
||
if not ok:
|
||
nfail += 1
|
||
finally:
|
||
shutil.rmtree(fix, ignore_errors=True)
|
||
|
||
for line in out:
|
||
print(line)
|
||
print()
|
||
print("小计:%d / %d 过" % (len(cases) - nfail, len(cases)))
|
||
print("✅ 产品根定位全过。" if not nfail else "⛔ 有用例没过 —— 先修定位再跑流水线。")
|
||
return 0 if not nfail else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|