关于 temporary-id-safe-output
一项为 safe output 作业添加临时 issue ID 支持的开发技能,涵盖 ID 生成、跨工作流作业传递映射、引用解析,以及不中断其他处理的失败管理。
主要功能
- 01生成并验证临时 ID
- 02临时 ID 到 issue 编号的映射
- 03配置工作流依赖与环境变量
- 04替换文本中的临时 ID 引用
- 05以警告处理解析失败
适用场景
- 01将子 issue 链接到刚创建的父 issue
- 02为 safe output 作业添加临时 ID 支持
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ github/ gh-aw --skill temporary-id-safe-output安装后在 Claude Code 中输入/temporary-id-safe-output确认已加载。
详细介绍
为安全输出任务添加临时 ID 支持
使用此实施计划为安全输出任务添加临时 ID 支持。临时 ID 可让 Agent 在同一次运行中引用新创建的问题,而无需等待真实问题编号生成。
问题描述
当 Agent 创建父问题后,立即在同一次运行中关联子问题时,在 create_issue 执行完成前,它不知道真实的问题编号。临时 ID 通过占位符解决这一问题,并在执行时解析占位符。
临时 ID 格式
临时 ID 遵循 aw_[A-Za-z0-9]{3,8} 模式,其中:
aw_是固定前缀,用于标识 Agent 工作流临时 IDXXXXXXXX是长度为 3–8 个字符的字母数字字符串(A-Za-z0-9)
示例:aw_abc、aw_abc123、aw_Test123
实施组件
1. 共享模块:temporary_id.cjs
位置:pkg/workflow/js/temporary_id.cjs
此模块提供临时 ID 处理的共享实用工具:
// Core functions
generateTemporaryId() // Generate new temporary ID
isTemporaryId(value) // Check if value is a temporary ID
normalizeTemporaryId(tempId) // Normalize to lowercase for map lookups
loadTemporaryIdMap() // Load map from GH_AW_TEMPORARY_ID_MAP env var
resolveIssueNumber(value, map) // Resolve value to issue number (supports temp IDs)
replaceTemporaryIdReferences(text, map) // Replace #aw_XXX references in text
2. 生成任务:create_issue
create_issue 任务会输出临时 ID 映射,供其他任务使用:
Go 更改(pkg/workflow/create_issue.go):
- 无需更改——已输出
temporary_id_map
JavaScript 更改(pkg/workflow/js/create_issue.cjs):
- 为每个创建的问题生成临时 ID
- 构建
temporary_id -> issue_number映射 - 通过
core.setOutput("temporary_id_map", JSON.stringify(map))输出映射
3. 消费任务:添加临时 ID 支持
对于每个需要解析临时 ID 的安全输出任务:
步骤 1:更新 Go 任务构建器
在 pkg/workflow/<job_name>.go 中:
- 在构建函数中添加
createIssueJobName参数:
func (c *Compiler) build<JobName>Job(data *WorkflowData, mainJobName string, createIssueJobName string) (*Job, error) {
- 添加环境变量以传递临时 ID 映射:
if createIssueJobName != "" {
customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_TEMPORARY_ID_MAP: ${{ needs.%s.outputs.temporary_id_map }}\n", createIssueJobName))
}
- 将
create_issue添加到任务的needs数组:
needs := []string{mainJobName}
if createIssueJobName != "" {
needs = append(needs, createIssueJobName)
}
- 更新
SafeOutputJobConfig,使其使用动态needs:
return c.buildSafeOutputJob(data, SafeOutputJobConfig{
// ...
Needs: needs,
// ...
})
步骤 2:更新编译器任务
在 pkg/workflow/compiler_jobs.go 中:
构建任务时传入 createIssueJobName:
job, err := c.build<JobName>Job(data, mainJobName, createIssueJobName)
步骤 3:更新 JavaScript 脚本
在 pkg/workflow/js/<job_name>.cjs 中:
- 导入临时 ID 实用工具:
const { loadTemporaryIdMap, resolveIssueNumber } = require("./temporary_id.cjs");
- 在 main() 开始时加载临时 ID 映射:
const temporaryIdMap = loadTemporaryIdMap();
if (temporaryIdMap.size > 0) {
core.info(`Loaded temporary ID map with ${temporaryIdMap.size} entries`);
}
- 使用
resolveIssueNumber()解析问题编号:
const resolved = resolveIssueNumber(item.issue_number, temporaryIdMap);
if (resolved.errorMessage) {
core.warning(`Failed to resolve issue: ${resolved.errorMessage}`);
continue;
}
const issueNumber = resolved.resolved;
if (resolved.wasTemporaryId) {
core.info(`Resolved temporary ID '${item.issue_number}' to issue #${issueNumber}`);
}
步骤 4:更新 Agent 输入验证
在 pkg/workflow/js/collect_ndjson_output.cjs 中:
为接受临时 ID 的字段添加验证:
function isValidIssueNumberOrTemporaryId(value) {
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
return true;
}
if (typeof value === "string" && /^aw_[0-9a-f]{12}$/i.test(value)) {
return true;
}
return false;
}
对 parent_issue_number、sub_issue_number 等字段使用此验证。
4. 失败处理
临时 ID 解析失败时,任务应:
- 使用
core.warning()记录警告,而不是使用core.setFailed()报错 - 继续处理其他项目
- 在步骤摘要中包含失败信息
- 带警告成功完成
这样可以确保:
- 支持部分成功(部分关联可能成功,其他关联可能失败)
- 工作流不会因单次解析失败而彻底失败
- 用户可以在步骤摘要中查看警告
使用示例
工作流配置
safe-outputs:
create-issue:
title-prefix: "[Parent] "
labels: [tracking]
max: 3
link-sub-issue:
max: 10
Agent 输出
{"type": "create_issue", "temporary_id": "aw_abc123", "title": "Parent: Feature X", "body": "..."}
{"type": "link_sub_issue", "parent_issue_number": "aw_abc123", "sub_issue_number": 42}
{"type": "link_sub_issue", "parent_issue_number": "aw_abc123", "sub_issue_number": 43}
执行流程
main任务:Agent 生成包含临时 IDaw_abc123的输出create_issue任务:创建问题 #100,并输出{"aw_abc123": 100}link_sub_issue任务:- 加载临时 ID 映射
- 将
aw_abc123解析为100 - 将问题 #42 和 #43 关联为 #100 的子问题
支持临时 ID 的任务
| 任务 | 字段 | 状态 |
|---|---|---|
link_sub_issue | parent_issue_number、sub_issue_number | ✅ 已实现 |
add_comment | issue_number(通过文本替换) | ✅ 已实现 |
update_issue | issue_number | 🔄 可添加 |
close_pull_request | - | N/A(使用 PR 编号) |
测试
单元测试
在 pkg/workflow/js/temporary_id.test.cjs 中添加以下测试:
- 使用有效和无效输入测试
isTemporaryId() - 使用临时 ID 和常规编号测试
resolveIssueNumber() - 使用各种 JSON 输入测试
loadTemporaryIdMap()
集成测试
在 pkg/workflow/<job_name>_dependencies_test.go 中添加测试,以验证:
- 按配置添加
create_issue到 Job 的 needs 中 - 正确设置
GH_AW_TEMPORARY_ID_MAP环境变量 - Job 在没有
create_issue依赖项的情况下也能正常运行
安全注意事项
- 临时 ID 仅在单次工作流运行期间有效
- 映射通过环境变量传递(不会对外暴露)
- Agent 无法伪造临时 ID 来引用其他工作流中的问题
- 解析失败会记录日志,但不会暴露临时 ID 映射的内容
为新 Job 添加支持的检查清单
- 更新 Go Job 构建器,使其接受
createIssueJobName参数 - 添加
GH_AW_TEMPORARY_ID_MAP环境变量 - 更新 needs 数组,以便有条件地包含
create_issue - 更新
compiler_jobs.go,以传递createIssueJobName - 在 JavaScript 脚本中导入临时 ID 工具
- 对问题编号字段使用
resolveIssueNumber() - 根据需要更新
collect_ndjson_output.cjs中的验证逻辑 - 为解析逻辑添加单元测试
- 为 Job 依赖关系添加集成测试
- 更新文档