feat: 根目录文档、脚本、gitignore

This commit is contained in:
2026-10-08 16:15:33 +08:00
commit e98660ce4e
284 changed files with 26838 additions and 0 deletions
@@ -0,0 +1,229 @@
#!/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()