init-project
当用户明确要求"初始化项目"、"创建项目指令文件"或"生成 AGENTS.md"时使用。完全自动化:自动检测操作系统默认语言,分析项目目录结构(支持 Python/Web/Rust/Go/Java/数据科学/文档项目等),推断项目类型和用途,一键生成规范的项目指令文档。生成结果包括:AGENTS.md(跨平台通用项目指令,Single Source of Truth)、CLAUDE.md(Claude Code 特定适配,通过 @./AGENTS.md 引用)、README.md(项目介绍与使用方法)、CHANGELOG.md(项目变更记录)、.giti
#claude-code
Install
npx skills add https://github.com/huangwb8/skills/tree/main/skills/alpha/init-project
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install huangwb8-skills@llmmart
git clone https://github.com/huangwb8/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole huangwb8/skills collection as a plugin from our marketplace. Git is the plain clone.
README
Init Project
这个 skill 用来为当前项目初始化标准化的 AI 协作文档和基础仓库文件,适合新项目起步或已有项目补齐指令体系;它只应该在当前项目目录内工作,不应越界修改其它目录。
用法
最推荐用法
请使用 init-project skill 为本项目进行初始化。
输入:当前项目根目录
输出:`AGENTS.md`、`CLAUDE.md`、`README.md`、`CHANGELOG.md`、`.gitignore`、`docs/`、`docs/plans/`、`skills/`
进阶用法
请使用 init-project skill 为本项目进行初始化。
输入:当前项目根目录
输出:标准化项目指令与说明文档
另外,还有下列参数约束:
- 尽量保留已有内容
- 默认语言自动检测
- 不修改当前目录之外的文件
能做什么
- 为项目生成
AGENTS.md、CLAUDE.md、README.md、CHANGELOG.md、.gitignore,并初始化docs/与docs/plans/。 - 把
AGENTS.md作为跨平台通用指令的单一真相来源。 - 让
CLAUDE.md成为面向 Claude Code 的轻量适配层。 - 自动分析项目结构、项目类型和默认语言。
- 兼容 Windows GBK 等非 UTF-8 控制台;状态符号无法显示时会安全转义,不会把真实业务失败误报为成功。
- 默认启用 BAC 贡献记录:检查 Python 环境和
bac包,必要时安装,并初始化docs/contribution.bac。 - 不适合拿来扫描父目录、批量改多个项目,或无边界地覆盖已有文件。
使用示例
示例 1:初始化一个新项目
请使用 init-project skill 为本项目进行初始化。
输入:当前项目根目录
输出:完整的项目指令文件与说明文档
示例 2:为已有项目补齐协作文档
请使用 init-project skill 初始化这个已有仓库。
输入:当前项目根目录
输出:`AGENTS.md`、`CLAUDE.md`、`README.md`、`CHANGELOG.md`、`.gitignore`、`docs/`、`docs/plans/`
另外,还有下列参数约束:
- 尽量保留已有 README 的有效信息
- 不破坏现有项目结构
示例 3:只补某一类文档
请使用 init-project skill 为本项目补齐说明文档。
输入:当前项目根目录
输出:README 或 CHANGELOG
另外,还有下列参数约束:
- 只更新 README
输出
AGENTS.md:跨平台通用项目指令,应该被长期维护。CLAUDE.md:Claude Code 适配层,核心内容应与AGENTS.md保持一致。README.md:项目介绍、快速开始和目录说明。CHANGELOG.md:项目变更记录。.gitignore:默认的安全与项目类型忽略规则。docs/:项目文档根目录。docs/plans/:计划文档固定目录;其余docs/文档在代码变化时也应及时同步更新。skills/:project-specific Agent Skills 目录。目录内 Skill 遵循huangwb8/skills的AGENTS.md与docs/templates规范;通用 Skill 不应复制到这里。docs/contribution.bac:默认 BAC 贡献托管文件;用户可通过--bac-file指定其它项目内路径。
配置
- 配置文件:
init-project/config.yaml - 关键配置节:
language_mappingbac_contributionagents_required_sectionsclaude_required_sectionsreadme_required_sectionschangelog_required_sections
- 这个 skill 的默认定位是“完整初始化”,不是只生成一份孤立文档。
备选用法(脚本/硬编码)
如果你想直接在命令行下执行项目初始化,脚本入口最方便。
自动分析当前目录并生成文件
python3 init-project/scripts/generate.py --auto
自动分析并覆盖已有文件
python3 init-project/scripts/generate.py --auto --overwrite
只生成部分文档
python3 init-project/scripts/generate.py --auto --only-readme
python3 init-project/scripts/generate.py --auto --only-changelog
跳过部分输出
python3 init-project/scripts/generate.py \
--auto \
--skip-readme \
--skip-changelog \
--skip-gitignore
BAC 贡献记录
# 默认开启:检查/安装 bac,并初始化 docs/contribution.bac
python3 init-project/scripts/generate.py --auto
# 指定项目内的其它 BAC 文件
python3 init-project/scripts/generate.py --auto --bac-file docs/audit/contribution.bac
# 随时显式关闭 BAC 初始化步骤
python3 init-project/scripts/generate.py --auto --disable-bac
关闭后,生成的 AGENTS.md 会明确 BAC 当前未启用,不再保留“默认且强制”的启用态指令。
BAC 基于 https://github.com/huangwb8/bensz-auto-contribution,用于客观记录人类与 AI 的协作过程和证据,不替代最终署名、责任或合规判断。
常见问题
Q:AGENTS.md 和 CLAUDE.md 到底谁是主文件?
A:AGENTS.md 是单一真相来源;CLAUDE.md 是平台适配层。维护时应优先保证 AGENTS.md 的口径正确。
Q:它会不会改到当前项目目录之外?
A:不应该。这个 skill 的边界就是“当前目录内生成或更新项目文件”。
Q:既然是自动化,是不是可以放心覆盖任何已有文件?
A:不能这么理解。自动化不等于无脑覆盖。是否覆盖应由你显式决定,例如使用 --overwrite。
Q:为什么 .gitignore 也算初始化结果的一部分?
A:因为它直接关系到项目安全和仓库整洁度,尤其能防止敏感文件、系统文件和缓存文件被误提交。
Skill manifest
Init Project
目标
当用户明确要求初始化项目、创建项目指令文件、生成 AGENTS.md,或为已有项目补齐 AI 协作规范时使用。本 Skill 分析项目结构,并生成或更新适用于当前项目的标准化协作文档与基础目录。
流程
输入
输入为目标项目根目录及用户选择的初始化模式;可选输入包括项目名称/描述、工作流、输出开关、--overwrite、--bac-file 和 --disable-bac。输出路径必须位于当前项目目录内,现有治理文件和用户自定义章节应先识别再合并。
执行步骤
目标与边界
为当前项目生成标准 AI 协作文档,让 Claude Code / OpenAI Codex CLI 等工具理解项目目标、工程原则、变更记录规则与协作边界。
只允许在当前工作目录及其子目录内创建或修改文件。禁止写入父目录、其它项目、系统目录或用户级配置。脚本会在写入前校验输出路径,失败时立即停止。
核心约束
AGENTS.md是唯一需要长期手动维护的通用指令源;CLAUDE.md只做 Claude Code 适配,并通过@./AGENTS.md自动引用。- 生成模板统一放在
init-project/templates/:AGENTS.md.template、CLAUDE.md.template、README.md.template、CHANGELOG.md.template、gitignore.yaml。 - 配置统一放在
init-project/config.yaml,版本号以skill_info.version为准;当前 BAC 配置在bac_contribution。 - 完整初始化必须补齐
docs/、docs/plans/与skills/;skills/只托管项目专属 Agent Skills。 skills/中的 Agent Skill 必须遵循huangwb8/skills仓库的AGENTS.md,并配合该仓库的docs/templates使用;不得把通用 Skill 或无关项目代码放入其中。- 代码变化导致
docs/中非plans/文档过时时,生成的项目指令必须要求同步更新。 - 影响项目行为、结构、工作流、工程原则、指令文件或关键配置的变更,必须写入
CHANGELOG.md的[Unreleased]。
BAC 贡献记录
默认基于 bensz-auto-contribution / bac 记录人类、AI 与工具贡献证据:
- 默认仓库:
https://github.com/huangwb8/bensz-auto-contribution - 默认安装源:
git+https://github.com/huangwb8/bensz-auto-contribution.git - 默认文件:
docs/contribution.bac - Python 要求:
config.yaml:bac_contribution.min_python_version,当前为3.10 - 默认开启;用户可随时通过
--disable-bac显式关闭。关闭时生成的文档也必须说明当前已关闭且可重新启用。 - 用户通过
--bac-file指定项目内其它路径时,以用户指定为准;禁止把.bac文件写到项目目录外。
BAC 是过程记录与辅助审计材料,不替代最终署名、责任或合规判断;不得记录敏感密钥、完整私有提示词或无关个人隐私。
推荐执行
在目标项目根目录运行:
python3 init-project/scripts/generate.py --auto
常用参数:
# 覆盖/强制更新已有文件
python3 init-project/scripts/generate.py --auto --overwrite
# 指定 BAC 文件,必须位于项目目录内
python3 init-project/scripts/generate.py --auto --bac-file docs/audit/contribution.bac
# 显式关闭默认 BAC 初始化
python3 init-project/scripts/generate.py --auto --disable-bac
# 只生成单类文档 / 跳过可选输出
python3 init-project/scripts/generate.py --auto --only-readme
python3 init-project/scripts/generate.py --auto --only-changelog
python3 init-project/scripts/generate.py --auto --skip-readme --skip-gitignore
手动模式只在用户明确给出项目信息时使用:
python3 init-project/scripts/generate.py \
--project-name "my-project" \
--project-description "数据科学项目" \
--workflow "数据获取 → 分析 → 可视化"
自动模式流程
--auto 会依次完成:
- 验证输出目录必须位于当前工作目录内。
- 分析项目:从 README 提取名称/描述,按标志文件识别项目类型,生成最多 2 层目录树。
- 检测默认语言,失败时回退到简体中文。
- 完整初始化时创建
docs/与docs/plans/。 - 按配置决定是否启用 BAC:检查 Python 与
bac包,必要时安装,初始化或验证.bac文件。 - 生成或智能合并
AGENTS.md、CLAUDE.md。 - 按条件生成
README.md、CHANGELOG.md、.gitignore。 - 输出生成文件、目录与项目分析摘要。
项目类型识别标志:Python(pyproject.toml、requirements.txt 等)、Web(package.json 等)、Rust(Cargo.toml)、Go(go.mod)、Java(pom.xml/Gradle)、数据科学(*.ipynb、*.R、environment.yml)、文档(docs/、mkdocs.yml、docusaurus.config.js)。
智能合并策略
当 AGENTS.md 或 CLAUDE.md 已存在时,默认智能合并而非直接覆盖:保留用户自定义的 ## 项目目标、## 核心工作流、## 变更边界 及非标准章节;更新工程原则、默认语言、平台适配、AGENTS.md 必需章节与 CLAUDE.md 的 @./AGENTS.md 引用。AGENTS.md 中历史遗留的 ## 目录结构 会被丢弃,避免回填为自定义章节;合并不符合预期时提示用户用 --overwrite。
.gitignore 策略
从 templates/gitignore.yaml 读取规则;缺少 PyYAML 或配置损坏时使用默认规则兜底。安全优先,默认忽略系统文件、IDE 配置、日志、临时文件、环境变量、密钥、凭证目录和常见构建/缓存产物。已有 .gitignore 在覆盖模式下会保留用户自定义规则。
输出
输出文件
AGENTS.md:跨平台通用项目指令,Single Source of Truth;必生成,智能合并。CLAUDE.md:Claude Code 适配层,核心为@./AGENTS.md;必生成,智能合并。README.md、CHANGELOG.md、.gitignore:按需生成;--overwrite可覆盖/合并。项目变更必须维护CHANGELOG.md。docs/、docs/plans/、skills/:完整初始化时自动补齐;计划文档固定放在./docs/plans/,项目专属 Agent Skills 固定放在./skills/。docs/contribution.bac:默认 BAC 账本;--bac-file可改,--disable-bac可关。
输出管理
BenszAPI 任务工作区
校验
交付前检查
-
AGENTS.md包含必需章节:项目目标、核心工作流、工程原则、默认语言、联网与搜索、贡献记录、Codex CLI 特定说明、变更记录与版本、有机更新原则。 -
CLAUDE.md正确通过@./AGENTS.md引用通用指令。 -
docs/、docs/plans/、skills/已存在或无需本模式创建。 - BAC 已初始化/验证,或用户已显式使用
--disable-bac。 -
.gitignore已生成/合并,且包含敏感文件忽略规则。 -
CHANGELOG.md已创建或变更已记录。 - 未写入当前项目目录之外的文件。
失败与恢复
错误处理
- Windows GBK 等非 UTF-8 控制台不会因装饰性 Unicode 状态符号中止;脚本保留宿主编码,仅转义无法编码的字符,业务异常与退出码仍按原逻辑传播。
- 输出目录越界、目标目录不存在或不是目录:停止。
docs/docs/plans/skills已存在但不是目录:停止。- BAC 安装、导入、初始化或验证失败:停止,并提示可用
--disable-bac显式关闭。 - 语言检测失败:回退到简体中文。
- 项目类型无法识别:使用通用项目模板。
PyYAML缺失:脚本继续运行,配置与.gitignore使用默认值。
约束
公共硬约束
本块由 docs/templates/skill-common-constraints.md 统一维护;每个 SKILL.md 的 ## 约束 必须逐字同步本块,不得在副本中改写公共规则。
- 任务需要落盘时,使用唯一的
./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/根目录;共享材料放入shared/,Skill 专属材料放入该 Skill 的input/、output/、log/。 - 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
- 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
- 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
- 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
- Skill 版本唯一记录在自身
config.yaml:skill_info.version;公开 API、协议、目录或配置变更同步文档与CHANGELOG.md。 bensz-collect-bugs是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入~/.bensz-skills/bugs/,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。
Files (skills)
-
scripts
-
generate.py 65 KB
#!/usr/bin/env python3 """ Project Init Generator - 生成脚本 用于生成 AI 项目指令文件: - AGENTS.md(跨平台通用项目指令 - Single Source of Truth) - CLAUDE.md(Claude Code 特定适配 - 通过 @./AGENTS.md 引用) - README.md(项目介绍与使用方法 - 可选) - CHANGELOG.md(项目变更记录 - 强制性) 并在完整初始化时补齐标准项目目录: - docs/ - docs/plans/ - skills/ 支持语言检测、模板变量替换、自定义配置和自动项目分析。 注意:版本号以 config.yaml:skill_info.version 为准 """ import os import sys import platform import subprocess import re import importlib.util from pathlib import Path from datetime import datetime from typing import Dict, List, Tuple, Optional class _UnicodeSafeTextStream: """Retry only Unicode encoding failures; propagate every other write error.""" def __init__(self, stream): self._stream = stream def write(self, text): try: return self._stream.write(text) except UnicodeEncodeError: encoding = getattr(self._stream, "encoding", None) or "ascii" escaped = text.encode(encoding, errors="backslashreplace").decode(encoding) return self._stream.write(escaped) def writelines(self, lines): for line in lines: self.write(line) def __getattr__(self, name): return getattr(self._stream, name) def _configure_console_streams() -> None: """Keep the host encoding while preventing decorative Unicode from aborting the CLI.""" for stream_name in ("stdout", "stderr"): stream = getattr(sys, stream_name, None) if stream is None or isinstance(stream, _UnicodeSafeTextStream): continue reconfigure = getattr(stream, "reconfigure", None) if callable(reconfigure): try: reconfigure(errors="backslashreplace") continue except (AttributeError, TypeError, ValueError): pass setattr(sys, stream_name, _UnicodeSafeTextStream(stream)) _configure_console_streams() try: import yaml except ImportError: yaml = None class ProjectAnalyzer: """项目结构分析器""" # 项目类型识别规则 PROJECT_PATTERNS = { "python": { "indicators": ["pyproject.toml", "requirements.txt", "setup.py", "setup.cfg", "__init__.py"], "default_dirs": ["src/", "tests/", "docs/", "notebooks/", "scripts/"], "name": "Python 项目" }, "web": { "indicators": ["package.json", "yarn.lock", "pnpm-lock.yaml", "webpack.config.js"], "default_dirs": ["src/", "public/", "tests/", "docs/", "config/"], "name": "Web 项目" }, "rust": { "indicators": ["Cargo.toml", "Cargo.lock"], "default_dirs": ["src/", "tests/", "benches/", "examples/"], "name": "Rust 项目" }, "go": { "indicators": ["go.mod", "go.sum"], "default_dirs": ["cmd/", "pkg/", "internal/", "api/"], "name": "Go 项目" }, "java": { "indicators": ["pom.xml", "build.gradle", "build.gradle.kts"], "default_dirs": ["src/main/", "src/test/", "docs/"], "name": "Java 项目" }, "data-science": { "indicators": ["*.ipynb", "*.R", "requirements.txt", "environment.yml"], "default_dirs": ["data/", "notebooks/", "src/", "models/", "reports/"], "name": "数据科学项目" }, "docs": { "indicators": ["docs/", "_docs/", "mkdocs.yml", "docusaurus.config.js"], "default_dirs": ["docs/", "assets/", "static/"], "name": "文档项目" }, } @classmethod def analyze_project(cls, root_dir: Path) -> Dict: """ 分析项目目录结构,推断项目类型和用途 Args: root_dir: 项目根目录 Returns: 包含项目信息的字典 """ result = { "name": None, "type": "通用", "description": None, "directory_tree": None, "detected_dirs": [], } # 1. 尝试从 README 获取项目名称和描述 readme_files = ["README.md", "README.txt", "README.rst", "readme.md"] for readme_name in readme_files: readme_path = root_dir / readme_name if readme_path.exists(): name, desc = cls._parse_readme(readme_path) if name: result["name"] = name if desc: result["description"] = desc break # 2. 从目录名推断项目名称 if not result["name"]: result["name"] = cls._sanitize_name(root_dir.name) # 3. 检测项目类型 project_type, type_info = cls._detect_project_type(root_dir) result["type"] = project_type result["type_info"] = type_info # 4. 生成目录树 result["directory_tree"] = cls._generate_tree(root_dir, max_depth=2) return result @classmethod def _parse_readme(cls, readme_path: Path) -> Tuple[Optional[str], Optional[str]]: """ 解析 README 文件,提取项目名称和描述 Returns: (项目名称, 项目描述) """ try: with open(readme_path, 'r', encoding='utf-8') as f: content = f.read() # 提取标题(# 标题) title_match = re.search(r'^#\s+(.+)$', content, re.MULTILINE) name = title_match.group(1).strip() if title_match else None # 提取第一段作为描述 paragraphs = re.split(r'\n\n+', content) desc = None for para in paragraphs: # 跳过标题 if para.startswith('#'): continue # 获取第一个非空段落 clean_para = para.strip() if clean_para and len(clean_para) > 10: desc = clean_para[:200] # 限制长度 break return name, desc except Exception: return None, None @classmethod def _detect_project_type(cls, root_dir: Path) -> Tuple[str, Dict]: """ 检测项目类型 Returns: (类型键名, 类型信息字典) """ all_files = [] all_dirs = [] # 收集所有文件和目录 for item in root_dir.iterdir(): if item.is_file() and not item.name.startswith('.'): all_files.append(item.name) elif item.is_dir() and not item.name.startswith('.'): all_dirs.append(item.name) # 检查每种项目类型 for type_key, type_info in cls.PROJECT_PATTERNS.items(): for indicator in type_info["indicators"]: # 检查文件(支持通配符) if '*' in indicator: pattern = indicator.replace('*', '.*') if any(re.match(pattern, f) for f in all_files): return type_key, type_info # 检查精确文件名 elif indicator in all_files: return type_key, type_info # 检查目录 elif indicator.endswith('/') and indicator[:-1] in all_dirs: return type_key, type_info # 默认返回通用类型 return "generic", { "name": "通用项目", "default_dirs": ["src/", "docs/", "tests/"] } @classmethod def _generate_tree(cls, root_dir: Path, max_depth: int = 2) -> str: """ 生成目录树字符串 Args: root_dir: 根目录 max_depth: 最大深度 Returns: 目录树字符串 """ lines = [] ignore = {'.git', '.DS_Store', '__pycache__', 'node_modules', '.venv', 'venv', '.env', 'dist', 'build'} def _add_tree(path: Path, prefix: str, depth: int): if depth > max_depth: return try: items = sorted(path.iterdir(), key=lambda x: (not x.is_dir(), x.name)) except PermissionError: return # 过滤忽略项 items = [i for i in items if i.name not in ignore and not i.name.startswith('.')] for i, item in enumerate(items): is_last = i == len(items) - 1 connector = "└── " if is_last else "├── " lines.append(f"{prefix}{connector}{item.name}") if item.is_dir() and depth < max_depth: extension = " " if is_last else "│ " _add_tree(item, prefix + extension, depth + 1) lines.append(root_dir.name + "/") _add_tree(root_dir, "", 0) return "\n".join(lines) @classmethod def _sanitize_name(cls, name: str) -> str: """清理项目名称""" # 移除特殊字符,替换空格和连字符 clean = re.sub(r'[^\w\s-]', '', name) clean = re.sub(r'[-\s]+', '-', clean) return clean.strip("-") class ProjectInitGenerator: """项目初始化文档生成器""" DEFAULT_BAC_CONFIG = { "enabled_by_default": True, "default_bac_file": "docs/contribution.bac", "install_spec": "git+https://github.com/huangwb8/bensz-auto-contribution.git", "min_python_version": "3.10", "project_url": "https://github.com/huangwb8/bensz-auto-contribution", } def __init__(self, config_path: str = None): """ 初始化生成器 Args: config_path: 配置文件路径(默认使用项目内 config.yaml) """ # 获取脚本所在目录 script_dir = Path(__file__).resolve().parents[1] self.config_path = config_path or script_dir / "config.yaml" self.template_dir = script_dir / "templates" # 加载配置(支持优雅降级) self.config = self._load_config() def _load_config(self) -> dict: """ 加载配置文件,支持优雅降级 Returns: 配置字典 """ # 默认配置(当配置文件不存在或损坏时使用) default_config = { 'language_mapping': {'default': '简体中文'}, 'language_detection_commands': { 'darwin': ['locale | grep LANG'], 'linux': ['echo $LANG'], 'windows': ['echo $LANG'] }, } try: if not self.config_path.exists(): print(f"⚠️ 配置文件 {self.config_path} 不存在,使用默认配置") return default_config if yaml is None: print("⚠️ 未安装 PyYAML,使用默认配置") return default_config with open(self.config_path, 'r', encoding='utf-8') as f: config = yaml.safe_load(f) or {} # 合并默认配置(确保关键字段存在) for key, value in default_config.items(): if key not in config: config[key] = value return config except getattr(yaml, "YAMLError", Exception) as e: print(f"⚠️ 配置文件格式错误: {e},使用默认配置") return default_config except Exception as e: print(f"⚠️ 加载配置失败: {e},使用默认配置") return default_config @staticmethod def validate_output_dir(output_dir: Path) -> Tuple[bool, Optional[str]]: """ 验证输出目录是否安全 安全边界: - 只允许在当前工作目录(或其子目录)内操作 - 禁止修改父目录或其它项目目录 - 禁止修改系统敏感目录 Args: output_dir: 输出目录路径 Returns: (是否安全, 错误信息) """ # 解析绝对路径 resolved = output_dir.resolve() current_dir = Path.cwd().resolve() # 1. 检查是否在当前工作目录内(最重要的安全检查) try: # 如果 resolved 是 current_dir 的子目录或就是 current_dir 本身,则安全 resolved.relative_to(current_dir) except ValueError: # 如果抛出 ValueError,说明 resolved 不在 current_dir 内 return False, ( f"🚫 安全警告:禁止在当前工作目录之外创建文件\n" f" 当前工作目录: {current_dir}\n" f" 尝试访问目录: {resolved}\n" f" 本技能仅允许在当前项目目录内操作,以防止意外修改其它项目或系统文件" ) # 2. 检查是否为系统敏感目录(额外的安全层) sensitive_dirs = { "/", "/etc", "/root", "/home", "/usr", "/bin", "/sbin", "/var", "/sys", "/proc", "/dev", "/lib", "/lib64", "/opt" } resolved_str = str(resolved) for sensitive in sensitive_dirs: if resolved_str == sensitive: return False, f"🚫 安全警告:禁止在系统目录 '{sensitive}' 中创建文件" # 3. 检查目录是否存在 if not output_dir.exists(): return False, f"错误: 目录 {output_dir} 不存在" # 4. 检查是否为有效目录 if not output_dir.is_dir(): return False, f"错误: {output_dir} 不是有效目录" return True, None def detect_language(self) -> str: """ 检测操作系统默认语言 Returns: 语言描述(如:简体中文、English) """ system = platform.system().lower() lang_code = None # 根据系统选择检测命令 commands = self.config.get('language_detection_commands', {}).get(system, []) if not commands: commands = ["echo $LANG"] for cmd in commands: try: result = subprocess.run( cmd, shell=True, capture_output=True, text=True, timeout=5 ) if result.returncode == 0 and result.stdout.strip(): # 提取语言代码 output = result.stdout.strip() if "=" in output: lang_code = output.split("=")[1].split(".")[0] else: lang_code = output.split()[0].split(".")[0] break except (subprocess.TimeoutExpired, FileNotFoundError, Exception): continue # 映射到对话语言 mapping = self.config.get('language_mapping', {}) return mapping.get(lang_code, mapping.get('default', '简体中文')) def load_template(self, template_name: str) -> str: """ 加载模板文件 Args: template_name: 模板文件名(如 AGENTS.md.template) Returns: 模板内容 """ template_path = self.template_dir / template_name with open(template_path, 'r', encoding='utf-8') as f: return f.read() def replace_placeholders(self, template: str, variables: dict) -> str: """ 替换模板中的占位符 Args: template: 模板内容 variables: 变量字典 Returns: 替换后的内容 """ result = template for key, value in variables.items(): placeholder = "{" + key + "}" result = result.replace(placeholder, value or f"[待填写: {key}]") # 检查是否有未替换的占位符(排除代码块中的占位符) # 使用简单的启发式方法:检查非代码块区域的占位符 remaining = re.findall(r'\{([^}\s]+)\}', result) # 过滤掉常见的代码模式(如 {key}、{value} 等在代码示例中) code_patterns = {'key', 'value', 'year', 'month', 'day', 'hour', 'minute', 'version', '时间戳'} real_remaining = [p for p in remaining if p not in code_patterns and not p.startswith('项目')] if real_remaining: print(f"⚠️ 以下占位符可能未被替换: {set(real_remaining)}") return result def generate_agents_md(self, variables: dict) -> str: """ 生成 AGENTS.md 内容 Args: variables: 模板变量字典 Returns: AGENTS.md 内容 """ template = self.load_template("AGENTS.md.template") return self.replace_placeholders(template, variables) def generate_claude_md(self, variables: dict) -> str: """ 生成 CLAUDE.md 内容 Args: variables: 模板变量字典 Returns: CLAUDE.md 内容 """ template = self.load_template("CLAUDE.md.template") return self.replace_placeholders(template, variables) def generate_readme_md(self, variables: dict) -> str: """ 生成 README.md 内容 Args: variables: 模板变量字典 Returns: README.md 内容 """ template = self.load_template("README.md.template") return self.replace_placeholders(template, variables) def generate_changelog_md(self, variables: dict) -> str: """ 生成 CHANGELOG.md 内容 Args: variables: 模板变量字典 Returns: CHANGELOG.md 内容 """ template = self.load_template("CHANGELOG.md.template") return self.replace_placeholders(template, variables) def ensure_project_structure(self, output_dir: Path) -> List[Path]: """ 确保项目具备标准 docs 与 project-specific skills 目录结构。 会创建: - docs/ - docs/plans/ - skills/ 如果目录已存在,则静默跳过。 """ docs_dir = output_dir / "docs" plans_dir = docs_dir / "plans" skills_dir = output_dir / "skills" created_dirs = [] for directory in [docs_dir, plans_dir, skills_dir]: if directory.exists(): if not directory.is_dir(): raise ValueError(f"{directory} 已存在但不是目录,无法初始化标准项目结构") continue directory.mkdir(parents=True, exist_ok=True) created_dirs.append(directory) return created_dirs def ensure_docs_structure(self, output_dir: Path) -> List[Path]: """向后兼容的别名;同时初始化标准项目目录。""" return self.ensure_project_structure(output_dir) def get_bac_config(self) -> dict: """读取 BAC 贡献记录配置。""" config = dict(self.DEFAULT_BAC_CONFIG) config.update(self.config.get("bac_contribution", {}) or {}) return config @staticmethod def _parse_version(version: str) -> Tuple[int, ...]: parts = [] for item in version.split("."): try: parts.append(int(item)) except ValueError: break return tuple(parts) or (0,) @staticmethod def _is_bac_importable() -> bool: return importlib.util.find_spec("bac") is not None def ensure_bac_dependency(self) -> bool: """确保当前 Python 环境可调用 bac 包。""" bac_config = self.get_bac_config() min_version = self._parse_version(str(bac_config.get("min_python_version", "3.10"))) if sys.version_info[: len(min_version)] < min_version: print( "❌ BAC 贡献记录需要 Python " f"{bac_config.get('min_python_version', '3.10')}+;当前为 " f"{platform.python_version()}。如需跳过,请使用 --disable-bac。" ) return False if self._is_bac_importable(): print("✅ 已检测到 bac 包") return True install_spec = str(bac_config.get("install_spec", self.DEFAULT_BAC_CONFIG["install_spec"])) print("📦 未检测到 bac 包,正在安装强制依赖:") print(f" {sys.executable} -m pip install {install_spec}") try: result = subprocess.run( [sys.executable, "-m", "pip", "install", install_spec], text=True, timeout=300, ) except (subprocess.TimeoutExpired, FileNotFoundError) as e: print(f"❌ bac 包安装失败:{e}") print(" 如项目决定暂不启用贡献记录,可使用 --disable-bac 显式关闭。") return False if result.returncode != 0: print("❌ bac 包安装失败") print(" 如项目决定暂不启用贡献记录,可使用 --disable-bac 显式关闭。") return False importlib.invalidate_caches() if not self._is_bac_importable(): print("❌ bac 包安装后仍不可导入") return False print("✅ bac 包已安装") return True @staticmethod def resolve_bac_file(output_dir: Path, bac_file: str) -> Optional[Path]: """解析并验证 BAC 文件路径,防止写出项目目录。""" candidate = Path(bac_file) if not candidate.is_absolute(): candidate = output_dir / candidate resolved = candidate.resolve() try: resolved.relative_to(output_dir.resolve()) except ValueError: print("🚫 安全警告:BAC 贡献记录文件必须位于目标项目目录内") print(f" 目标项目目录: {output_dir.resolve()}") print(f" 尝试写入位置: {resolved}") return None return resolved def setup_bac_contribution(self, output_dir: Path, bac_file: str) -> Tuple[bool, Optional[Path], bool]: """ 初始化或验证 BAC 贡献记录文件。 Returns: (是否成功, BAC 文件路径, 是否新建) """ bac_path = self.resolve_bac_file(output_dir, bac_file) if bac_path is None: return False, None, False if not self.ensure_bac_dependency(): return False, bac_path, False relative_bac_file = str(bac_path.relative_to(output_dir.resolve())) bac_path.parent.mkdir(parents=True, exist_ok=True) created = not bac_path.exists() if not created: print(f"ℹ️ 已存在 BAC 贡献记录文件:{relative_bac_file}") command = [ sys.executable, "-m", "bac", "--root", str(output_dir), "--bac-file", relative_bac_file, "verify", "--json", ] else: print(f"🧾 正在初始化 BAC 贡献记录文件:{relative_bac_file}") command = [ sys.executable, "-m", "bac", "--root", str(output_dir), "--bac-file", relative_bac_file, "init", "--json", ] result = subprocess.run(command, text=True) if result.returncode != 0: print("❌ BAC 贡献记录初始化/验证失败") print(" 如项目决定暂不启用贡献记录,可使用 --disable-bac 显式关闭。") return False, bac_path, False print("✅ BAC 贡献记录已启用") print(" 可随时通过 --disable-bac 显式关闭 init-project 的 BAC 初始化步骤。") return True, bac_path, created def _load_gitignore_config(self) -> dict: """ 加载 .gitignore 配置模板 从 templates/gitignore.yaml 读取配置,支持优雅降级 Returns: gitignore 配置字典(包含 common 和 by_type) """ gitignore_config_path = self.template_dir / "gitignore.yaml" # 默认配置(当配置文件不存在或损坏时使用) default_config = { 'common': [ '.DS_Store', '.idea/', '.vscode/', '*.log', '*.tmp', '.env', '.env.local', '*.pem', '*.key', 'secrets/', '.secrets/', '/tests/', '/plans/', '/reviews/', '/suggestions/', '/tmp/run_*/', '.auto-test-code-run.json', '.awesome-code/', '.bensz-api/', '/.bensz-api/', '.bensz-skills/', '.bensz-skills-backup/', '.check-review-alignment/', '.compact-bensz-skills/', '.complete_example/', '.download-fulltext-pdf/', '.draw-plot/', '.dudu-optimize-prompt/', '.explain-figures/', '.explain-results/', '.find-best-skill/', '.git-pr-review/', '.install-bensz-skills/', '.latex-cache/', '.make-research-plan/', '.make_latex_model/', '.md-to-word/', '.mirror/', '.nsfc-budget/', '.nsfc-code/', '.nsfc-length-aligner/', '.nsfc-qc/', '*.nsfc-qc/', '.nsfc-ref-alignment/', '.nsfc-reviewers/', '.nsfc-roadmap/', '.nsfc-schematic/', '.paper-explain-figures/', '.paper-know-journal/', '.paper-select-journal/', '.paper-write-sci/', '.parallel-vibe/', '.parallel_vibe/', '.research-idea/', '.systematic-literature-review/', '.write-paper-sci/', '.write-paper/' ], 'by_type': {} } try: if not gitignore_config_path.exists(): print(f"⚠️ gitignore 配置文件 {gitignore_config_path} 不存在,使用默认配置") return default_config if yaml is None: print("⚠️ 未安装 PyYAML,.gitignore 使用默认配置") return default_config with open(gitignore_config_path, 'r', encoding='utf-8') as f: config = yaml.safe_load(f) or {} # 合并默认配置 for key, value in default_config.items(): if key not in config: config[key] = value return config except getattr(yaml, "YAMLError", Exception) as e: print(f"⚠️ gitignore 配置文件格式错误: {e},使用默认配置") return default_config except Exception as e: print(f"⚠️ 加载 gitignore 配置失败: {e},使用默认配置") return default_config def generate_gitignore(self, project_type: str) -> str: """ 生成 .gitignore 内容 根据项目类型生成合适的 .gitignore 文件,包括: 1. 共性设置:所有项目通用的忽略规则 2. 个性化设置:根据项目类型添加特定规则 Args: project_type: 项目类型键名(如 python、web、rust 等) Returns: .gitignore 内容 """ # 从 templates/gitignore.yaml 加载配置 gitignore_config = self._load_gitignore_config() lines = ["# .gitignore - 自动生成", ""] lines.append("# ========================================注意========================================") lines.append("# 此文件由 init-project 自动生成,包含共性设置和项目特定规则。") lines.append("# 如需添加自定义规则,请在文件末尾的「自定义规则」部分添加。") lines.append("# ===================================================================================") lines.append("") # 1. 添加共性忽略规则 lines.append("# === 共性设置(所有项目通用)===") lines.append("") common_rules = gitignore_config.get('common', []) for rule in common_rules: lines.append(rule) lines.append("") # 2. 添加项目类型特定的忽略规则 type_mapping = { "python": "python", "web": "web", "rust": "rust", "go": "go", "java": "java", "data-science": "data-science", "docs": "docs", "generic": "python", # 通用项目默认使用 python 规则作为基础 } config_type = type_mapping.get(project_type, "python") type_rules = gitignore_config.get('by_type', {}).get(config_type, []) if type_rules: type_names = { "python": "Python", "web": "Web / Node.js", "rust": "Rust", "go": "Go", "java": "Java", "data-science": "数据科学", "docs": "文档项目", } lines.append(f"# === {type_names.get(config_type, '项目特定')} 设置 ===") lines.append("") for rule in type_rules: lines.append(rule) lines.append("") # 3. 添加自定义规则区域 lines.append("# === 自定义规则(在下方添加项目特定的忽略规则)===") lines.append("") lines.append("# 示例:") lines.append("# local-config.yml") lines.append("# *.backup") lines.append("") return "\n".join(lines) def merge_gitignore(self, existing_path: Path, new_content: str) -> str: """ 智能合并现有 .gitignore 和新内容 策略: 1. 保留现有文件中的自定义规则(非自动生成的部分) 2. 更新共性设置和项目类型特定规则 Args: existing_path: 现有 .gitignore 文件路径 new_content: 新生成的 .gitignore 内容 Returns: 合并后的内容 """ try: with open(existing_path, 'r', encoding='utf-8') as f: existing_content = f.read() except Exception: return new_content # 检查是否是自动生成的文件 if "# .gitignore - 自动生成" not in existing_content: # 非自动生成的文件,保留原内容并在末尾添加提示 if "# === 自定义规则(由 init-project 保留)===" not in existing_content: return existing_content + "\n\n# === 自定义规则(由 init-project 保留)===\n# 以上内容为用户自定义,以下为新生成的规则\n\n" + new_content return existing_content # 提取现有自定义规则 custom_marker = "# === 自定义规则" if custom_marker in existing_content: # 找到自定义规则部分 parts = existing_content.split(custom_marker) if len(parts) > 1: custom_content = parts[1] # 提取非空的自定义规则行 custom_lines = [] in_custom_section = False for line in custom_content.split('\n'): if line.strip() and not line.strip().startswith('# 示例'): in_custom_section = True if in_custom_section and line.strip(): custom_lines.append(line) # 如果有自定义规则,追加到新内容 if custom_lines: # 移除新内容末尾的示例部分 new_lines = new_content.split('\n') result_lines = [] in_example = False for line in new_lines: if "# 示例:" in line: in_example = True if not in_example: result_lines.append(line) if in_example and not line.strip(): in_example = False # 添加自定义规则 result_lines.append("# === 自定义规则(用户添加)===") result_lines.append("") result_lines.extend(custom_lines) return '\n'.join(result_lines) return new_content def append_changelog_entry(self, changelog_path: Path, entry: str) -> bool: """ 向 CHANGELOG.md 追加新条目 Args: changelog_path: CHANGELOG.md 文件路径 entry: 要追加的条目内容 Returns: 是否成功 """ try: with open(changelog_path, 'r', encoding='utf-8') as f: content = f.read() # 在 [Unreleased] 部分后面追加 if "## [Unreleased]" in content: parts = content.split("## [Unreleased]") new_content = parts[0] + "## [Unreleased]\n\n" + entry + "\n" + parts[1] else: # 如果没有 Unreleased 部分,在文件末尾追加 new_content = content + "\n" + entry with open(changelog_path, 'w', encoding='utf-8') as f: f.write(new_content) return True except Exception as e: print(f"⚠️ 追加 CHANGELOG 条目失败: {e}") return False def write_file(self, path: Path, content: str, overwrite: bool = False, merge: bool = False) -> bool: """ 写入文件 Args: path: 文件路径 content: 文件内容 overwrite: 是否覆盖已存在的文件 merge: 是否智能合并已存在的文件(仅用于 CLAUDE.md 和 AGENTS.md) Returns: 是否成功写入 注意: 智能合并使用正则表达式解析 Markdown 章节,可能存在边缘情况处理不当。 如果合并结果不符合预期,建议使用 --overwrite 参数完全覆盖。 """ if path.exists() and not overwrite: if merge: # 智能合并模式:保留用户自定义内容,更新标准模板结构 print(f"⚠️ 正在智能合并 {path.name}(保留自定义内容,更新标准部分)") print(f" 提示:如果合并结果不符合预期,请使用 --overwrite 参数完全覆盖") content = self.merge_existing_file(path, content, path.name) else: return False path.parent.mkdir(parents=True, exist_ok=True) with open(path, 'w', encoding='utf-8') as f: f.write(content) return True def merge_existing_file(self, existing_path: Path, new_content: str, file_type: str) -> str: """ 智能合并现有文件和新内容 策略: 1. 读取现有文件,识别用户自定义的章节 2. 保留以下用户自定义章节(如果存在): - ## 项目目标 下的自定义描述 - ## 核心工作流 下的自定义工作流 - ## 变更边界 下的自定义规则 - 用户添加的自定义章节(不在标准模板中的章节) 3. 更新标准化章节: - ## 工程原则(更新为最新标准) - ## 默认语言(更新为检测值) - ## 目录结构(仅 CLAUDE.md:更新为最新目录树;AGENTS.md 已不再包含该章节) - 平台特定说明(Claude Code / Codex CLI 特定部分) Args: existing_path: 现有文件路径 new_content: 新生成的内容 file_type: 文件类型("CLAUDE.md" 或 "AGENTS.md") Returns: 合并后的内容 """ try: with open(existing_path, 'r', encoding='utf-8') as f: existing_content = f.read() except Exception: # 如果读取失败,返回新内容 return new_content # 解析现有文件,提取需要保留的自定义内容 preserved_sections = {} custom_sections = [] # 1. 提取需要保留的自定义章节 section_patterns = { "项目目标": r"## 项目目标\s*\n+(.*?)(?=\n##|\Z)", "核心工作流": r"## 核心工作流\s*\n+(.*?)(?=\n##|\Z)", "变更边界": r"## 变更边界\s*\n+(.*?)(?=\n##|\Z)", } for section_name, pattern in section_patterns.items(): match = re.search(pattern, existing_content, re.DOTALL) if match: section_content = match.group(1).strip() # 检查是否是默认模板内容(通过特征判断) default_indicators = ["待填写", "请根据实际情况", "[项目类型]", "[待补充"] if not any(indicator in section_content for indicator in default_indicators): # 这是用户自定义的内容,保留它 preserved_sections[section_name] = section_content # 2. 提取用户添加的自定义章节(不在标准模板中的) standard_sections = { "CLAUDE.md": ["项目目标", "核心工作流", "工程原则", "默认语言", "目录结构", "Claude Code 特定说明", "文件引用规范", "验证要点", "变更边界", "有机更新原则"], # 说明:AGENTS.md 不再包含「目录结构」章节;为兼容旧文件,合并时会主动丢弃旧的该章节。 "AGENTS.md": ["项目目标", "核心工作流", "工程原则", "默认语言", "联网与搜索", "贡献记录", "代码优化与修改", "Codex CLI 特定说明", "文件与输出", "编辑原则", "变更边界", "变更记录规范", "版本号管理规范", "变更记录与版本", "与 CLAUDE.md 的关系", "有机更新原则"] } legacy_drop_sections = { "AGENTS.md": {"目录结构"}, } # 找出所有章节标题 all_sections = re.findall(r"^##\s+(.+)$", existing_content, re.MULTILINE) for section in all_sections: # 丢弃历史遗留但已废弃的标准章节(避免被当作“自定义章节”回填到新文件里) if section in legacy_drop_sections.get(file_type, set()): continue if section not in standard_sections.get(file_type, []): # 这是一个自定义章节,提取它的内容 pattern = rf"## {re.escape(section)}\s*\n+(.*?)(?=\n##|\Z)" match = re.search(pattern, existing_content, re.DOTALL) if match: custom_sections.append((section, match.group(1).strip())) # 3. 在新内容中应用保留的自定义内容 merged_content = new_content # 替换保留的章节 for section_name, section_content in preserved_sections.items(): pattern = rf"(## {re.escape(section_name)}\s*\n+)(.*?)(?=\n##|\Z)" if re.search(pattern, merged_content, re.DOTALL): merged_content = re.sub(pattern, rf"\1{section_content}\n", merged_content, count=1, flags=re.DOTALL) elif section_name == "变更边界": merged_content = re.sub( r"(### 编辑原则\s*\n+)(.*?)(?=\n##|\Z)", rf"\1\2\n{section_content}\n", merged_content, count=1, flags=re.DOTALL, ) # 添加自定义章节到文件末尾(在有机更新原则之前) if custom_sections: for section_name, section_content in custom_sections: # 检查新内容中是否已经有这个章节 if f"## {section_name}" not in merged_content: # 在有机更新原则之前插入 merged_content = merged_content.replace( "## 有机更新原则", f"## {section_name}\n\n{section_content}\n\n## 有机更新原则" ) return merged_content def check_consistency_reminder(self, claude_path: Path, agents_path: Path) -> None: """ 提醒用户新的维护工作流 Args: claude_path: CLAUDE.md 文件路径 agents_path: AGENTS.md 文件路径 """ both_exist = claude_path.exists() and agents_path.exists() if both_exist: print("\n" + "="*60) print("💡 AGENTS.md 与 CLAUDE.md 的关系") print("="*60) print("\n📋 推荐维护工作流:") print(" 1. 修改 AGENTS.md(唯一需要手动维护的文件)") print(" 2. CLAUDE.md 通过 @./AGENTS.md 自动引用") print(" 3. 无需运行任何同步命令") print("\n📌 架构说明:") print(" - AGENTS.md:跨平台通用项目指令(Single Source of Truth)") print(" - CLAUDE.md:Claude Code 特定适配(自动引用 AGENTS.md)") print(" - 修改 AGENTS.md 后,CLAUDE.md 会自动生效") print("\n🔧 参考文档:") print(" - AGENTS.md 标准:https://agents.md/") print(" - Claude Code @ 引用语法:https://github.com/anthropics/claude-code/issues/990") print("="*60 + "\n") def generate_auto( self, output_dir: Path = None, overwrite: bool = False, skip_readme: bool = False, skip_changelog: bool = False, skip_gitignore: bool = False, only_readme: bool = False, only_changelog: bool = False, enable_bac: Optional[bool] = None, bac_file: str = None ) -> bool: """ 完全自动生成:分析当前目录并生成文档 Args: output_dir: 输出目录(默认当前目录) overwrite: 是否覆盖已存在的文件 skip_readme: 跳过 README.md 生成 skip_changelog: 跳过 CHANGELOG.md 生成 skip_gitignore: 跳过 .gitignore 生成 only_readme: 仅生成 README.md only_changelog: 仅生成 CHANGELOG.md Returns: 是否成功 """ output_dir = output_dir or Path.cwd() # 验证输出目录(使用统一的安全验证方法) is_safe, error_msg = self.validate_output_dir(output_dir) if not is_safe: print(error_msg) return False # 分析项目 analysis = ProjectAnalyzer.analyze_project(output_dir) # 检测语言 language = self.detect_language() # 准备变量 bac_config = self.get_bac_config() bac_file = bac_file or bac_config.get("default_bac_file", "docs/contribution.bac") if enable_bac is None: enable_bac = bool(bac_config.get("enabled_by_default", True)) variables = self._prepare_variables(analysis, language, output_dir, bac_file, enable_bac) success = True generated_files = [] created_dirs = [] # 定义文件路径 claude_path = output_dir / "CLAUDE.md" agents_path = output_dir / "AGENTS.md" readme_path = output_dir / "README.md" changelog_path = output_dir / "CHANGELOG.md" # 如果是仅生成特定文件模式 if only_readme: readme_content = self.generate_readme_md(variables) if self.write_file(readme_path, readme_content, overwrite): generated_files.append(readme_path) else: print(f"⚠️ {readme_path.name} 已存在,使用 --overwrite 覆盖") success = False elif only_changelog: changelog_content = self.generate_changelog_md(variables) if self.write_file(changelog_path, changelog_content, overwrite): generated_files.append(changelog_path) else: print(f"⚠️ {changelog_path.name} 已存在,使用 --overwrite 覆盖") success = False else: # 完整初始化时补齐标准 docs 目录,但不让其影响项目类型检测结果 try: created_dirs = self.ensure_project_structure(output_dir) except ValueError as e: print(f"❌ {e}") return False if created_dirs: analysis["directory_tree"] = ProjectAnalyzer._generate_tree(output_dir, max_depth=2) variables = self._prepare_variables(analysis, language, output_dir, bac_file, enable_bac) if enable_bac: bac_success, bac_path, bac_created = self.setup_bac_contribution(output_dir, bac_file) if not bac_success: success = False elif bac_created and bac_path: generated_files.append(bac_path) else: print("ℹ️ BAC 贡献记录已通过 --disable-bac 显式关闭;之后可移除该参数重新启用。") # 完整生成模式 # 1. 生成 AGENTS.md(跨平台通用项目指令 - Single Source of Truth) agents_content = self.generate_agents_md(variables) agents_was_merged = agents_path.exists() and not overwrite if self.write_file(agents_path, agents_content, overwrite, merge=True): generated_files.append(agents_path) if agents_was_merged: print(f"🔄 {agents_path.name} 已智能更新(保留了自定义内容)") else: print(f"⚠️ {agents_path.name} 已存在,使用 --overwrite 覆盖") success = False # 2. 生成 CLAUDE.md(Claude Code 特定适配,使用 @./AGENTS.md 引用) claude_content = self.generate_claude_md(variables) claude_was_merged = claude_path.exists() and not overwrite if self.write_file(claude_path, claude_content, overwrite, merge=True): generated_files.append(claude_path) if claude_was_merged: print(f"🔄 {claude_path.name} 已智能更新(保留了自定义内容)") else: print(f"⚠️ {claude_path.name} 已存在,使用 --overwrite 覆盖") success = False # 显示工作流提醒 self.check_consistency_reminder(claude_path, agents_path) # 3. 生成 README.md(如果不存在或要求覆盖) if not skip_readme: if not readme_path.exists() or overwrite: readme_content = self.generate_readme_md(variables) if self.write_file(readme_path, readme_content, overwrite): generated_files.append(readme_path) else: print(f"ℹ️ {readme_path.name} 已存在,跳过生成(使用 --overwrite 覆盖)") # 4. 生成或更新 CHANGELOG.md if not skip_changelog: if not changelog_path.exists(): # 创建新的 CHANGELOG.md changelog_content = self.generate_changelog_md(variables) if self.write_file(changelog_path, changelog_content, True): generated_files.append(changelog_path) elif overwrite: # 如果要求覆盖,追加新条目 today = datetime.now().strftime("%Y-%m-%d") entry = f"""## [1.0.0] - {today} ### Added(新增) - 重新初始化 AI 项目指令文件 - 更新 `AGENTS.md`(跨平台通用项目指令) - 更新 `CLAUDE.md`(Claude Code 特定适配) """ if self.append_changelog_entry(changelog_path, entry): print(f"ℹ️ 已更新 {changelog_path.name}") else: print(f"ℹ️ {changelog_path.name} 已存在,跳过更新") # 5. 生成或更新 .gitignore gitignore_path = output_dir / ".gitignore" if not skip_gitignore: if not gitignore_path.exists(): # 创建新的 .gitignore gitignore_content = self.generate_gitignore(analysis['type']) if self.write_file(gitignore_path, gitignore_content, True): generated_files.append(gitignore_path) print(f"🔒 已生成 {gitignore_path.name}(包含安全和项目特定规则)") elif overwrite: # 覆盖模式:智能合并 new_gitignore = self.generate_gitignore(analysis['type']) merged_gitignore = self.merge_gitignore(gitignore_path, new_gitignore) if self.write_file(gitignore_path, merged_gitignore, True): generated_files.append(gitignore_path) print(f"🔄 已更新 {gitignore_path.name}(保留自定义规则)") else: print(f"ℹ️ {gitignore_path.name} 已存在,跳过更新(使用 --overwrite 更新)") # 输出结果 if generated_files: print(f"✅ 已生成 AI 项目指令文档:") for f in generated_files: print(f" - {f.name}") if created_dirs: print(f"\n📁 已初始化文档目录:") for directory in created_dirs: print(f" - {directory.relative_to(output_dir)}/") print(f"\n📊 项目分析结果:") print(f" 名称: {analysis['name']}") print(f" 类型: {analysis['type_info']['name']}") print(f" 语言: {language}") return success def _bac_notes(self, bac_file: str, bac_enabled: bool) -> dict: """按 BAC 启用状态生成贡献记录相关模板变量""" if bac_enabled: return { "贡献记录政策说明": ( "本项目默认且强制基于 " "[bensz-auto-contribution](https://github.com/huangwb8/bensz-auto-contribution) " f"使用 `bac` 工具,客观记录人类与 AI 的协作贡献边界;默认贡献托管文件为 `{bac_file}`" ), "贡献记录初始化说明": "初始化项目时必须检查 Python 环境、确认 `bac` 包可用;若环境未配置好,必须自动安装该 Python 依赖并初始化账本", "贡献记录开关说明": "BAC 是默认强制执行步骤;除非项目负责人明确要求使用脚本级 `--disable-bac` 逃生开关,否则不得跳过依赖检查、安装与账本初始化", "贡献记录README说明": f"默认使用 `{bac_file}` 记录人类与 AI 协作过程;如项目决定关闭,可在初始化时使用 `--disable-bac`", "贡献记录变更说明": f"初始化 BAC 贡献记录:默认托管文件为 `{bac_file}`", } return { "贡献记录政策说明": ( "本项目当前未启用 " "[bensz-auto-contribution](https://github.com/huangwb8/bensz-auto-contribution) " f"的 `bac` 贡献记录;如后续重新启用,贡献托管文件建议使用 `{bac_file}`" ), "贡献记录初始化说明": "本次初始化已显式关闭 BAC 自动安装与账本初始化,之后可移除关闭开关重新启用", "贡献记录开关说明": "贡献记录当前处于关闭状态;用户可以随时重新开启,例如运行初始化脚本时不要传入 `--disable-bac`", "贡献记录README说明": f"本次初始化已显式关闭 BAC 贡献记录;默认托管文件仍建议使用 `{bac_file}`,后续可重新启用", "贡献记录变更说明": "本次初始化显式关闭 BAC 贡献记录,未创建默认 `.bac` 文件", } def _prepare_variables( self, analysis: dict, language: str, output_dir: Path, bac_file: str = None, bac_enabled: bool = True ) -> dict: """准备模板变量""" project_type = analysis['type_info']['name'] today = datetime.now().strftime("%Y-%m-%d") bac_file = bac_file or self.get_bac_config().get("default_bac_file", "docs/contribution.bac") bac_notes = self._bac_notes(bac_file, bac_enabled) # 根据项目类型生成默认工作流描述 workflow_templates = { "Python 项目": "代码开发 → 单元测试 → 文档更新 → 版本发布", "Web 项目": "功能开发 → 组件测试 → 构建部署 → 监控反馈", "数据科学项目": "数据获取 → 探索分析 → 模型训练 → 验证评估", "Rust 项目": "API 设计 → 实现 → 单元测试 → 文档 → 发布", "Go 项目": "需求分析 → API 设计 → 实现 → 集成测试 → 部署", "Java 项目": "需求分析 → 设计 → 编码 → 测试 → 构建 → 部署", "文档项目": "内容规划 → 撰写 → 审校 → 发布", "通用项目": "需求分析 → 设计 → 实现 → 验证 → 交付", } # 根据项目类型生成特性描述 feature_templates = { "Python 项目": "- 基于 Python 开发\n- 遵循 PEP 8 代码规范\n- 支持单元测试和文档生成", "Web 项目": "- 现代 Web 应用架构\n- 组件化开发模式\n- 响应式设计支持", "数据科学项目": "- 数据处理与分析\n- 机器学习模型训练\n- 可视化报告生成", "Rust 项目": "- 高性能系统编程\n- 内存安全保证\n- 零成本抽象", "Go 项目": "- 简洁高效的语法\n- 原生并发支持\n- 快速编译部署", "Java 项目": "- 企业级应用开发\n- 强类型系统\n- 丰富的生态系统", "文档项目": "- 结构化文档管理\n- 多格式输出支持\n- 版本控制集成", "通用项目": "- 模块化设计\n- 可扩展架构\n- 完善的文档", } # 根据项目类型生成环境要求 env_templates = { "Python 项目": "- Python 3.8+\n- pip 或 uv 包管理器", "Web 项目": "- Node.js 18+\n- npm 或 pnpm 包管理器", "数据科学项目": "- Python 3.8+\n- Jupyter Notebook\n- 常用数据科学库", "Rust 项目": "- Rust 1.70+\n- Cargo 包管理器", "Go 项目": "- Go 1.21+\n- Go modules 支持", "Java 项目": "- JDK 17+\n- Maven 或 Gradle 构建工具", "文档项目": "- Markdown 编辑器\n- 静态站点生成器(可选)", "通用项目": "- 根据项目需求配置", } # 根据项目类型生成安装步骤 install_templates = { "Python 项目": "```bash\n# 创建虚拟环境(统一放入 BenszAPI 运行产物目录)\npython -m venv .bensz-api/.venv\nsource .bensz-api/.venv/bin/activate # Windows: .bensz-api\\.venv\\Scripts\\activate\n\n# 安装依赖\npip install -r requirements.txt\n```", "Web 项目": "```bash\n# 安装依赖\nnpm install\n# 或使用 pnpm\npnpm install\n```", "数据科学项目": "```bash\n# 创建虚拟环境(统一放入 BenszAPI 运行产物目录)\npython -m venv .bensz-api/.venv\nsource .bensz-api/.venv/bin/activate\n\n# 安装依赖\npip install -r requirements.txt\n```", "Rust 项目": "```bash\n# 构建项目\ncargo build\n\n# 运行测试\ncargo test\n```", "Go 项目": "```bash\n# 下载依赖\ngo mod download\n\n# 构建项目\ngo build ./...\n```", "Java 项目": "```bash\n# Maven 构建\nmvn clean install\n\n# 或 Gradle 构建\n./gradlew build\n```", "文档项目": "```bash\n# 根据使用的文档工具进行安装\n# 例如 MkDocs:\npip install mkdocs\nmkdocs serve\n```", "通用项目": "```bash\n# 根据项目需求进行安装\n```", } # 根据项目类型生成使用示例 usage_templates = { "Python 项目": "```bash\n# 运行主程序\npython main.py\n\n# 运行测试\npytest\n```", "Web 项目": "```bash\n# 开发模式\nnpm run dev\n\n# 构建生产版本\nnpm run build\n```", "数据科学项目": "```bash\n# 启动 Jupyter Notebook\njupyter notebook\n\n# 或运行分析脚本\npython analyze.py\n```", "Rust 项目": "```bash\n# 运行项目\ncargo run\n\n# 发布构建\ncargo build --release\n```", "Go 项目": "```bash\n# 运行项目\ngo run .\n\n# 测试\ngo test ./...\n```", "Java 项目": "```bash\n# Maven 运行\nmvn exec:java\n\n# 或直接运行 JAR\njava -jar target/app.jar\n```", "文档项目": "```bash\n# 本地预览\nmkdocs serve\n\n# 构建静态站点\nmkdocs build\n```", "通用项目": "```bash\n# 根据项目需求运行\n```", } return { "项目名称": analysis['name'], "项目描述": analysis['description'] or f"{project_type},遵循工程最佳实践", "工作目录": "本项目", "默认语言": language, "项目用途": analysis['description'] or f"{project_type}开发与维护", "核心功能描述": analysis['description'] or f"{project_type}的核心功能开发与维护", "工作流描述": workflow_templates.get(project_type, workflow_templates["通用项目"]), "目录树": analysis['directory_tree'], "项目类型": project_type, **bac_notes, # README.md 专用变量 "项目特性": feature_templates.get(project_type, feature_templates["通用项目"]), "环境要求": env_templates.get(project_type, env_templates["通用项目"]), "安装步骤": install_templates.get(project_type, install_templates["通用项目"]), "使用示例": usage_templates.get(project_type, usage_templates["通用项目"]), # CHANGELOG.md 专用变量 "版本号": "1.0.0", "日期": today, "一句话概括项目的价值主张": analysis['description'] or f"提供 {project_type} 的核心功能", } def main(): """命令行入口""" import argparse parser = argparse.ArgumentParser( description="为项目生成 AI 项目指令文件(CLAUDE.md + AGENTS.md + README.md + CHANGELOG.md)", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" 示例: # 完全自动生成(分析当前目录) python3 generate.py --auto # 自动生成并覆盖现有文件 python3 generate.py --auto --overwrite # 显式关闭默认 BAC 贡献记录初始化 python3 generate.py --auto --disable-bac # 仅生成 AGENTS.md 和 CLAUDE.md(跳过 README 和 CHANGELOG) python3 generate.py --auto --skip-readme --skip-changelog # 手动指定项目信息 python3 generate.py --project-name my-project --project-descriptio -
test_console_encoding.py 6.5 KB
from __future__ import annotations import importlib.util import os import subprocess import sys import tempfile import unittest from pathlib import Path SKILL_ROOT = Path(__file__).resolve().parents[1] SCRIPT_PATH = SKILL_ROOT / "scripts" / "generate.py" def _load_generate_module(): spec = importlib.util.spec_from_file_location("init_project_generate_for_test", SCRIPT_PATH) if spec is None or spec.loader is None: raise RuntimeError("cannot load generate.py") module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module class _AsciiStream: encoding = "ascii" def __init__(self) -> None: self.data = "" def write(self, text: str) -> int: encoded = text.encode(self.encoding) decoded = encoded.decode(self.encoding) self.data += decoded return len(text) def flush(self) -> None: return None class _BrokenStream(_AsciiStream): def write(self, text: str) -> int: raise OSError("simulated stream failure") class ConsoleEncodingTest(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.module = _load_generate_module() def _run_cli(self, args: list[str], *, encoding: str) -> tuple[subprocess.CompletedProcess[bytes], Path]: tempdir = tempfile.TemporaryDirectory(prefix="init-project-console-") self.addCleanup(tempdir.cleanup) project_root = Path(tempdir.name) / "project" project_root.mkdir() env = os.environ.copy() env["PYTHONIOENCODING"] = f"{encoding}:strict" proc = subprocess.run( [sys.executable, str(SCRIPT_PATH), *args], cwd=str(project_root), env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False, ) return proc, project_root def test_proxy_retries_only_unicode_encode_error(self) -> None: stream = _AsciiStream() proxy = self.module._UnicodeSafeTextStream(stream) proxy.write("status ✅") self.assertIn("\\u2705", stream.data) with self.assertRaises(OSError): self.module._UnicodeSafeTextStream(_BrokenStream()).write("plain text") def test_non_reconfigurable_streams_are_wrapped(self) -> None: stdout = _AsciiStream() stderr = _AsciiStream() original_stdout, original_stderr = sys.stdout, sys.stderr try: sys.stdout, sys.stderr = stdout, stderr self.module._configure_console_streams() self.assertIsInstance(sys.stdout, self.module._UnicodeSafeTextStream) self.assertIsInstance(sys.stderr, self.module._UnicodeSafeTextStream) sys.stdout.write("✅") sys.stderr.write("❌") finally: sys.stdout, sys.stderr = original_stdout, original_stderr self.assertIn("\\u2705", stdout.data) self.assertIn("\\u274c", stderr.data) def test_auto_mode_completes_under_strict_gbk(self) -> None: proc, project_root = self._run_cli(["--auto", "--disable-bac"], encoding="gbk") output = (proc.stdout + proc.stderr).decode("gbk", errors="replace") self.assertEqual(proc.returncode, 0, output) self.assertNotIn("UnicodeEncodeError", output) for name in ("AGENTS.md", "CLAUDE.md", "README.md", "CHANGELOG.md", ".gitignore"): self.assertTrue((project_root / name).exists(), name) self.assertTrue((project_root / "docs" / "plans").is_dir()) self.assertTrue((project_root / "skills").is_dir()) agents_content = (project_root / "AGENTS.md").read_text(encoding="utf-8") self.assertIn("project-specific Agent Skills", agents_content) self.assertIn("huangwb8/skills", agents_content) def test_manual_mode_completes_under_strict_gbk(self) -> None: proc, project_root = self._run_cli( [ "--project-name", "console-test", "--project-description", "encoding regression", "--disable-bac", ], encoding="gbk", ) output = (proc.stdout + proc.stderr).decode("gbk", errors="replace") self.assertEqual(proc.returncode, 0, output) self.assertNotIn("UnicodeEncodeError", output) self.assertTrue((project_root / "AGENTS.md").exists()) self.assertTrue((project_root / "CLAUDE.md").exists()) self.assertTrue((project_root / "skills").is_dir()) agents_content = (project_root / "AGENTS.md").read_text(encoding="utf-8") self.assertIn("本项目当前未启用", agents_content) self.assertIn("贡献记录当前处于关闭状态", agents_content) self.assertNotIn("{贡献记录政策说明}", agents_content) self.assertNotIn("本项目默认且强制", agents_content) def test_utf8_behavior_remains_successful(self) -> None: proc, project_root = self._run_cli(["--auto", "--disable-bac"], encoding="utf-8") output = (proc.stdout + proc.stderr).decode("utf-8", errors="replace") self.assertEqual(proc.returncode, 0, output) self.assertIn("已生成", output) self.assertTrue((project_root / "AGENTS.md").exists()) def test_bac_policy_matches_enabled_state(self) -> None: generator = self.module.ProjectInitGenerator() analysis = { "name": "bac-policy-test", "description": "BAC policy regression", "type_info": {"name": "通用项目"}, "directory_tree": "bac-policy-test/", } enabled_variables = generator._prepare_variables( analysis, "简体中文", Path.cwd(), bac_enabled=True ) enabled_agents = generator.generate_agents_md(enabled_variables) self.assertIn("本项目默认且强制", enabled_agents) self.assertIn("BAC 是默认强制执行步骤", enabled_agents) self.assertNotIn("本项目当前未启用", enabled_agents) disabled_variables = generator._prepare_variables( analysis, "简体中文", Path.cwd(), bac_enabled=False ) disabled_agents = generator.generate_agents_md(disabled_variables) self.assertIn("本项目当前未启用", disabled_agents) self.assertIn("贡献记录当前处于关闭状态", disabled_agents) for forbidden_text in ( "本项目默认且强制", "BAC 是默认强制执行步骤", "默认贡献托管文件", ): self.assertNotIn(forbidden_text, disabled_agents) if __name__ == "__main__": unittest.main()
-
-
templates
-
AGENTS.md.template 5.1 KB · in bundle
-
CHANGELOG.md.template 986 B · in bundle
-
CLAUDE.md.template 411 B · in bundle
-
gitignore.yaml 5.1 KB
# .gitignore 配置模板 # 说明:init-project 从此文件读取 .gitignore 生成规则 # 版本:1.0.0 # ============================================================================ # 共性设置(所有项目类型都会添加) # ============================================================================ common: # 操作系统生成文件 - ".DS_Store" - ".DS_Store?" - "._*" - ".Spotlight-V100" - ".Trashes" - "ehthumbs.db" - "Thumbs.db" - "desktop.ini" # IDE 和编辑器 - ".idea/" - ".vscode/" - "*.swp" - "*.swo" - "*~" - ".sublime-*" - "*.sublime-workspace" # 环境变量和敏感信息(安全关键) - ".env" - ".env.local" - ".env.*.local" - "*.pem" - "*.key" - "*.crt" - "secrets/" - ".secrets/" - "credentials/" - ".credentials" # 日志和临时文件 - "*.log" - "*.tmp" - "*.temp" - "*.bak" - "*.cache" - "tmp/" - "temp/" # Agent Skills / AI 工作流中间产物 # 根级目录使用 / 前缀,避免误伤源码项目自己的子目录 tests/plans - "/tests/" - "/plans/" - "/reviews/" - "/suggestions/" - "/tmp/run_*/" - ".auto-test-code-run.json" - ".awesome-code/" - ".bensz-api/" - ".bensz-skills/" - ".bensz-skills-backup/" - ".check-review-alignment/" - ".compact-bensz-skills/" - ".complete_example/" - ".download-fulltext-pdf/" - ".draw-plot/" - ".dudu-optimize-prompt/" - ".explain-figures/" - ".explain-results/" - ".find-best-skill/" - ".git-pr-review/" - ".install-bensz-skills/" - ".latex-cache/" - ".make-research-plan/" - ".make_latex_model/" - ".md-to-word/" - ".mirror/" - ".nsfc-budget/" - ".nsfc-code/" - ".nsfc-length-aligner/" - ".nsfc-qc/" - "*.nsfc-qc/" - ".nsfc-ref-alignment/" - ".nsfc-reviewers/" - ".nsfc-roadmap/" - ".nsfc-schematic/" - ".paper-explain-figures/" - ".paper-know-journal/" - ".paper-select-journal/" - ".paper-write-sci/" - ".parallel-vibe/" - ".parallel_vibe/" - ".research-idea/" - ".systematic-literature-review/" - ".write-paper-sci/" - ".write-paper/" # 压缩文件(通常不需要版本控制) - "*.zip" - "*.tar.gz" - "*.rar" - "*.7z" # ============================================================================ # 项目类型特定设置 # ============================================================================ by_type: python: # Python 字节码和包 - "__pycache__/" - "*.py[cod]" - "*$py.class" - "*.so" - ".Python" # 虚拟环境 - "venv/" - ".venv/" - "env/" - ".env/" - "ENV/" # 分发和打包 - "build/" - "develop-eggs/" - "dist/" - "downloads/" - "eggs/" - ".eggs/" - "lib/" - "lib64/" - "parts/" - "sdist/" - "var/" - "wheels/" - "*.egg-info/" - "*.egg" - ".manifest" # 测试和覆盖率 - ".pytest_cache/" - ".ruff_cache/" - ".coverage" - "htmlcov/" - ".tox/" - ".nox/" - "coverage.xml" - "*.cover" # Jupyter Notebook - ".ipynb_checkpoints" - "*.ipynb_checkpoints/" # mypy - ".mypy_cache/" - ".dmypy.json" - "dmypy.json" web: # 依赖目录 - "node_modules/" - "jspm_packages/" # 构建输出 - "dist/" - "build/" - "out/" - ".next/" - ".nuxt/" - ".output/" - ".cache/" # 日志 - "npm-debug.log*" - "yarn-debug.log*" - "yarn-error.log*" - "pnpm-debug.log*" - "lerna-debug.log*" # 运行时数据 - "pids" - "*.pid" - "*.seed" - "*.pid.lock" # TypeScript - "*.tsbuildinfo" rust: # 编译输出 - "/target/" - "**/*.rs.bk" # IDE - ".cargo/config.toml.bak" go: # 编译输出 - "*.exe" - "*.exe~" - "*.dll" - "*.so" - "*.dylib" - "*.test" - "*.out" # 依赖目录 - "vendor/" # Go 工作区文件 - "go.work" - "go.work.sum" java: # 编译输出 - "target/" - "*.class" - "*.jar" - "*.war" - "*.ear" # Maven - ".mvn/" - "mvnw" - "mvnw.cmd" # Gradle - ".gradle/" - "gradle-app.setting" - "!gradle-wrapper.jar" - ".gradle-build-cache/" # IDE - ".settings/" - ".classpath" - ".project" - "*.iml" data-science: # Python 相关(继承 python 规则) - "__pycache__/" - "*.py[cod]" - ".venv/" - "venv/" # Jupyter - ".ipynb_checkpoints" - "*.ipynb_checkpoints/" # 数据文件(通常很大,不适合版本控制) - "*.csv" - "*.xlsx" - "*.parquet" - "*.h5" - "*.hdf5" - "*.pkl" - "*.pickle" - "*.npy" - "*.npz" # 模型文件 - "*.pt" - "*.pth" - "*.onnx" - "*.model" - "*.weights" # 数据目录 - "data/raw/" - "data/processed/" - "models/" - "checkpoints/" - "outputs/" # MLflow - "mlruns/" - "mlartifacts/" # TensorBoard - "runs/" - "logs/" docs: # 构建输出 - "site/" - "_site/" - ".docusaurus/" - ".cache/" # Node 依赖 - "node_modules/" # 临时文件 - "*.md.tmp" -
README.md.template 1.2 KB · in bundle
-
-
CHANGELOG.md 12.8 KB
# Changelog **重要**:本文件是 init-project 技能变更的**唯一正式记录**。凡是本技能的更新,都要统一在本文件里记录。 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。 ## [Unreleased] ### Added(新增) - **项目专属 Skills 目录**:完整初始化新增 `skills/`,用于托管 project-specific Agent Skills;生成的 `AGENTS.md` 明确要求遵循 `huangwb8/skills` 的 `AGENTS.md` 与 `docs/templates` 规范,技能版本号 `2.3.6 → 2.4.0` - **BAC 贡献记录默认集成**:初始化项目时默认检查 Python 环境和 `bac` 包,必要时安装 `git+https://github.com/huangwb8/bensz-auto-contribution.git`,并初始化贡献托管文件 - 默认托管文件为 `docs/contribution.bac` - 新增 `--bac-file` 参数,允许用户指定项目内其它 `.bac` 文件路径 - 新增 `--disable-bac` 参数,允许用户随时显式关闭 BAC 初始化步骤 - 生成的 `AGENTS.md` 新增“贡献记录”章节,声明基于 auto-contribution 客观记录人类/AI 协作贡献边界 - **安全性声明章节**:在 SKILL.md 中新增"安全性声明"章节,明确技能的工作边界 - 允许的操作:在当前工作目录内创建/修改文件,只读访问当前目录 - 禁止的操作:修改当前目录之外的任何文件或文件夹 - 风险说明:违反边界可能导致用户不知情的文件修改、其它项目崩溃、数据丢失 - 执行保障:脚本使用相对路径,所有文件写入前验证目标路径 - **README.md 安全性保障章节**:在用户指南中添加"安全性保障"章节,说明安全机制和操作边界 - **docs 目录初始化**:完整初始化项目时,脚本会自动创建 `docs/` 与 `docs/plans/`;如果目录已经存在则直接复用,避免重复创建或报错 - **计划文档固定位置**:在生成的 `AGENTS.md` 中明确计划文档统一放在 `./docs/plans/` ### Changed(变更) - **跨平台控制台兼容**:版本号 `2.3.3 → 2.3.4`;保持宿主 stdout/stderr 编码,只把不可编码字符的错误策略收敛为 `backslashreplace`,UTF-8 输出与业务退出语义不变 - **.gitignore 中间目录忽略规则**:基于 `pipelines/skills/` 与 `ChineseResearchLaTeX/skills/` 的现有 skill 工作区约定,新增 `.systematic-literature-review/`、`.complete_example/`、`.latex-cache/`、`.make_latex_model/`、`.nsfc-budget/`、`.nsfc-code/`、`.nsfc-length-aligner/`、`.nsfc-qc/`、`*.nsfc-qc/`、`.nsfc-ref-alignment/`、`.research-idea/`、`.write-paper/` 与 `.secrets/` 到生成模板和 PyYAML 缺失时的脚本内置兜底规则;`.check-review-alignment/` 已在模板中保留;技能版本号 `2.3.2 → 2.3.3` - **.gitignore 中间目录忽略规则**:新增 `.parallel-vibe/` 到生成模板与 PyYAML 缺失时的脚本内置兜底规则,用于匹配 `parallel-vibe` 默认中间工作区新目录;保留 `.parallel_vibe/` 兼容旧运行产物 - **.gitignore 中间目录忽略规则**:新增 `.bensz-api/` 到生成模板与 PyYAML 缺失时的脚本内置兜底规则,用于忽略 api-prompt 协作产物目录;技能版本号 `2.3.1 → 2.3.2` - **.gitignore 模板补全**:新增 Bensz/Agent Skills 常见中间产物忽略规则,覆盖 `.draw-plot/`、`.parallel_vibe/`、`.paper-know-journal/`、`.compact-bensz-skills/`、`.git-pr-review/`、`.awesome-code/` 等隐藏工作区,以及根级 `/tests/`、`/plans/`、`/reviews/`、`/suggestions/`;同步更新 PyYAML 缺失时的脚本内置兜底规则,并将版本号 `2.3.0 → 2.3.1` - **AGENTS.md BAC 默认口径**:生成的 `AGENTS.md` 将 BAC 贡献记录声明为默认强制执行步骤;初始化时必须检查 Python 环境与 `bac` 包,环境未配置好时自动安装并初始化账本。脚本级 `--disable-bac` 逃生开关保留,但模板不再把 BAC 描述为普通可选项 - **SKILL.md 工作型文档压缩**:使用 `compact-bensz-skills` 精简 `SKILL.md` 正文,并二次轻量压缩表格与合并策略说明;保留触发语义、路径安全、BAC 默认集成、docs 初始化、智能合并和验证清单等硬约束 - **BAC 仓库地址同步**:将默认安装源、项目链接与生成模板中的仓库地址从 `huangwb8/auto-contribution` 更新为 `huangwb8/bensz-auto-contribution`,匹配上游仓库改名后的正式地址 - **增强路径验证**:改进 `validate_output_dir()` 方法,新增"当前工作目录边界检查" - 使用 `Path.relative_to()` 验证输出目录必须在当前工作目录内 - 如果尝试访问当前目录之外的路径,立即终止并显示详细警告信息 - 保留原有的系统敏感目录检查作为额外安全层 - **docs 非计划文档同步约束**:更新 `AGENTS.md` 模板与说明文档,要求当代码变化导致 `docs/` 中非 `plans/` 文档过时时,必须实时更新这些用户文档、教程等内容,使其与项目实际业务逻辑保持一致 - **AGENTS.md 模板压缩**:合并 Codex CLI 输出、编辑边界、变更记录、版本管理与有机更新说明,保留核心约束并减少生成文档冗余 - **必需章节同步**:更新 `agents_required_sections` 与智能合并白名单,兼容旧版 `## 变更边界` 内容迁移到新版编辑原则 - **CHANGELOG.md 模板压缩**:将教程式记录规范改为最小维护规则,保留初始记录、Keep a Changelog 和 SemVer 约束 - **CLAUDE.md 模板压缩**:将 Claude Code 专属说明进一步合并为 4 条短规则,保留 `@./AGENTS.md` 引用和必要适配 ### Fixed(修复) - **手动模式 BAC 占位符残留**:版本号 `2.3.5 → 2.3.6`;手动模式改为在 CLI 侧内联构造完整模板变量,与自动模式的 `_prepare_variables()` 解耦;按启用状态生成的五条贡献记录说明收敛为 `_bac_notes()` 单一来源供两种模式共用,修复手动模式生成的 `AGENTS.md` 残留 `{贡献记录政策说明}` 未替换占位符的问题,并恢复手动模式禁用 BAC 的内容回归断言 - **禁用 BAC 后的指令一致性**:版本号 `2.3.4 → 2.3.5`;修复使用 `--disable-bac` 时生成的 `AGENTS.md` 仍无条件声明 BAC“默认且强制”的问题,改为按启用状态完整生成贡献记录政策,并新增启用/禁用分支回归测试。 - **Windows GBK 初始化崩溃**:在任何业务输出前集中配置 stdout/stderr 编码容错;不支持 `reconfigure()` 的嵌入流仅在底层抛出 `UnicodeEncodeError` 时转义并重试,普通 `OSError` 和业务异常继续传播;新增自动模式、手动模式、UTF-8 与异常传播回归测试 - **占位符误报**:将模板示例中的 `{时间戳}` 识别为代码示例占位符,避免初始化时出现无效未替换警告 - **裸 Python 启动**:`PyYAML` 缺失时不再导入崩溃,改为使用内置默认配置和默认 `.gitignore` 规则兜底 ## [2.1.0] - 2026-03-02 ### Added(新增) - **智能 .gitignore 生成**:自动生成适合项目类型的 Git 忽略规则,确保向 GitHub 提交时安全 - 共性设置:操作系统生成文件、IDE 配置、环境变量和敏感信息(.env、*.pem、*.key)、日志和临时文件 - 个性化设置:根据项目类型(Python/Web/Rust/Go/Java/数据科学/文档)添加特定忽略规则 - 安全优先原则:宁可多忽略,不可漏掉敏感文件 - 智能合并策略:保留用户自定义规则,更新标准化部分 - 新增 `--skip-gitignore` 命令行参数,可跳过 .gitignore 生成 - 在 config.yaml 中添加 `gitignore_common` 和 `gitignore_by_type` 配置项 - **配置加载优雅降级**:config.yaml 不存在或损坏时使用默认配置,而非崩溃 - **输出目录安全验证**:阻止在系统敏感目录(/etc、/root 等)中创建文件 ### Fixed(修复) - 移除 Python gitignore 规则中的 `.gitignore` 条目(该规则会导致 .gitignore 文件忽略自己) - 修复 docs 项目类型检测过于宽泛的问题(移除 `*.md` 指标,避免误判) - 修复 YAML frontmatter 与 SKILL.md 正文对生成文件描述不一致的问题 - 消除目录验证逻辑重复代码(提取为 `validate_output_dir` 公共方法) ### Removed(移除) - 移除未使用的目录模板配置(default_directory_template、python_directory_template、web_directory_template) - 移除未使用的 template_placeholders 配置 ### Changed(变更) - `init-project/SKILL.md` 按社区推荐格式瘦身:移除大段内嵌模板示例,改为引用 `init-project/templates/*.template`,确保 `SKILL.md` ≤ 500 行 - **AGENTS.md 输出精简**:`init-project/templates/AGENTS.md.template` 不再生成 `## 目录结构` 章节;智能合并时会自动丢弃旧的该章节,避免被当作自定义内容回填 - **.gitignore 配置迁移**:将 gitignore 规则从 config.yaml 迁移到 templates/gitignore.yaml,减少 config.yaml 篇幅约 230 行 ## [2.0.1] - 2026-01-18 ### Fixed(修复) - **版本号一致性**:从 SKILL.md 中移除硬编码的 `version` 字段,改为注释引用 config.yaml(P0-1) - **路径验证**:在 `generate_auto()` 和 `main()` 中添加输出目录验证,防止在不存在的目录中创建文件(P0-2) - **必需章节同步**:更新 config.yaml 中的 `agents_required_sections`,与 AGENTS.md.template 保持一致(P0-3) - **智能合并提示**:在智能合并时输出警告,提示用户如果结果不符合预期可使用 `--overwrite` 参数(B3-1) - **占位符检测**:在 `replace_placeholders()` 中添加未替换占位符警告(P1-7) ### Removed(移除) - **未使用配置**:删除 `max_questions_rush`、`min_required_info_rush`、`backup_before_overwrite`、`backup_suffix`、`static_validation_checks` 等未实现的配置项(P1-2/P1-3/P1-4) - **脚本版本号**:移除 generate.py 中的硬编码版本号,改为注释引用 config.yaml(P2-1) ### 说明(Notes) 本次更新基于 auto-test-skill 的批判性分析,修复了 8 个问题(3 个 P0、4 个 P1、1 个 P2)。 --- ## [2.0.0] - 2025-01-18 ### Added(新增) - **架构重构**:采用 AGENTS.md 作为 Single Source of Truth 的新架构 - **自动引用**:CLAUDE.md 通过 `@./AGENTS.md` 语法自动引用 AGENTS.md - **零维护成本**:修改 AGENTS.md 后,CLAUDE.md 自动生效,无需运行同步命令 - **符合社区标准**:遵循 [AGENTS.md 官方规范](https://agents.md/)(60k+ 开源项目采用) - **版本管理**:在 config.yaml 中添加 skill_info 版本信息 ### Changed(变更) - **生成顺序**:先生成 AGENTS.md(跨平台通用),再生成 CLAUDE.md(Claude Code 特定) - **SKILL.md**: - 更新描述,强调 AGENTS.md 的 Single Source of Truth 地位 - 移除所有同步相关的工作流说明 - 添加 Claude Code @ 引用语法的说明 - **generate.py**: - 移除 `--sync-from` 参数和相关逻辑 - 移除 `--check-consistency` 参数和相关逻辑 - 移除 `sync_from_source()`、`check_consistency()` 方法 - 更新 `check_consistency_reminder()` 为新的工作流提醒 - 调整生成顺序,先生成 AGENTS.md,再生成 CLAUDE.md - **CLAUDE.md.template**: - 完全重写为简洁的引用模板 - 使用 `@./AGENTS.md` 语法 - 添加"与 AGENTS.md 的关系"章节 - **config.yaml**: - 添加 skill_info 版本信息 - 更新目录结构模板的注释 - 简化 claude_required_sections 和 agents_required_sections ### Removed(移除) - **双向同步功能**:移除 AGENTS.md ↔ CLAUDE.md 的双向同步逻辑 - **一致性检查**:移除两个文件的一致性检查功能 - **同步命令**:移除 `--sync-from` 和 `--check-consistency` 命令行参数 ### Fixed(修复) - 修正了 CLAUDE.md 和 AGENTS.md 的关系描述,明确 AGENTS.md 是跨平台通用文件 ### 说明(Notes) **为何进行此次大版本更新?** 1. **符合社区标准**:AGENTS.md 是跨平台通用格式,应作为主文件,而非特定平台的附属文件 2. **降低维护成本**:通过 Claude Code 的 `@` 引用语法,实现真正的零维护成本 3. **简化工作流**:用户只需维护 AGENTS.md 一个文件,CLAUDE.md 自动生效 4. **更好的架构**:AGENTS.md(通用)+ CLAUDE.md(特定)的分离架构更清晰 **升级指南**: 如果你已经在使用 v1.x 版本: 1. 运行 `python3 init-project/scripts/generate.py --auto --overwrite` 重新生成文件 2. 之后只需维护 AGENTS.md,CLAUDE.md 会自动引用 AGENTS.md 的内容 3. 不再需要运行任何同步命令 **参考文档**: - [AGENTS.md 官方网站](https://agents.md/) - [Claude Code Issue #990:@ 引用语法](https://github.com/anthropics/claude-code/issues/990) --- ## [1.0.0] - 2025-01-XX ### Added(新增) - 初始化 init-project 技能 - 支持自动生成 CLAUDE.md 和 AGENTS.md - 支持双向同步功能 - 支持一致性检查 -
config.yaml 4 KB
# Project Init Generator 配置文件 # 说明:集中管理可配置参数,避免在 SKILL.md 中硬编码 # 版本号以 skill_info.version 为准 # ============================================================================ # 版本信息 # ============================================================================ skill_info: name: init-project version: 2.4.0 description: 完全自动生成 AI 项目指令文档(AGENTS.md + CLAUDE.md + README.md + CHANGELOG.md + .gitignore) author: "Bensz Conan" category: 项目初始化 # ============================================================================ # BAC 贡献记录配置 # ============================================================================ bac_contribution: enabled_by_default: true default_bac_file: docs/contribution.bac install_spec: git+https://github.com/huangwb8/bensz-auto-contribution.git min_python_version: "3.10" project_url: https://github.com/huangwb8/bensz-auto-contribution # ============================================================================ # 语言映射配置 # ============================================================================ # 操作系统语言代码到对话语言的映射 language_mapping: zh-CN: 简体中文 zh_CN: 简体中文 zh-Hans: 简体中文 zh-Hans-CN: 简体中文 en-US: English en_US: English en-GB: English en_GB: English ja-JP: 日本語 ja_JP: 日本語 ko-KR: 한국어 ko_KR: 한국어 # 默认回退语言 default: 简体中文 # 语言检测命令(按平台优先级) language_detection_commands: darwin: # macOS - locale | grep LANG - defaults read -g AppleLanguages linux: - echo $LANG - locale - cat /etc/locale.conf windows: # Git Bash / WSL - echo $LANG - locale # ============================================================================ # 内置工程原则 # ============================================================================ built_in_principles: - KISS (Keep It Simple, Stupid) - YAGNI (You Aren't Gonna Need It) - DRY (Don't Repeat Yourself) - SOLID (面向对象设计五大原则) - 关注点分离 (Separation of Concerns) - 奥卡姆剃刀 (Occam's Razor) - 最小惊讶原则 (Principle of Least Astonishment) - 早期返回原则 (Early Return) # 原则冲突时的决策优先级 principle_priority: - 正确性 - 简洁性 - 清晰性 - 扩展性 # ============================================================================ # 文档生成配置 # ============================================================================ # AGENTS.md 必需章节(跨平台通用项目指令) # 注意:此列表应与 templates/AGENTS.md.template 中的实际章节保持一致 agents_required_sections: - 项目目标 - 核心工作流 - 工程原则 - 默认语言 - 联网与搜索 - 贡献记录 - Codex CLI 特定说明 - 变更记录与版本 - 有机更新原则 # CLAUDE.md 必需章节(Claude Code 特定适配) claude_required_sections: - 核心指令(通过 @./AGENTS.md 引用) - Claude Code 特定说明 - 与 AGENTS.md 的关系 # README.md 必需章节 readme_required_sections: - 项目名称和描述 - 特性 - 快速开始 - 目录结构 - AI 辅助开发 - 许可证 # CHANGELOG.md 必需章节 changelog_required_sections: - Unreleased - 版本条目(Added/Changed/Fixed) # ============================================================================ # 文件处理配置 # ============================================================================ # 覆盖确认提示 overwrite_prompt: "文件已存在,是否覆盖?" # ============================================================================ # .gitignore 配置 # ============================================================================ # 注意:.gitignore 规则已迁移到 templates/gitignore.yaml # 这样可以: # 1. 减少 config.yaml 的篇幅 # 2. 让 .gitignore 配置更易于维护 # 3. 支持独立版本控制 -
README.md 5.4 KB
# Init Project 这个 skill 用来为当前项目初始化标准化的 AI 协作文档和基础仓库文件,适合新项目起步或已有项目补齐指令体系;它只应该在当前项目目录内工作,不应越界修改其它目录。 ## 用法 ### 最推荐用法 ```text 请使用 init-project skill 为本项目进行初始化。 输入:当前项目根目录 输出:`AGENTS.md`、`CLAUDE.md`、`README.md`、`CHANGELOG.md`、`.gitignore`、`docs/`、`docs/plans/`、`skills/` ``` ### 进阶用法 ```text 请使用 init-project skill 为本项目进行初始化。 输入:当前项目根目录 输出:标准化项目指令与说明文档 另外,还有下列参数约束: - 尽量保留已有内容 - 默认语言自动检测 - 不修改当前目录之外的文件 ``` ## 能做什么 - 为项目生成 `AGENTS.md`、`CLAUDE.md`、`README.md`、`CHANGELOG.md`、`.gitignore`,并初始化 `docs/` 与 `docs/plans/`。 - 把 `AGENTS.md` 作为跨平台通用指令的单一真相来源。 - 让 `CLAUDE.md` 成为面向 Claude Code 的轻量适配层。 - 自动分析项目结构、项目类型和默认语言。 - 兼容 Windows GBK 等非 UTF-8 控制台;状态符号无法显示时会安全转义,不会把真实业务失败误报为成功。 - 默认启用 BAC 贡献记录:检查 Python 环境和 `bac` 包,必要时安装,并初始化 `docs/contribution.bac`。 - 不适合拿来扫描父目录、批量改多个项目,或无边界地覆盖已有文件。 ## 使用示例 ### 示例 1:初始化一个新项目 ```text 请使用 init-project skill 为本项目进行初始化。 输入:当前项目根目录 输出:完整的项目指令文件与说明文档 ``` ### 示例 2:为已有项目补齐协作文档 ```text 请使用 init-project skill 初始化这个已有仓库。 输入:当前项目根目录 输出:`AGENTS.md`、`CLAUDE.md`、`README.md`、`CHANGELOG.md`、`.gitignore`、`docs/`、`docs/plans/` 另外,还有下列参数约束: - 尽量保留已有 README 的有效信息 - 不破坏现有项目结构 ``` ### 示例 3:只补某一类文档 ```text 请使用 init-project skill 为本项目补齐说明文档。 输入:当前项目根目录 输出:README 或 CHANGELOG 另外,还有下列参数约束: - 只更新 README ``` ## 输出 - `AGENTS.md`:跨平台通用项目指令,应该被长期维护。 - `CLAUDE.md`:Claude Code 适配层,核心内容应与 `AGENTS.md` 保持一致。 - `README.md`:项目介绍、快速开始和目录说明。 - `CHANGELOG.md`:项目变更记录。 - `.gitignore`:默认的安全与项目类型忽略规则。 - `docs/`:项目文档根目录。 - `docs/plans/`:计划文档固定目录;其余 `docs/` 文档在代码变化时也应及时同步更新。 - `skills/`:project-specific Agent Skills 目录。目录内 Skill 遵循 `huangwb8/skills` 的 `AGENTS.md` 与 `docs/templates` 规范;通用 Skill 不应复制到这里。 - `docs/contribution.bac`:默认 BAC 贡献托管文件;用户可通过 `--bac-file` 指定其它项目内路径。 ## 配置 - 配置文件:`init-project/config.yaml` - 关键配置节: - `language_mapping` - `bac_contribution` - `agents_required_sections` - `claude_required_sections` - `readme_required_sections` - `changelog_required_sections` - 这个 skill 的默认定位是“完整初始化”,不是只生成一份孤立文档。 ## 备选用法(脚本/硬编码) 如果你想直接在命令行下执行项目初始化,脚本入口最方便。 ### 自动分析当前目录并生成文件 ```bash python3 init-project/scripts/generate.py --auto ``` ### 自动分析并覆盖已有文件 ```bash python3 init-project/scripts/generate.py --auto --overwrite ``` ### 只生成部分文档 ```bash python3 init-project/scripts/generate.py --auto --only-readme python3 init-project/scripts/generate.py --auto --only-changelog ``` ### 跳过部分输出 ```bash python3 init-project/scripts/generate.py \ --auto \ --skip-readme \ --skip-changelog \ --skip-gitignore ``` ### BAC 贡献记录 ```bash # 默认开启:检查/安装 bac,并初始化 docs/contribution.bac python3 init-project/scripts/generate.py --auto # 指定项目内的其它 BAC 文件 python3 init-project/scripts/generate.py --auto --bac-file docs/audit/contribution.bac # 随时显式关闭 BAC 初始化步骤 python3 init-project/scripts/generate.py --auto --disable-bac ``` 关闭后,生成的 `AGENTS.md` 会明确 BAC 当前未启用,不再保留“默认且强制”的启用态指令。 BAC 基于 <https://github.com/huangwb8/bensz-auto-contribution>,用于客观记录人类与 AI 的协作过程和证据,不替代最终署名、责任或合规判断。 ## 常见问题 ### Q:`AGENTS.md` 和 `CLAUDE.md` 到底谁是主文件? A:`AGENTS.md` 是单一真相来源;`CLAUDE.md` 是平台适配层。维护时应优先保证 `AGENTS.md` 的口径正确。 ### Q:它会不会改到当前项目目录之外? A:不应该。这个 skill 的边界就是“当前目录内生成或更新项目文件”。 ### Q:既然是自动化,是不是可以放心覆盖任何已有文件? A:不能这么理解。自动化不等于无脑覆盖。是否覆盖应由你显式决定,例如使用 `--overwrite`。 ### Q:为什么 `.gitignore` 也算初始化结果的一部分? A:因为它直接关系到项目安全和仓库整洁度,尤其能防止敏感文件、系统文件和缓存文件被误提交。 -
SKILL.md 10 KB
--- name: init-project description: 当用户明确要求初始化项目、创建项目指令文件、生成 AGENTS.md,或为已有项目补齐 AI 协作规范时使用。该 Skill 会分析项目结构,并生成或更新适用于当前项目的标准化协作文档与基础目录。 metadata: author: Bensz Conan short-description: 完全自动生成 AI 项目指令文档并初始化标准 docs 目录 keywords: - init-project - 项目初始化 - AGENTS.md - CLAUDE.md - 项目指令 - 项目规范 - 自动分析项目 - 检测项目类型 - OpenAI Codex - Claude Code - 跨平台指令 - "@引用语法" - SingleSourceofTruth --- # Init Project ## 目标 当用户明确要求初始化项目、创建项目指令文件、生成 AGENTS.md,或为已有项目补齐 AI 协作规范时使用。本 Skill 分析项目结构,并生成或更新适用于当前项目的标准化协作文档与基础目录。 ## 流程 ### 输入 输入为目标项目根目录及用户选择的初始化模式;可选输入包括项目名称/描述、工作流、输出开关、`--overwrite`、`--bac-file` 和 `--disable-bac`。输出路径必须位于当前项目目录内,现有治理文件和用户自定义章节应先识别再合并。 ### 执行步骤 #### 目标与边界 为当前项目生成标准 AI 协作文档,让 Claude Code / OpenAI Codex CLI 等工具理解项目目标、工程原则、变更记录规则与协作边界。 只允许在当前工作目录及其子目录内创建或修改文件。禁止写入父目录、其它项目、系统目录或用户级配置。脚本会在写入前校验输出路径,失败时立即停止。 #### 核心约束 - `AGENTS.md` 是唯一需要长期手动维护的通用指令源;`CLAUDE.md` 只做 Claude Code 适配,并通过 `@./AGENTS.md` 自动引用。 - 生成模板统一放在 `init-project/templates/`:`AGENTS.md.template`、`CLAUDE.md.template`、`README.md.template`、`CHANGELOG.md.template`、`gitignore.yaml`。 - 配置统一放在 `init-project/config.yaml`,版本号以 `skill_info.version` 为准;当前 BAC 配置在 `bac_contribution`。 - 完整初始化必须补齐 `docs/`、`docs/plans/` 与 `skills/`;`skills/` 只托管项目专属 Agent Skills。 - `skills/` 中的 Agent Skill 必须遵循 `huangwb8/skills` 仓库的 `AGENTS.md`,并配合该仓库的 `docs/templates` 使用;不得把通用 Skill 或无关项目代码放入其中。 - 代码变化导致 `docs/` 中非 `plans/` 文档过时时,生成的项目指令必须要求同步更新。 - 影响项目行为、结构、工作流、工程原则、指令文件或关键配置的变更,必须写入 `CHANGELOG.md` 的 `[Unreleased]`。 #### BAC 贡献记录 默认基于 `bensz-auto-contribution` / `bac` 记录人类、AI 与工具贡献证据: - 默认仓库:`https://github.com/huangwb8/bensz-auto-contribution` - 默认安装源:`git+https://github.com/huangwb8/bensz-auto-contribution.git` - 默认文件:`docs/contribution.bac` - Python 要求:`config.yaml:bac_contribution.min_python_version`,当前为 `3.10` - 默认开启;用户可随时通过 `--disable-bac` 显式关闭。关闭时生成的文档也必须说明当前已关闭且可重新启用。 - 用户通过 `--bac-file` 指定项目内其它路径时,以用户指定为准;禁止把 `.bac` 文件写到项目目录外。 BAC 是过程记录与辅助审计材料,不替代最终署名、责任或合规判断;不得记录敏感密钥、完整私有提示词或无关个人隐私。 #### 推荐执行 在目标项目根目录运行: ```bash python3 init-project/scripts/generate.py --auto ``` 常用参数: ```bash # 覆盖/强制更新已有文件 python3 init-project/scripts/generate.py --auto --overwrite # 指定 BAC 文件,必须位于项目目录内 python3 init-project/scripts/generate.py --auto --bac-file docs/audit/contribution.bac # 显式关闭默认 BAC 初始化 python3 init-project/scripts/generate.py --auto --disable-bac # 只生成单类文档 / 跳过可选输出 python3 init-project/scripts/generate.py --auto --only-readme python3 init-project/scripts/generate.py --auto --only-changelog python3 init-project/scripts/generate.py --auto --skip-readme --skip-gitignore ``` 手动模式只在用户明确给出项目信息时使用: ```bash python3 init-project/scripts/generate.py \ --project-name "my-project" \ --project-description "数据科学项目" \ --workflow "数据获取 → 分析 → 可视化" ``` #### 自动模式流程 `--auto` 会依次完成: 1. 验证输出目录必须位于当前工作目录内。 2. 分析项目:从 README 提取名称/描述,按标志文件识别项目类型,生成最多 2 层目录树。 3. 检测默认语言,失败时回退到简体中文。 4. 完整初始化时创建 `docs/` 与 `docs/plans/`。 5. 按配置决定是否启用 BAC:检查 Python 与 `bac` 包,必要时安装,初始化或验证 `.bac` 文件。 6. 生成或智能合并 `AGENTS.md`、`CLAUDE.md`。 7. 按条件生成 `README.md`、`CHANGELOG.md`、`.gitignore`。 8. 输出生成文件、目录与项目分析摘要。 项目类型识别标志:Python(`pyproject.toml`、`requirements.txt` 等)、Web(`package.json` 等)、Rust(`Cargo.toml`)、Go(`go.mod`)、Java(`pom.xml`/Gradle)、数据科学(`*.ipynb`、`*.R`、`environment.yml`)、文档(`docs/`、`mkdocs.yml`、`docusaurus.config.js`)。 #### 智能合并策略 当 `AGENTS.md` 或 `CLAUDE.md` 已存在时,默认智能合并而非直接覆盖:保留用户自定义的 `## 项目目标`、`## 核心工作流`、`## 变更边界` 及非标准章节;更新工程原则、默认语言、平台适配、`AGENTS.md` 必需章节与 `CLAUDE.md` 的 `@./AGENTS.md` 引用。`AGENTS.md` 中历史遗留的 `## 目录结构` 会被丢弃,避免回填为自定义章节;合并不符合预期时提示用户用 `--overwrite`。 #### .gitignore 策略 从 `templates/gitignore.yaml` 读取规则;缺少 PyYAML 或配置损坏时使用默认规则兜底。安全优先,默认忽略系统文件、IDE 配置、日志、临时文件、环境变量、密钥、凭证目录和常见构建/缓存产物。已有 `.gitignore` 在覆盖模式下会保留用户自定义规则。 ### 输出 #### 输出文件 - `AGENTS.md`:跨平台通用项目指令,Single Source of Truth;必生成,智能合并。 - `CLAUDE.md`:Claude Code 适配层,核心为 `@./AGENTS.md`;必生成,智能合并。 - `README.md`、`CHANGELOG.md`、`.gitignore`:按需生成;`--overwrite` 可覆盖/合并。项目变更必须维护 `CHANGELOG.md`。 - `docs/`、`docs/plans/`、`skills/`:完整初始化时自动补齐;计划文档固定放在 `./docs/plans/`,项目专属 Agent Skills 固定放在 `./skills/`。 - `docs/contribution.bac`:默认 BAC 账本;`--bac-file` 可改,`--disable-bac` 可关。 ### 输出管理 #### BenszAPI 任务工作区 ### 校验 #### 交付前检查 - [ ] `AGENTS.md` 包含必需章节:项目目标、核心工作流、工程原则、默认语言、联网与搜索、贡献记录、Codex CLI 特定说明、变更记录与版本、有机更新原则。 - [ ] `CLAUDE.md` 正确通过 `@./AGENTS.md` 引用通用指令。 - [ ] `docs/`、`docs/plans/`、`skills/` 已存在或无需本模式创建。 - [ ] BAC 已初始化/验证,或用户已显式使用 `--disable-bac`。 - [ ] `.gitignore` 已生成/合并,且包含敏感文件忽略规则。 - [ ] `CHANGELOG.md` 已创建或变更已记录。 - [ ] 未写入当前项目目录之外的文件。 ### 失败与恢复 #### 错误处理 - Windows GBK 等非 UTF-8 控制台不会因装饰性 Unicode 状态符号中止;脚本保留宿主编码,仅转义无法编码的字符,业务异常与退出码仍按原逻辑传播。 - 输出目录越界、目标目录不存在或不是目录:停止。 - `docs` / `docs/plans` / `skills` 已存在但不是目录:停止。 - BAC 安装、导入、初始化或验证失败:停止,并提示可用 `--disable-bac` 显式关闭。 - 语言检测失败:回退到简体中文。 - 项目类型无法识别:使用通用项目模板。 - `PyYAML` 缺失:脚本继续运行,配置与 `.gitignore` 使用默认值。 ## 约束 <!-- BEGIN COMMON CONSTRAINTS --> <!-- Source-Hash: sha256:15120201e9e0c7569517261d57ecefb63ac279c26ed13876f8e95b6dc35854d3 --> <!-- Template-ID: skill-common-constraints; Template-Version: 1; Sync-Policy: exact-block --> ### 公共硬约束 本块由 `docs/templates/skill-common-constraints.md` 统一维护;每个 `SKILL.md` 的 `## 约束` 必须逐字同步本块,不得在副本中改写公共规则。 - 任务需要落盘时,使用唯一的 `./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/` 根目录;共享材料放入 `shared/`,Skill 专属材料放入该 Skill 的 `input/`、`output/`、`log/`。 - 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。 - 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。 - 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。 - 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。 - Skill 版本唯一记录在自身 `config.yaml:skill_info.version`;公开 API、协议、目录或配置变更同步文档与 `CHANGELOG.md`。 - `bensz-collect-bugs` 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 `~/.bensz-skills/bugs/`,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。 <!-- End of canonical common constraints. --> <!-- END COMMON CONSTRAINTS -->
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.