ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

,\n text,\n )\n if not match:\n raise ValueError(f\"Could not find [project] version in {path}.\")\n return SemVer.parse(match.group(1))\n\n\ndef extract_python_init_version(path: Path) -> SemVer:\n \"\"\"Extract the runtime package version from anp/__init__.py.\"\"\"\n text = read_text(path)\n match = re.search(r'(?m)^__version__ = \"(\\d+\\.\\d+\\.\\d+)\"

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

, text)\n if not match:\n raise ValueError(f\"Could not find __version__ in {path}.\")\n return SemVer.parse(match.group(1))\n\n\ndef extract_cargo_package_version(path: Path) -> SemVer:\n \"\"\"Extract the package version from rust/Cargo.toml.\"\"\"\n text = read_text(path)\n match = re.search(\n r'(?ms)^\\[package\\]\\s+.*?^version = \"(\\d+\\.\\d+\\.\\d+)\"\\s*

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

,\n text,\n )\n if not match:\n raise ValueError(f\"Could not find [package] version in {path}.\")\n return SemVer.parse(match.group(1))\n\n\ndef extract_go_runtime_version(path: Path) -> SemVer:\n \"\"\"Extract the runtime package version from golang/version.go.\"\"\"\n text = read_text(path)\n match = re.search(r'(?m)^const Version = \"(\\d+\\.\\d+\\.\\d+)\"

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

, text)\n if not match:\n raise ValueError(f\"Could not find Version const in {path}.\")\n return SemVer.parse(match.group(1))\n\n\ndef extract_uv_lock_version(path: Path) -> SemVer:\n \"\"\"Extract the editable root package version from uv.lock.\"\"\"\n text = read_text(path)\n match = re.search(\n r'(?ms)^name = \"anp\"\\nversion = \"(\\d+\\.\\d+\\.\\d+)\"\\nsource = \\{ editable = \"\\.\" \\}

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

,\n text,\n )\n if not match:\n raise ValueError(\n \"Could not find the editable root package version in uv.lock.\"\n )\n return SemVer.parse(match.group(1))\n\n\ndef extract_cargo_lock_version(path: Path) -> SemVer:\n \"\"\"Extract the root package version from rust/Cargo.lock.\"\"\"\n text = read_text(path)\n match = re.search(\n r'(?ms)^name = \"anp\"\\nversion = \"(\\d+\\.\\d+\\.\\d+)\"\\n',\n text,\n )\n if not match:\n raise ValueError(\"Could not find the root package version in Cargo.lock.\")\n return SemVer.parse(match.group(1))\n\n\ndef resolve_target_version(\n current_version: SemVer,\n explicit_version: str | None,\n) -> SemVer:\n \"\"\"Resolve the target version from arguments.\"\"\"\n if explicit_version:\n return SemVer.parse(explicit_version)\n return current_version.next_single_digit()\n\n\ndef update_version_files(paths: ReleasePaths, target_version: SemVer) -> list[Path]:\n \"\"\"Update all tracked version files and return the changed file list.\"\"\"\n changed_paths: list[Path] = []\n\n replacements: list[tuple[Path, str]] = [\n (\n paths.pyproject_toml,\n r'(?ms)(^\\[project\\]\\s+.*?^version = \")(\\d+\\.\\d+\\.\\d+)(\".*$)',\n ),\n (\n paths.python_init,\n r'(?m)^(__version__ = \")(\\d+\\.\\d+\\.\\d+)(\")

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

,\n ),\n (\n paths.cargo_toml,\n r'(?ms)(^\\[package\\]\\s+.*?^version = \")(\\d+\\.\\d+\\.\\d+)(\".*$)',\n ),\n (\n paths.go_version,\n r'(?m)^(const Version = \")(\\d+\\.\\d+\\.\\d+)(\")

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---

,\n ),\n (\n paths.uv_lock,\n r'(?ms)(^name = \"anp\"\\nversion = \")(\\d+\\.\\d+\\.\\d+)(\"\\nsource = \\{ editable = \"\\.\" \\}$)',\n ),\n (\n paths.cargo_lock,\n r'(?ms)(^name = \"anp\"\\nversion = \")(\\d+\\.\\d+\\.\\d+)(\"\\n)',\n ),\n ]\n\n if not paths.cargo_lock.exists():\n replacements = [\n item for item in replacements if item[0] != paths.cargo_lock\n ]\n\n for path, pattern in replacements:\n original_text = read_text(path)\n updated_text, count = re.subn(\n pattern,\n rf\"\\g\u003c1>{target_version}\\g\u003c3>\",\n original_text,\n count=1,\n )\n if count != 1:\n raise ValueError(f\"Failed to update version in {path}.\")\n if updated_text != original_text:\n write_text(path, updated_text)\n changed_paths.append(path)\n\n return changed_paths\n\n\ndef build_release_tags(target_version: SemVer) -> tuple[str, str]:\n \"\"\"Return the root tag and Go module tag for the target version.\"\"\"\n version_text = str(target_version)\n return version_text, f\"golang/v{version_text}\"\n\n\ndef check_tag_absent(repo_root: Path, remote: str, tag_name: str) -> None:\n \"\"\"Ensure a tag does not already exist locally or remotely.\"\"\"\n local_result = run_command(\n [\"git\", \"tag\", \"--list\", tag_name],\n cwd=repo_root,\n capture_output=True,\n )\n if local_result.stdout.strip():\n raise RuntimeError(f\"Tag already exists locally: {tag_name}\")\n\n remote_result = run_command(\n [\"git\", \"ls-remote\", \"--tags\", remote, f\"refs/tags/{tag_name}\"],\n cwd=repo_root,\n capture_output=True,\n )\n if remote_result.stdout.strip():\n raise RuntimeError(f\"Tag already exists on {remote}: {tag_name}\")\n\n\ndef ensure_clean_worktree(repo_root: Path) -> None:\n \"\"\"Ensure the repository has no uncommitted changes.\"\"\"\n status = run_command(\n [\"git\", \"status\", \"--short\"],\n cwd=repo_root,\n capture_output=True,\n )\n if status.stdout.strip():\n raise RuntimeError(\n \"Working tree is not clean. Commit or stash changes before release.\"\n )\n\n\ndef clean_dist_directory(dist_dir: Path) -> None:\n \"\"\"Remove previous release artifacts from dist/.\"\"\"\n if not dist_dir.exists():\n return\n for child in dist_dir.iterdir():\n if child.is_dir():\n shutil.rmtree(child)\n else:\n child.unlink()\n\n\ndef run_release_validations(paths: ReleasePaths) -> None:\n \"\"\"Run build and validation commands before publishing.\"\"\"\n clean_dist_directory(paths.dist_dir)\n\n run_command([\"uv\", \"build\"], cwd=paths.repo_root)\n run_command(\n [\n \"cargo\",\n \"publish\",\n \"--dry-run\",\n \"--allow-dirty\",\n \"--manifest-path\",\n \"rust/Cargo.toml\",\n ],\n cwd=paths.repo_root,\n )\n run_command([\"go\", \"test\", \"./...\"], cwd=paths.repo_root / \"golang\")\n\n\ndef collect_python_publish_files(\n paths: ReleasePaths,\n target_version: SemVer,\n) -> list[Path]:\n \"\"\"Return the Python distribution files for the target version only.\"\"\"\n version_text = str(target_version)\n sdist_matches = sorted(paths.dist_dir.glob(f\"anp-{version_text}*.tar.gz\"))\n wheel_matches = sorted(paths.dist_dir.glob(f\"anp-{version_text}*.whl\"))\n\n missing_artifacts: list[str] = []\n if len(sdist_matches) != 1:\n missing_artifacts.append(f\"dist/anp-{version_text}*.tar.gz\")\n if not wheel_matches:\n missing_artifacts.append(f\"dist/anp-{version_text}*.whl\")\n\n if missing_artifacts:\n raise FileNotFoundError(\n \"Missing Python distribution files for publish:\\n- \"\n + \"\\n- \".join(missing_artifacts)\n )\n\n return [*sdist_matches, *wheel_matches]\n\n\ndef maybe_commit_version_bump(\n repo_root: Path,\n changed_paths: Sequence[Path],\n target_version: SemVer,\n remote: str,\n) -> None:\n \"\"\"Commit and push changed version files when needed.\"\"\"\n if not changed_paths:\n print(\"No version files changed. Skip commit and branch push.\")\n return\n\n tracked_paths = [\n path for path in changed_paths if is_git_tracked(repo_root, path)\n ]\n if not tracked_paths:\n print(\"Only ignored or untracked files changed. Skip commit and branch push.\")\n return\n\n relative_paths = [str(path.relative_to(repo_root)) for path in tracked_paths]\n run_command([\"git\", \"add\", *relative_paths], cwd=repo_root)\n run_command(build_version_bump_commit_command(target_version), cwd=repo_root)\n run_command([\"git\", \"push\", remote, \"HEAD\"], cwd=repo_root)\n\n\ndef build_version_bump_commit_command(target_version: SemVer) -> list[str]:\n \"\"\"Build a Lore-compatible git commit command for the release bump.\"\"\"\n return [\n \"git\",\n \"commit\",\n \"-m\",\n f\"Keep Python, Rust, and Go consumers on {target_version}\",\n \"-m\",\n (\n \"The coordinated release workflow bumps every package manifest, \"\n \"lock file, and runtime version constant together before publishing \"\n \"so registry artifacts and Go module tags identify the same SDK cut.\"\n ),\n \"-m\",\n \"\\n\".join(\n [\n (\n \"Constraint: Python, Rust, and Go package ecosystems publish \"\n \"from different metadata surfaces\"\n ),\n (\n \"Rejected: Hand-edit per-language version files during \"\n \"release | recurring manual step previously caused drift\"\n ),\n \"Confidence: high\",\n \"Scope-risk: narrow\",\n (\n \"Directive: Do not publish a coordinated release unless all \"\n \"version surfaces are bumped by this helper\"\n ),\n \"Tested: uv build\",\n (\n \"Tested: cargo publish --dry-run --allow-dirty \"\n \"--manifest-path rust/Cargo.toml\"\n ),\n \"Tested: go test ./... from golang/\",\n \"Not-tested: Registry publication happens after this commit\",\n ]\n ),\n ]\n\n\ndef publish_python(paths: ReleasePaths, target_version: SemVer) -> None:\n \"\"\"Publish only the target Python distribution files with uv.\"\"\"\n publish_files = collect_python_publish_files(paths, target_version)\n relative_paths = [\n str(path.relative_to(paths.repo_root)) for path in publish_files\n ]\n run_command([\"uv\", \"publish\", *relative_paths], cwd=paths.repo_root)\n\n\ndef publish_rust(repo_root: Path) -> None:\n \"\"\"Publish the Rust crate to crates.io.\"\"\"\n run_command(\n [\"cargo\", \"publish\", \"--manifest-path\", \"rust/Cargo.toml\"],\n cwd=repo_root,\n )\n\n\ndef create_and_push_tags(\n repo_root: Path,\n remote: str,\n root_tag: str,\n go_tag: str,\n) -> None:\n \"\"\"Create and push the root release tag and Go module tag.\"\"\"\n run_command([\"git\", \"tag\", root_tag], cwd=repo_root)\n run_command([\"git\", \"tag\", go_tag], cwd=repo_root)\n run_command([\"git\", \"push\", remote, root_tag, go_tag], cwd=repo_root)\n\n\ndef print_release_plan(\n paths: ReleasePaths,\n current_version: SemVer,\n target_version: SemVer,\n remote: str,\n) -> None:\n \"\"\"Print the release plan without modifying files.\"\"\"\n root_tag, go_tag = build_release_tags(target_version)\n print(f\"Repository root: {paths.repo_root}\")\n print(f\"Current version: {current_version}\")\n print(f\"Target version: {target_version}\")\n print(f\"Git remote: {remote}\")\n print(f\"Root release tag: {root_tag}\")\n print(f\"Go module tag: {go_tag}\")\n print(\"Files to update:\")\n print(f\"- {paths.pyproject_toml.relative_to(paths.repo_root)}\")\n print(f\"- {paths.python_init.relative_to(paths.repo_root)}\")\n print(f\"- {paths.uv_lock.relative_to(paths.repo_root)}\")\n print(f\"- {paths.cargo_toml.relative_to(paths.repo_root)}\")\n print(f\"- {paths.go_version.relative_to(paths.repo_root)}\")\n if paths.cargo_lock.exists():\n print(f\"- {paths.cargo_lock.relative_to(paths.repo_root)}\")\n print(\"Validation steps:\")\n print(\"- uv build\")\n print(\"- cargo publish --dry-run --manifest-path rust/Cargo.toml\")\n print(\"- go test ./... (from golang/)\")\n print(\"Publish steps:\")\n print(\"- git push origin HEAD (after version commit)\")\n print(\n f\"- uv publish dist/anp-{target_version}*.tar.gz \"\n f\"dist/anp-{target_version}*.whl\"\n )\n print(\"- cargo publish --manifest-path rust/Cargo.toml\")\n print(f\"- git push {remote} {root_tag} {go_tag}\")\n\n\ndef run_command(\n command: Sequence[str],\n *,\n cwd: Path,\n capture_output: bool = False,\n) -> subprocess.CompletedProcess[str]:\n \"\"\"Run a command and stream or capture its output.\"\"\"\n print(f\"Running: {' '.join(command)}\")\n return subprocess.run(\n command,\n cwd=str(cwd),\n check=True,\n text=True,\n capture_output=capture_output,\n )\n\n\ndef is_git_tracked(repo_root: Path, path: Path) -> bool:\n \"\"\"Return whether a path is tracked by git.\"\"\"\n result = subprocess.run(\n [\"git\", \"ls-files\", \"--error-unmatch\", str(path.relative_to(repo_root))],\n cwd=str(repo_root),\n text=True,\n capture_output=True,\n check=False,\n )\n return result.returncode == 0\n\n\ndef main() -> int:\n \"\"\"Run the CLI.\"\"\"\n parser = build_parser()\n args = parser.parse_args()\n\n repo_root = detect_repo_root(\n args.repo_root.resolve() if args.repo_root else Path(__file__).resolve()\n )\n paths = get_release_paths(repo_root)\n current_version = extract_current_version(paths)\n\n if args.command == \"next-version\":\n print(current_version.next_single_digit())\n return 0\n\n target_version = resolve_target_version(current_version, args.version)\n root_tag, go_tag = build_release_tags(target_version)\n\n if args.command == \"plan\":\n print_release_plan(paths, current_version, target_version, args.remote)\n return 0\n\n if not args.allow_dirty:\n ensure_clean_worktree(paths.repo_root)\n\n check_tag_absent(paths.repo_root, args.remote, root_tag)\n check_tag_absent(paths.repo_root, args.remote, go_tag)\n\n changed_paths = update_version_files(paths, target_version)\n run_release_validations(paths)\n maybe_commit_version_bump(paths.repo_root, changed_paths, target_version, args.remote)\n publish_python(paths, target_version)\n publish_rust(paths.repo_root)\n create_and_push_tags(paths.repo_root, args.remote, root_tag, go_tag)\n\n print(f\"Release completed successfully for version {target_version}.\")\n print(\"Note: pkg.go.dev and proxy.golang.org may take time to index the Go tag.\")\n return 0\n\n\nif __name__ == \"__main__\":\n try:\n sys.exit(main())\n except subprocess.CalledProcessError as error:\n print(\n f\"Command failed with exit code {error.returncode}: \"\n f\"{' '.join(error.cmd)}\",\n file=sys.stderr,\n )\n if error.stdout:\n print(error.stdout, file=sys.stderr)\n if error.stderr:\n print(error.stderr, file=sys.stderr)\n sys.exit(error.returncode)\n except Exception as error: # pylint: disable=broad-except\n print(f\"Release failed: {error}\", file=sys.stderr)\n sys.exit(1)\n","content_type":"text/x-python; charset=utf-8","language":"python","size":22221,"content_sha256":"c0342193c0e78888dcfb76e5a4ffb8f4518136f14264495bc4a81b408e960b56"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"ANP Multi SDK Release","type":"text"}]},{"type":"paragraph","content":[{"text":"在 ","type":"text"},{"text":"anp/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 仓库根目录执行统一发版。","type":"text"}]},{"type":"paragraph","content":[{"text":"优先使用脚本:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv run python skills/anp-multilang-release/scripts/release.py ...","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"快速使用","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"本次固定发布 0.7.2","type":"text"}]},{"type":"paragraph","content":[{"text":"先看计划:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd anp\nuv run python skills/anp-multilang-release/scripts/release.py plan --version 0.7.2","type":"text"}]},{"type":"paragraph","content":[{"text":"确认后正式发布:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd anp\nuv run python skills/anp-multilang-release/scripts/release.py release --version 0.7.2","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"下次自动递增版本","type":"text"}]},{"type":"paragraph","content":[{"text":"查看下一个版本号:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd anp\nuv run python skills/anp-multilang-release/scripts/release.py next-version","type":"text"}]},{"type":"paragraph","content":[{"text":"直接按自动版本发布:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd anp\nuv run python skills/anp-multilang-release/scripts/release.py release","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"版本规则","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"统一版本格式是 ","type":"text"},{"text":"X.Y.Z","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"每一段都必须是单个数字 ","type":"text"},{"text":"0-9","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"自动递增顺序:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0.7.2 -> 0.7.3","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0.7.9 -> 0.8.0","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0.9.9 -> 1.0.0","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不允许生成 ","type":"text"},{"text":"0.7.10","type":"text","marks":[{"type":"code_inline"}]},{"text":" 这种两位数段","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"如果要改规则,先读 ","type":"text"},{"text":"references/release-policy.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"发布动作","type":"text"}]},{"type":"paragraph","content":[{"text":"脚本会按下面顺序执行:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"检查 Git 工作区是否干净","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"检查 Python、Rust、锁文件版本是否一致","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"更新:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pyproject.toml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"anp/__init__.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"uv.lock","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rust/Cargo.toml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rust/Cargo.lock","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"golang/version.go","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"执行校验:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"uv build","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"cargo publish --dry-run --manifest-path rust/Cargo.toml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"go test ./...","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果版本文件有变化,提交并推送分支","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布 Python 包","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布 Rust crate","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"推送两个 tag:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"根 tag:","type":"text"},{"text":"\u003cversion>","type":"text","marks":[{"type":"code_inline"}]},{"text":",例如 ","type":"text"},{"text":"0.7.2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Go tag:","type":"text"},{"text":"golang/v\u003cversion>","type":"text","marks":[{"type":"code_inline"}]},{"text":",例如 ","type":"text"},{"text":"golang/v0.7.2","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Python 发布阶段会显式上传当前目标版本对应的 ","type":"text"},{"text":"dist/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 构件,避免把历史产物一并上传。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"使用前提","type":"text"}]},{"type":"paragraph","content":[{"text":"发布前确保:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"当前仓库是 ","type":"text"},{"text":"anp/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 根目录","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Git remote 具备 push 权限","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"uv publish","type":"text","marks":[{"type":"code_inline"}]},{"text":" 已经具备可用凭证","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"cargo publish","type":"text","marks":[{"type":"code_inline"}]},{"text":" 已经具备可用凭证","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"如果不是用 ","type":"text"},{"text":"origin","type":"text","marks":[{"type":"code_inline"}]},{"text":",可以加:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv run python skills/anp-multilang-release/scripts/release.py release --remote \u003cremote-name>","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"处理异常","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果 tag 已存在,脚本会直接停止","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果版本文件不同步,脚本会直接停止","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果构建或发布失败,先修复问题,再重新执行","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果只是想查看动作,不要直接发版,先运行 ","type":"text"},{"text":"plan","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"anp-multilang-release","author":"@skillopedia","source":{"stars":315,"repo_name":"anp","origin_url":"https://github.com/agent-network-protocol/anp/blob/HEAD/skills/anp-multilang-release/SKILL.md","repo_owner":"agent-network-protocol","body_sha256":"9eb07b36a1d3759437673f2b89bfe699ddf99cbcca2164ab2bc157c3e6cc89c8","cluster_key":"bf812b453f865756ade2813042f9e80b7f9429a9a3441c4fc687ac59a33289a5","clean_bundle":{"format":"clean-skill-bundle-v1","source":"agent-network-protocol/anp/skills/anp-multilang-release/SKILL.md","attachments":[{"id":"af403cb0-c085-5145-b244-f4473eec90c8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/af403cb0-c085-5145-b244-f4473eec90c8/attachment.yaml","path":"agents/openai.yaml","size":297,"sha256":"c9604568a8d3573a44a53bdd76e99b23dac5afe7928daf12188f773545de20e3","contentType":"application/yaml; charset=utf-8"},{"id":"187a58ab-b2d6-559e-8dfc-c65481aad44a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/187a58ab-b2d6-559e-8dfc-c65481aad44a/attachment.md","path":"references/release-policy.md","size":1398,"sha256":"f33cfecc6cf690d292627bb26971960481bc99d870cc4ccee9e3de20696417f5","contentType":"text/markdown; charset=utf-8"},{"id":"47939177-5b8f-5ef8-bf24-287a51a29cb9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/47939177-5b8f-5ef8-bf24-287a51a29cb9/attachment.py","path":"scripts/release.py","size":22221,"sha256":"c0342193c0e78888dcfb76e5a4ffb8f4518136f14264495bc4a81b408e960b56","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"33340a7c62e2f39ce6b2636f4374d165ddda81f9cc6cbb5388d3bbccf48e9d34","attachment_count":3,"text_attachments":3,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/anp-multilang-release/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"integrations-apis","category_label":"Integrations"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"integrations-apis","import_tag":"clean-skills-v1","description":"在 ANP SDK 仓库里统一发布 Go、Python、Rust 三个 SDK。用于同时更新 pyproject.toml、anp/__init__.py、uv.lock、rust/Cargo.toml、rust/Cargo.lock、golang/version.go,执行 uv/cargo/go 校验,发布 PyPI 与 crates.io,并按 Go 子目录 module 规则推送 golang/vX.Y.Z tag。用户提到 Go/Python/Rust 一起发版、统一版本号、固定发布 0.7.2、下一版自动 +1、保持版本段为一位数时使用此 skill。"}},"renderedAt":1782981375181}

ANP Multi SDK Release 在 仓库根目录执行统一发版。 优先使用脚本: 快速使用 本次固定发布 0.7.2 先看计划: 确认后正式发布: 下次自动递增版本 查看下一个版本号: 直接按自动版本发布: 版本规则 - 统一版本格式是 - 每一段都必须是单个数字 - 自动递增顺序: - - - - 不允许生成 这种两位数段 如果要改规则,先读 。 发布动作 脚本会按下面顺序执行: 1. 检查 Git 工作区是否干净 2. 检查 Python、Rust、锁文件版本是否一致 3. 更新: - - - - - - 4. 执行校验: - - - 5. 如果版本文件有变化,提交并推送分支 6. 发布 Python 包 7. 发布 Rust crate 8. 推送两个 tag: - 根 tag: ,例如 - Go tag: ,例如 Python 发布阶段会显式上传当前目标版本对应的 构件,避免把历史产物一并上传。 使用前提 发布前确保: - 当前仓库是 根目录 - Git remote 具备 push 权限 - 已经具备可用凭证 - 已经具备可用凭证 如果不是用 ,可以加: 处理异常 - 如果 tag 已存在,脚本会直接停止 - 如果版本文件不同步,脚本会直接停止 - 如果构建或发布失败,先修复问题,再重新执行 - 如果只是想查看动作,不要直接发版,先运行 ---