Files

230 lines
6.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
pmassist-v3 session initializer
初始化 pmassist-v3 会话工作目录与基础文件
用法:
python3 skills/pmassist-v3/scripts/init_session.py \
--path <workdir> \
--doc prd|frd|dar \
--alias <简称> \
--title <标题> \
--desc <原始需求> \
[--enable-prototype] \
[--enable-acceptance]
"""
import argparse
from pathlib import Path
from datetime import datetime
DOC_MAP = {
"prd": "prd.md",
"frd": "frd.md",
"dar": "dar.md",
}
def now_ts():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def read_template(doc_type: str, skill_dir: Path) -> str:
ref_name = DOC_MAP[doc_type]
ref_path = skill_dir / "references" / ref_name
if ref_path.exists():
return ref_path.read_text(encoding="utf-8")
return f"# {doc_type.upper()}\n\n> 模板缺失,请手动补充。\n"
def read_acceptance_template(skill_dir: Path) -> str:
ref_path = skill_dir / "references" / "acceptance_template.md"
if ref_path.exists():
return ref_path.read_text(encoding="utf-8")
return "# 验收标准(Acceptance Criteria)\n\n> 按 Given/When/Then 格式填写。\n"
def write_file(path: Path, content: str, force: bool = False) -> bool:
if path.exists() and not force:
return False
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
return True
def main():
parser = argparse.ArgumentParser(
description="Initialize pmassist-v3 session workspace"
)
parser.add_argument("--path", required=True, help="Work directory path")
parser.add_argument(
"--doc", required=True, choices=["prd", "frd", "dar"], help="Document type"
)
parser.add_argument("--alias", default="", help="Project alias (short name)")
parser.add_argument("--title", default="", help="Document title")
parser.add_argument("--desc", default="", help="Raw requirement description")
parser.add_argument("--force", action="store_true", help="Overwrite existing files")
parser.add_argument(
"--enable-prototype",
action="store_true",
help="Enable prototype design phase",
)
parser.add_argument(
"--enable-acceptance",
action="store_true",
help="Pre-create acceptance.md for Given/When/Then AC output",
)
args = parser.parse_args()
workdir = Path(args.path).resolve()
workdir.mkdir(parents=True, exist_ok=True)
# Skill 根目录(脚本位于 scripts/ 下)
skill_dir = Path(__file__).resolve().parent.parent
# ── 基础目录 ──────────────────────────────────────
base_dirs = ["materials", "rounds", "questions", "outputs"]
# ── 原型目录(可选)──────────────────────────────
proto_dirs = [
"materials/prototypes",
"materials/prototypes/reference",
"materials/prototypes/analysis",
"prototypes",
"prototypes/screenshots",
"prototypes/webapp",
]
dirs_to_create = base_dirs + (proto_dirs if args.enable_prototype else [])
for d in dirs_to_create:
(workdir / d).mkdir(parents=True, exist_ok=True)
ts = now_ts()
alias = args.alias or ""
title = args.title or ""
raw_desc = args.desc or ""
# ── desc.md ──────────────────────────────────────
desc_md = f"""# 需求描述
## 元信息
- 创建时间: {ts}
- 最后更新: {ts}
- 文档类型: {args.doc.upper()}
- 项目简称: {alias}
- 标题: {title}
## 原始输入
{raw_desc if raw_desc else '[待补充原始需求]'}
## WWH 分析
### What - 做什么
[待补充]
### Why - 为什么
[待补充]
### How - 怎么做
[待补充]
"""
# ── session.yaml ─────────────────────────────────
proto_section = ""
if args.enable_prototype:
proto_section = """
prototype:
enabled: true
status: "proto_pending"
proto_round: 0
tech_stack: []
outputs: []
unresolved_proto_questions: []
"""
session_yaml = f"""project_alias: "{alias}"
doc_type: "{args.doc}"
title: "{title}"
created_at: "{ts}"
updated_at: "{ts}"
round: 0
status: "init"
# 功能需求统计(v3 新增)
fr_count: 0
ac_count: 0
ac_coverage: "0/0"
# 未解决问题
unresolved_questions: []
# 跳过标记
skip_flags:
prototype: {'true' if not args.enable_prototype else 'false'}
ac_batch: false
diff_list: false
last_output: ""
materials: []{proto_section}
"""
# ── summary.md ───────────────────────────────────
summary_md = f"""# 会话摘要
- {ts} 初始化 pmassist-v3 会话
- 文档类型:{args.doc.upper()}
- 项目:{alias or '(未设置)'}
"""
# ── decision_log.md ──────────────────────────────
decision_log_md = """# 决策记录
| 时间 | 变更编号 | 事项 | 决策内容 | 影响 FR | 依据 |
|---|---|---|---|---|---|
"""
# ── materials_index.md ───────────────────────────
materials_index_md = """# 资料索引
| ID | 标题 | 类型 | 来源/路径 | 摘要 | 日期 |
|---|---|---|---|---|---|
"""
# ── 输出文档模板 ──────────────────────────────────
output_template = read_template(args.doc, skill_dir)
# ── acceptance.md(可选,PRD/FRD 推荐)──────────
acceptance_template = read_acceptance_template(skill_dir)
# ── 写文件 ────────────────────────────────────────
wrote = []
def wf(rel_path: str, content: str):
if write_file(workdir / rel_path, content, args.force):
wrote.append(rel_path)
wf("desc.md", desc_md)
wf("session.yaml", session_yaml)
wf("summary.md", summary_md)
wf("decision_log.md", decision_log_md)
wf("materials_index.md", materials_index_md)
wf(f"outputs/{DOC_MAP[args.doc]}", output_template)
# 验收标准(按需或 PRD/FRD 默认启用)
if args.enable_acceptance or args.doc in ("prd", "frd"):
wf("outputs/acceptance.md", acceptance_template)
if wrote:
print("[OK] pmassist-v3 会话初始化完成,创建/更新文件:")
for f in wrote:
print(f" - {f}")
print(f"\n工作目录:{workdir}")
print(f"下一步:加载 pmassist-v3 skill,开始 Round 1 PDCA。")
else:
print("[SKIP] 无文件变更。使用 --force 覆盖已有文件。")
if __name__ == "__main__":
main()