npx skills add https://github.com/alienfast/claude --skill 'PR Title and Description Generator'根据当前分支的实际变更生成或更新 PR 标题和描述。
仅记录代码最终状态中存在的内容,而非开发历史。
切勿在 bash 命令前添加注释行。 ~/.claude/settings.json 中的权限模式匹配命令的开头。开头的 # 注释 会破坏匹配并触发手动权限检查。请将描述放在 Bash 工具的 description 参数中。
如果一个功能在一个提交中添加,在另一个提交中移除,则它不应出现在 PR 描述中。在记录任何功能之前,始终验证它们是否存在于 HEAD 中。
git branch --show-current
# 获取 PR 信息,包括用于验证的状态
pr_info=$(gh pr view --json number,title,state,mergedAt,headRefName,baseRefName 2>/dev/null)
if [[ -n "$pr_info" ]]; then
# PR 存在 - 提取状态和元数据用于验证
pr_state=$(echo "$pr_info" | jq -r '.state // "UNKNOWN"')
pr_merged_at=$(echo "$pr_info" | jq -r '.mergedAt // "null"')
pr_number=$(echo "$pr_info" | jq -r '.number')
pr_title=$(echo "$pr_info" | jq -r '.title')
pr_head=$(echo "$pr_info" | jq -r '.headRefName')
pr_base=$(echo "$pr_info" | jq -r '.baseRefName')
# 安全修复 #4:验证 pr_state 是已知的 GitHub PR 状态(防止注入)
case "$pr_state" in
OPEN|CLOSED|MERGED|UNKNOWN)
# 有效状态,继续执行
;;
*)
echo "WARNING: Unexpected PR state from GitHub API: $pr_state" >&2
pr_state="UNKNOWN"
;;
esac
# 安全修复 #4:验证 pr_merged_at 是 "null" 或有效的 ISO 8601 时间戳
if [[ "$pr_merged_at" != "null" ]] && [[ ! "$pr_merged_at" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T ]]; then
echo "WARNING: Unexpected mergedAt format from GitHub API: $pr_merged_at" >&2
pr_merged_at="null"
fi
# 安全修复 #5:验证 pr_number 存在且是正整数
if [[ -z "$pr_number" ]] || [[ ! "$pr_number" =~ ^[0-9]+$ ]]; then
if [[ -n "$pr_info" ]]; then
echo "ERROR: PR data incomplete (missing or invalid PR number)" >&2
fi
pr_info="" # 视为不存在 PR
fi
fi
关键安全防护:在更新任何 PR 之前,验证其是否处于可安全修改的状态。
当 PR 存在时(pr_info 不为空):
步骤 1:检查 PR 是否为 OPEN 状态 - 可安全继续执行:
if [[ "$pr_state" == "OPEN" ]]; then
# 可安全继续执行正常更新工作流
# 继续步骤 2
fi
步骤 2:如果 PR 不是 OPEN 状态 - 停止并请求用户确认:
确定具体的非开放状态:
if [[ "$pr_state" == "MERGED" || "$pr_merged_at" != "null" ]]; then
pr_status_type="MERGED"
pr_status_detail="已合并"
pr_status_note="注意:更新已合并的 PR 只会更改其历史记录,而不会更改代码。"
elif [[ "$pr_state" == "CLOSED" ]]; then
pr_status_type="CLOSED"
pr_status_detail="已关闭但未合并"
pr_status_note="更新已关闭的 PR 是不常见的。大多数情况下应该创建一个新的 PR。"
else
pr_status_type="UNKNOWN"
pr_status_detail="处于不明确状态 ($pr_state)"
pr_status_note="无法安全验证 PR 状态。建议手动调查。"
fi
步骤 3:向用户显示确认提示:
停止执行并显示此消息(用实际值替换变量):
⚠️ **PR 状态警告**
检测到的拉取请求状态为 **{pr_status_type}**:
- **PR**: #{pr_number} - {pr_title}
- **分支**: {pr_head} → {pr_base}
- **状态**: {pr_status_detail}
**选项:**
1. **创建新 PR** - 为这些变更打开一个新的拉取请求(大多数情况推荐)
2. **仍然更新 {pr_status_type} PR** - 修改 PR 的标题/描述(很少需要)
3. **取消** - 停止而不做任何更改
{pr_status_note}
**您希望执行什么操作?**
步骤 4:等待明确的用户响应并验证输入:
# 读取用户选择
read -p "Enter your choice (1, 2, or 3): " user_choice
# 安全修复 #2:验证输入恰好是 1、2 或 3
if [[ ! "$user_choice" =~ ^[123]$ ]]; then
echo "Invalid choice. Please enter 1, 2, or 3." >&2
exit 1
fi
步骤 5:根据验证后的输入处理用户选择:
case "$user_choice" in
1)
# 选项 1:创建新 PR
pr_info=""
echo "Creating new PR instead..."
;;
2)
# 选项 2:仍然更新
user_confirmed_update="true"
echo "Proceeding with update to $pr_status_type PR..."
;;
3)
# 选项 3:取消
user_cancelled="true"
echo "PR update cancelled by user. No changes made."
exit 0
;;
esac
关于交互式与非交互式处理的说明:
如果将此技能实现为非交互式脚本,Claude 应直接处理用户的口头选择,而无需提示:
pr_info=""user_confirmed_update="true"当没有 PR 存在时(pr_info 为空): 完全跳过验证 - 技能将创建一个新的 PR(正常工作流)。
API 失败处理: 如果 gh pr view 返回的错误不是"未找到拉取请求",则视为 UNKNOWN 状态,并在继续之前询问用户。
获取提交数量:
git log main..HEAD --oneline | wc -l
获取文件变更摘要:
git diff main...HEAD --stat
识别主要变更领域:
git diff main...HEAD --name-only | cut -d/ -f1 | sort | uniq -c | sort -rn
生成分类的行数统计明细,以量化 PR 的影响。此部分帮助审阅者快速理解变更的范围和性质。
步骤 1:获取原始总计(包含重命名检测):
git diff --shortstat -M main...HEAD
步骤 2:使用 git diff --numstat 按用途分类:
git diff --numstat -M main...HEAD | awk '{if ($3 ~ /lock\.yaml$|lock\.json$|\.lock$/) next; added+=$1; removed+=$2; file=$3; if (file ~ /\.stories\./) {sa+=$1; sr+=$2} else if (file ~ /mock|Mock/) {ma+=$1; mr+=$2} else if (file ~ /generated|packages\/graphql\//) {ga+=$1; gr+=$2} else if (file ~ /ops\//) {oa+=$1; or+=$2} else if (file ~ /\.(yml|yaml|json|css|scss|svg|md)$/) {la+=$1; lr+=$2} else {ca+=$1; cr+=$2}} END {printf "%-20s %8s %8s %8s\n", "Category", "Added", "Removed", "Net"; printf "%-20s %8d %8d %8d\n", "App code", ca, cr, ca-cr; printf "%-20s %8d %8d %8d\n", "Stories", sa, sr, sa-sr; printf "%-20s %8d %8d %8d\n", "Mocks", ma, mr, ma-mr; printf "%-20s %8d %8d %8d\n", "Generated", ga, gr, ga-gr; printf "%-20s %8d %8d %8d\n", "Ops/Infra", oa, or, oa-or; printf "%-20s %8d %8d %8d\n", "Config/Assets", la, lr, la-lr; printf "%-20s %8d %8d %8d\n", "TOTAL", added, removed, added-removed}'
注意事项:
-M 标志进行重命名检测(防止因文件重命名导致计数膨胀)\.stories\. — Storybook 故事文件mock|Mock — 测试模拟文件generated|packages\/graphql\/ — 生成的代码(GraphQL 代码生成等)ops\/ — 基础设施/运维文件lock\.yaml$|lock\.json$|\.lock$ — 锁定文件(完全跳过)\.(yml|yaml|json|css|scss|svg|md)$ — 配置、本地化文件、样式、资源cloc 可用,cloc --diff main HEAD --git 提供了另一种按语言划分的明细,但缺乏分类且不处理重命名将结果表格包含在 PR 描述的 代码影响 部分下。
关键:对于每个明显的变更领域,验证其是否存在于最终状态中:
检查功能是否存在于最终代码中:
git show HEAD:path/to/file.ts | grep -q "feature_name" && echo "PRESENT" || echo "REMOVED"
示例 — 检查身份验证插件:
git show HEAD:cloud/database/src/SqlDatabase.ts | grep "authentication_plugin"
示例 — 检查函数是否存在:
git show HEAD:src/utils.ts | grep -A10 "function myFunction"
如果一个功能未出现在最终状态中,请勿将其包含在 PR 描述中。
根据实际存在的内容将变更组织到类别中:
对于每个变更领域:
git show HEAD:path/to/file 进行确认[filename.ts](path/to/filename.ts)[filename.ts:42](path/to/filename.ts#L42)[filename.ts:42-51](path/to/filename.ts#L42-L51)在最终确定描述之前,验证:
git show HEAD:path/to/file 中有关全面的标题格式示例和模式,请参阅 resources/title-patterns.md。
快速参考:
避免使用模糊的标题,如"PR deployment"、"Various fixes"或"Update code"。
有关详细模板,请参阅:
使用此通用模板结构:
## 摘要
[1-2 句话概述此 PR 实现的内容及原因]
## [主要类别 1 - 例如:基础设施变更]
### [子类别 - 例如:Cloud SQL Enterprise Plus]
**[功能名称]:**
- [在 HEAD 中验证的实现细节]
- [带有实际值的配置细节]
- [收益或影响]
**实现:**
- 文件: [链接到主文件](path/to/file.ts)
- 配置: [链接到配置](path/to/config.yaml)
**Stack 命令:**
- `./stack command_name` - 描述
**文档:**
- [链接到相关文档](doc/path/to/doc.md)
[为每个主要类别重复此结构]
## 代码影响
| 类别 | 新增 | 删除 | 净增 |
|---|---|---|---|
| App code | X | X | X |
| Stories | X | X | X |
| Mocks | X | X | X |
| Generated | X | X | X |
| Ops/Infra | X | X | X |
| Config/Assets | X | X | X |
| **总计** | **X** | **X** | **X** |
[1-2 句话解释数字的含义 — 例如:"通过 Y,生产代码减少了 X 行。净增长由新的测试覆盖率驱动。"]
## 破坏性变更
### [受影响的领域]
- **变更内容**: [具体变更]
- **迁移**: [迁移步骤]
- **影响**: [受影响的对象/内容]
## 依赖项
- 更新 `package-name` 到版本 X.Y.Z
- 添加 `new-package` 用于 [特定目的]
- 移除 `old-package`(不再需要)
## 测试
**[测试类别]:**
- ✅ [验证变更的具体测试]
- ✅ [另一个具体测试]
- ✅ [集成测试描述]
**[另一个测试类别]:**
- ✅ [测试描述]
## 成本影响
[如果适用 - 基础设施成本变更]
**生产环境:**
- 当前: $X/月
- 计划: $Y/月(通过优化 Z)
- 收益: [SLA/性能/可靠性改进]
**[环境]:**
- 基础: $X/月(共享基础设施)
- 每 [单位]: +$Y/月
---
🤖 由 [Claude Code](https://claude.com/claude-code) 生成
Co-Authored-By: Claude <noreply@anthropic.com>
有关如何分析和验证 PR 变更的逐步示例,请参阅 resources/analysis-workflow.md。
您也可以使用验证脚本:
检查功能是否存在于最终状态:
./scripts/verify-feature.sh path/to/file.ts "feature_name"
检查文件是否存在:
./scripts/verify-feature.sh packages/api/README.md ""
git show HEAD:file 确认功能存在于最终状态# 提交历史显示:
# - 提交 A:添加功能 X
# - 提交 B:移除功能 X
# 最终状态:没有功能 X
# 错误:"添加了功能 X"
# 正确:完全不提及功能 X
# 错误:"更新了数据库配置"
# 正确:"为 Cloud SQL Proxy v2 兼容性设置 default_authentication_plugin 为 mysql_native_password"
# 错误:假设功能存在,因为您在提交消息中看到了它
# 正确:git show HEAD:path/to/file.ts | grep "feature_name"
# 错误:[config.ts](/Users/kross/project/src/config.ts)
# 正确:[config.ts](src/config.ts)
安全修复 #1 - 命令注入防护:生成 title 和 description 变量时,确保使用正确的引号进行赋值以防止命令注入:
安全赋值(使用引号):
title="Generated title text"
description="$(cat <<'EOF'
Multi-line description
EOF
)"
不安全 — 切勿这样做:title=$(some_command) 不加引号可能会在标题中执行命令。
使用 GitHub CLI 更新 PR。
更新前状态验证(防止 TOCTOU 竞态条件)— 在更新前立即重新检查 PR 状态:
if [[ -n "$pr_number" ]]; then
current_pr_info=$(gh pr view "$pr_number" --json state 2>/dev/null)
if [[ -n "$current_pr_info" ]]; then
current_state=$(echo "$current_pr_info" | jq -r '.state // "UNKNOWN"')
# 验证状态自初始检查以来未发生变化
if [[ "$current_state" != "$pr_state" ]]; then
echo "ERROR: PR state changed during processing" >&2
echo " Initial state: $pr_state" >&2
echo " Current state: $current_state" >&2
echo " Aborting update to prevent unintended modification" >&2
exit 1
fi
else
echo "ERROR: PR no longer exists (may have been deleted)" >&2
exit 1
fi
fi
if [[ "$user_cancelled" == "true" ]]; then
echo "ERROR: Attempted to continue after user cancellation" >&2
exit 1
fi
if [[ "$pr_state" != "OPEN" ]] && [[ "$user_confirmed_update" != "true" ]]; then
echo "ERROR: Attempted to update non-open PR #$pr_number (state: $pr_state) without user confirmation."
echo "This indicates a bug in the PR state validation logic."
exit 1
fi
gh pr edit <number> --title "Your Title Here" --body "$(cat <<'EOF'
[Your full description here]
EOF
)"
确认更新成功:
gh pr view <number>
每周安装次数
0
仓库
首次出现
Jan 1, 1970
安全审计
Generate or update a PR title and description based on the actual changes in the current branch.
Document ONLY what exists in the final state of the code, not the development history.
NEVER prefix bash commands with comment lines. Permission patterns in ~/.claude/settings.json match against the start of the command. A leading # comment breaks the match and triggers a manual permission check. Put descriptions in the Bash tool's description parameter instead.
If a feature was added in one commit and removed in another, it should NOT be in the PR description. Always verify features exist in HEAD before documenting them.
git branch --show-current
# Fetch PR information including state for validation
pr_info=$(gh pr view --json number,title,state,mergedAt,headRefName,baseRefName 2>/dev/null)
if [[ -n "$pr_info" ]]; then
# PR exists - extract state and metadata for validation
pr_state=$(echo "$pr_info" | jq -r '.state // "UNKNOWN"')
pr_merged_at=$(echo "$pr_info" | jq -r '.mergedAt // "null"')
pr_number=$(echo "$pr_info" | jq -r '.number')
pr_title=$(echo "$pr_info" | jq -r '.title')
pr_head=$(echo "$pr_info" | jq -r '.headRefName')
pr_base=$(echo "$pr_info" | jq -r '.baseRefName')
# Security Fix #4: Validate pr_state is a known GitHub PR state (prevent injection)
case "$pr_state" in
OPEN|CLOSED|MERGED|UNKNOWN)
# Valid state, proceed
;;
*)
echo "WARNING: Unexpected PR state from GitHub API: $pr_state" >&2
pr_state="UNKNOWN"
;;
esac
# Security Fix #4: Validate pr_merged_at is either "null" or valid ISO 8601 timestamp
if [[ "$pr_merged_at" != "null" ]] && [[ ! "$pr_merged_at" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T ]]; then
echo "WARNING: Unexpected mergedAt format from GitHub API: $pr_merged_at" >&2
pr_merged_at="null"
fi
# Security Fix #5: Validate pr_number is present and is a positive integer
if [[ -z "$pr_number" ]] || [[ ! "$pr_number" =~ ^[0-9]+$ ]]; then
if [[ -n "$pr_info" ]]; then
echo "ERROR: PR data incomplete (missing or invalid PR number)" >&2
fi
pr_info="" # Treat as no PR exists
fi
fi
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
CRITICAL SAFEGUARD : Before updating any PR, verify it is in a safe state to modify.
When PR exists (pr_info is not empty):
Step 1: Check if PR is OPEN - safe to proceed immediately:
if [[ "$pr_state" == "OPEN" ]]; then
# Safe to proceed with normal update workflow
# Continue to Step 2
fi
Step 2: If PR is NOT OPEN - stop and ask user for confirmation:
Determine the specific non-open state:
if [[ "$pr_state" == "MERGED" || "$pr_merged_at" != "null" ]]; then
pr_status_type="MERGED"
pr_status_detail="merged"
pr_status_note="Note: Updating a merged PR only changes its historical record, not the code."
elif [[ "$pr_state" == "CLOSED" ]]; then
pr_status_type="CLOSED"
pr_status_detail="closed without merging"
pr_status_note="Updating a closed PR is unusual. Most cases should create a new PR instead."
else
pr_status_type="UNKNOWN"
pr_status_detail="in an unclear state ($pr_state)"
pr_status_note="Cannot verify PR state safely. Manual investigation recommended."
fi
Step 3: Present confirmation prompt to user :
Stop execution and display this message (substitute variables with actual values):
⚠️ **PR State Warning**
The detected pull request is **{pr_status_type}**:
- **PR**: #{pr_number} - {pr_title}
- **Branch**: {pr_head} → {pr_base}
- **State**: {pr_status_detail}
**Options:**
1. **Create new PR** - Open a fresh pull request for these changes (recommended for most cases)
2. **Update {pr_status_type} PR anyway** - Modify the PR's title/description (rarely needed)
3. **Cancel** - Stop without making changes
{pr_status_note}
**What would you like to do?**
Step 4: Wait for explicit user response and validate input :
# Read user choice
read -p "Enter your choice (1, 2, or 3): " user_choice
# Security Fix #2: Validate input is exactly 1, 2, or 3
if [[ ! "$user_choice" =~ ^[123]$ ]]; then
echo "Invalid choice. Please enter 1, 2, or 3." >&2
exit 1
fi
Step 5: Handle user choice based on validated input :
case "$user_choice" in
1)
# Option 1: Create new PR
pr_info=""
echo "Creating new PR instead..."
;;
2)
# Option 2: Update anyway
user_confirmed_update="true"
echo "Proceeding with update to $pr_status_type PR..."
;;
3)
# Option 3: Cancel
user_cancelled="true"
echo "PR update cancelled by user. No changes made."
exit 0
;;
esac
Note on Interactive vs Non-Interactive Handling :
If implementing this skill as a non-interactive script, Claude should directly handle the user's verbal choice without prompting:
pr_info=""user_confirmed_update="true"When no PR exists (pr_info is empty): Skip validation entirely - the skill will create a new PR (normal workflow).
API Failure Handling: If gh pr view returns an error OTHER than "no pull requests found", treat as UNKNOWN state and ask user before proceeding.
Get commit count:
git log main..HEAD --oneline | wc -l
Get file change summary:
git diff main...HEAD --stat
Identify major areas of change:
git diff main...HEAD --name-only | cut -d/ -f1 | sort | uniq -c | sort -rn
Generate a categorized line-count breakdown to quantify the PR's impact. This section helps reviewers quickly understand the scope and nature of changes.
Step 1: Get the raw totals (with rename detection):
git diff --shortstat -M main...HEAD
Step 2: Categorize by purpose using git diff --numstat:
git diff --numstat -M main...HEAD | awk '{if ($3 ~ /lock\.yaml$|lock\.json$|\.lock$/) next; added+=$1; removed+=$2; file=$3; if (file ~ /\.stories\./) {sa+=$1; sr+=$2} else if (file ~ /mock|Mock/) {ma+=$1; mr+=$2} else if (file ~ /generated|packages\/graphql\//) {ga+=$1; gr+=$2} else if (file ~ /ops\//) {oa+=$1; or+=$2} else if (file ~ /\.(yml|yaml|json|css|scss|svg|md)$/) {la+=$1; lr+=$2} else {ca+=$1; cr+=$2}} END {printf "%-20s %8s %8s %8s\n", "Category", "Added", "Removed", "Net"; printf "%-20s %8d %8d %8d\n", "App code", ca, cr, ca-cr; printf "%-20s %8d %8d %8d\n", "Stories", sa, sr, sa-sr; printf "%-20s %8d %8d %8d\n", "Mocks", ma, mr, ma-mr; printf "%-20s %8d %8d %8d\n", "Generated", ga, gr, ga-gr; printf "%-20s %8d %8d %8d\n", "Ops/Infra", oa, or, oa-or; printf "%-20s %8d %8d %8d\n", "Config/Assets", la, lr, la-lr; printf "%-20s %8d %8d %8d\n", "TOTAL", added, removed, added-removed}'
Notes:
-M flag for rename detection (prevents inflated counts from file renames)\.stories\. — Storybook story filesmock|Mock — Test mocksgenerated|packages\/graphql\/ — Generated code (GraphQL codegen, etc.)ops\/ — Infrastructure/operationslock\.yaml$|lock\.json$|\.lock$ — Lock files (skipped entirely)\.(yml|yaml|json|css|scss|svg|md)$ — Config, locales, styles, assetscloc is available, cloc --diff main HEAD --git provides an alternative per-language breakdown, but lacks categorization and doesn't handle renamesInclude the resulting table in the PR description under a Code Impact section.
CRITICAL : For each area of apparent change, verify if it's in the final state:
Check if a feature is in final code:
git show HEAD:path/to/file.ts | grep -q "feature_name" && echo "PRESENT" || echo "REMOVED"
Example — check for authentication plugin:
git show HEAD:cloud/database/src/SqlDatabase.ts | grep "authentication_plugin"
Example — check if a function exists:
git show HEAD:src/utils.ts | grep -A10 "function myFunction"
If a feature doesn't appear in the final state, DO NOT include it in the PR description.
Organize changes into categories based on what's actually present:
For each change area:
git show HEAD:path/to/file to confirm[filename.ts](path/to/filename.ts)[filename.ts:42](path/to/filename.ts#L42)[filename.ts:42-51](path/to/filename.ts#L42-L51)Before finalizing the description, verify:
git show HEAD:path/to/fileSee resources/title-patterns.md for comprehensive title format examples and patterns.
Quick reference:
Avoid vague titles like "PR deployment", "Various fixes", or "Update code".
For detailed templates, see:
Use this general template structure:
## Summary
[1-2 sentence overview of what this PR accomplishes and why]
## [Major Category 1 - e.g., Infrastructure Changes]
### [Subcategory - e.g., Cloud SQL Enterprise Plus]
**[Feature Name]:**
- [Implementation detail verified in HEAD]
- [Configuration detail with actual values]
- [Benefit or impact]
**Implementation:**
- File: [link to main file](path/to/file.ts)
- Configuration: [link to config](path/to/config.yaml)
**Stack Commands:**
- `./stack command_name` - Description
**Documentation:**
- [Link to relevant docs](doc/path/to/doc.md)
[Repeat structure for each major category]
## Code Impact
| Category | Added | Removed | Net |
|---|---|---|---|
| App code | X | X | X |
| Stories | X | X | X |
| Mocks | X | X | X |
| Generated | X | X | X |
| Ops/Infra | X | X | X |
| Config/Assets | X | X | X |
| **Total** | **X** | **X** | **X** |
[1-2 sentence interpretation of what the numbers mean — e.g., "Production code reduced by X lines through Y. Net increase driven by new test coverage."]
## Breaking Changes
### [Area Affected]
- **What changed**: [Specific change]
- **Migration**: [Steps to migrate]
- **Impact**: [Who/what is affected]
## Dependencies
- Updated `package-name` to version X.Y.Z
- Added `new-package` for [specific purpose]
- Removed `old-package` (no longer needed)
## Testing
**[Test Category]:**
- ✅ [Specific test that validates the change]
- ✅ [Another specific test]
- ✅ [Integration test description]
**[Another Test Category]:**
- ✅ [Test description]
## Cost Impact
[If applicable - infrastructure cost changes]
**Production:**
- Current: $X/month
- Planned: $Y/month (with optimization Z)
- Benefit: [SLA/performance/reliability improvements]
**[Environment]:**
- Base: $X/month (shared infrastructure)
- Per-[unit]: +$Y/month
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
For step-by-step examples of how to analyze and verify PR changes, see resources/analysis-workflow.md.
You can also use the verification script:
Check if a feature exists in final state:
./scripts/verify-feature.sh path/to/file.ts "feature_name"
Check if a file exists:
./scripts/verify-feature.sh packages/api/README.md ""
git show HEAD:file to confirm features exist in final state# Commit history shows:
# - Commit A: Add feature X
# - Commit B: Remove feature X
# Final state: No feature X
# WRONG: "Added feature X"
# RIGHT: Don't mention feature X at all
# WRONG: "Updated database configuration"
# RIGHT: "Set default_authentication_plugin to mysql_native_password for Cloud SQL Proxy v2 compatibility"
# WRONG: Assume a feature exists because you saw it in commit messages
# RIGHT: git show HEAD:path/to/file.ts | grep "feature_name"
# WRONG: [config.ts](/Users/kross/project/src/config.ts)
# RIGHT: [config.ts](src/config.ts)
Security Fix #1 - Command Injection Prevention : When generating title and description variables, ensure they are assigned using proper quoting to prevent command injection:
Safe assignment (use quotes):
title="Generated title text"
description="$(cat <<'EOF'
Multi-line description
EOF
)"
UNSAFE — never do this: title=$(some_command) without quotes could execute commands in the title.
Update the PR using GitHub CLI.
Pre-Update State Verification (prevent TOCTOU race condition) — re-check PR state immediately before update:
if [[ -n "$pr_number" ]]; then
current_pr_info=$(gh pr view "$pr_number" --json state 2>/dev/null)
if [[ -n "$current_pr_info" ]]; then
current_state=$(echo "$current_pr_info" | jq -r '.state // "UNKNOWN"')
# Verify state hasn't changed since initial check
if [[ "$current_state" != "$pr_state" ]]; then
echo "ERROR: PR state changed during processing" >&2
echo " Initial state: $pr_state" >&2
echo " Current state: $current_state" >&2
echo " Aborting update to prevent unintended modification" >&2
exit 1
fi
else
echo "ERROR: PR no longer exists (may have been deleted)" >&2
exit 1
fi
fi
if [[ "$user_cancelled" == "true" ]]; then
echo "ERROR: Attempted to continue after user cancellation" >&2
exit 1
fi
if [[ "$pr_state" != "OPEN" ]] && [[ "$user_confirmed_update" != "true" ]]; then
echo "ERROR: Attempted to update non-open PR #$pr_number (state: $pr_state) without user confirmation."
echo "This indicates a bug in the PR state validation logic."
exit 1
fi
gh pr edit <number> --title "Your Title Here" --body "$(cat <<'EOF'
[Your full description here]
EOF
)"
Confirm the update was successful:
gh pr view <number>
Weekly Installs
0
Repository
First Seen
Jan 1, 1970
Security Audits
agent-browser 浏览器自动化工具 - Vercel Labs 命令行网页操作与测试
150,000 周安装
Conventional Commit规范提交助手 - GitHub Copilot自动生成标准化提交信息
8,500 周安装
SQL性能优化助手 - 专业SQL查询调优与索引策略优化工具
8,600 周安装
Vue Router 最佳实践指南:导航守卫、路由生命周期与常见陷阱解决方案
9,200 周安装
后台代理状态通知 - 避免轮询浪费,高效处理AI代理进度更新
205 周安装
网站设计审查工具 - 自动检测并修复HTML/CSS/JS、React、Vue等框架的视觉与布局问题
8,900 周安装
.NET/C# 最佳实践指南:代码规范、设计模式、依赖注入与AI集成
8,900 周安装