mcpField
T
temporary-id-safe-output

temporary-id-safe-output

github.com/github开发5.5k50 次安装今天更新
代码仓库

关于 temporary-id-safe-output

一项为 safe output 作业添加临时 issue ID 支持的开发技能,涵盖 ID 生成、跨工作流作业传递映射、引用解析,以及不中断其他处理的失败管理。

主要功能

  1. 01生成并验证临时 ID
  2. 02临时 ID 到 issue 编号的映射
  3. 03配置工作流依赖与环境变量
  4. 04替换文本中的临时 ID 引用
  5. 05以警告处理解析失败

适用场景

  1. 01将子 issue 链接到刚创建的父 issue
  2. 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 工作流临时 ID
  • XXXXXXXX 是长度为 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 中:

  1. 在构建函数中添加 createIssueJobName 参数:
func (c *Compiler) build<JobName>Job(data *WorkflowData, mainJobName string, createIssueJobName string) (*Job, error) {
  1. 添加环境变量以传递临时 ID 映射:
if createIssueJobName != "" {
    customEnvVars = append(customEnvVars, fmt.Sprintf("          GH_AW_TEMPORARY_ID_MAP: ${{ needs.%s.outputs.temporary_id_map }}\n", createIssueJobName))
}
  1. 将 create_issue 添加到任务的 needs 数组:
needs := []string{mainJobName}
if createIssueJobName != "" {
    needs = append(needs, createIssueJobName)
}
  1. 更新 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 中:

  1. 导入临时 ID 实用工具:
const { loadTemporaryIdMap, resolveIssueNumber } = require("./temporary_id.cjs");
  1. 在 main() 开始时加载临时 ID 映射:
const temporaryIdMap = loadTemporaryIdMap();
if (temporaryIdMap.size > 0) {
    core.info(`Loaded temporary ID map with ${temporaryIdMap.size} entries`);
}
  1. 使用 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}
执行流程
  1. main 任务:Agent 生成包含临时 ID aw_abc123 的输出
  2. create_issue 任务:创建问题 #100,并输出 {"aw_abc123": 100}
  3. link_sub_issue 任务:
    • 加载临时 ID 映射
    • 将 aw_abc123 解析为 100
    • 将问题 #42 和 #43 关联为 #100 的子问题

支持临时 ID 的任务

任务字段状态
link_sub_issueparent_issue_number、sub_issue_number✅ 已实现
add_commentissue_number(通过文本替换)✅ 已实现
update_issueissue_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 依赖项的情况下也能正常运行

安全注意事项

  1. 临时 ID 仅在单次工作流运行期间有效
  2. 映射通过环境变量传递(不会对外暴露)
  3. Agent 无法伪造临时 ID 来引用其他工作流中的问题
  4. 解析失败会记录日志,但不会暴露临时 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 依赖关系添加集成测试
  • 更新文档

评论

支持 Markdown