状态同步技能Skill skill-status-sync

这是一个用于原子性地更新任务状态,跨TODO.md和state.json文件的独立技能。它提供preflight_update、postflight_update和artifact_link操作,确保数据一致性,适用于手动状态修正和恢复操作。关键词:任务状态同步、原子更新、TODO.md、state.json、Bash脚本、jq工具、文件编辑。

DevOps 0 次安装 0 次浏览 更新于 3/22/2026

name: skill-status-sync description: 原子性地更新任务状态,跨 TODO.md 和 state.json。仅供独立使用。 allowed-tools: Bash, Edit, Read, Read(/tmp/.json), Bash(rm:)

状态同步技能(直接执行)

用于原子状态同步的直接执行技能,跨 TODO.md 和 state.json。此技能内联执行,无需生成子代理,避免内存问题。

上下文参考

参考(不急切加载):

  • 路径:.opencode/context/core/patterns/jq-escaping-workarounds.md - jq 转义模式(问题 #1132)

仅供独立使用

重要:此技能仅供独立使用。

工作流技能(skill-researcher、skill-planner、skill-implementer 等)现在内联处理自己的预检/后检状态更新。这消除了多技能暂停边界问题,即 Claude 可能在技能调用之间暂停。

使用此技能用于

  • 手动任务状态修正
  • 需要更新任务状态的独立脚本
  • 工作流技能失败时的恢复操作
  • 隔离测试状态更新行为

不要在 workflow commands 中使用此技能(/research、/plan、/implement、/revise)— 这些命令现在调用处理自己状态更新的单个技能。

触发条件

此技能在以下情况下激活:

  • 需要手动状态修正
  • 需要在正常工作流之外链接工件
  • 需要在 TODO.md 和 state.json 之间进行状态同步恢复

API 操作

此技能提供三个主要操作:

操作 目的 使用时机
preflight_update 设置进行中状态 GATE IN 检查点
postflight_update 设置最终状态 + 链接工件 GATE OUT 检查点
artifact_link 添加工件链接(幂等) 工件创建后

执行

1. 输入验证

根据操作类型验证必需输入:

对于 preflight_update

  • task_number - 必须提供并存在于 state.json 中
  • target_status - 必须是进行中变体(researching、planning、implementing)
  • session_id - 必须提供以用于跟踪

对于 postflight_update

  • task_number - 必须提供并存在
  • target_status - 必须是最终变体(researched、planned、implemented、partial)
  • artifacts - 要链接的 {path, type} 数组
  • session_id - 必须提供

对于 artifact_link

  • task_number - 必须提供并存在
  • artifact_path - 工件的相对路径
  • artifact_type - 其中之一:research、plan、summary

2. 直接执行操作

使用 Bash(jq)和 Edit 工具路由到适当操作并执行。


操作:preflight_update

目的:在 GATE IN 检查点设置进行中状态

执行

  1. 验证任务存在
task_data=$(jq -r --arg num "{task_number}" \
  '.active_projects[] | select(.project_number == ($num | tonumber))' \
  specs/state.json)

if [ -z "$task_data" ]; then
  echo "Error: Task {task_number} not found"
  exit 1
fi
  1. 更新 state.json
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg status "{target_status}" \
  '(.active_projects[] | select(.project_number == {task_number})) |= . + {
    status: $status,
    last_updated: $ts
  }' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
  1. 更新 TODO.md 状态标记
    • 查找任务条目:grep -n "^### {task_number}\." specs/TODO.md
    • 使用 Edit 工具将 [OLD_STATUS] 更改为 [NEW_STATUS]

状态映射

state.json TODO.md
not_started [NOT STARTED]
researching [RESEARCHING]
planning [PLANNING]
implementing [IMPLEMENTING]

返回:带有状态 “synced” 和前/新状态字段的 JSON 对象。


操作:postflight_update

目的:在 GATE OUT 检查点设置最终状态并链接工件

执行

  1. 更新 state.json 状态和时间戳
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg status "{target_status}" \
  '(.active_projects[] | select(.project_number == {task_number})) |= . + {
    status: $status,
    last_updated: $ts
  }' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
  1. 将工件添加到 state.json(对于每个工件):

重要:使用两步 jq 模式避免问题 #1132 的转义错误。参见 jq-escaping-workarounds.md

# 步骤 1:更新时间戳
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  '(.active_projects[] | select(.project_number == {task_number})) |= . + {
    last_updated: $ts
  }' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json

# 步骤 2:添加工件(附加到数组)
jq --arg path "{artifact_path}" \
   --arg type "{artifact_type}" \
  '(.active_projects[] | select(.project_number == {task_number})).artifacts += [{"path": $path, "type": $type}]' \
  specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
  1. 更新 TODO.md 状态标记

    • 使用 Edit 更改状态:例如 [RESEARCHING] -> [RESEARCHED]
  2. TODO.md 中链接工件

    • 在适当位置添加 research/plan/summary 链接

状态映射

state.json TODO.md
researched [RESEARCHED]
planned [PLANNED]
implemented [IMPLEMENTED]
partial [PARTIAL]

返回:带有 target_status 和 artifacts_linked 字段的 JSON 对象。


操作:artifact_link

目的:添加单个工件链接(幂等)

执行

  1. 幂等性检查
if grep -A 30 "^### {task_number}\." specs/TODO.md | grep -q "{artifact_path}"; then
  echo "Link already exists"
  # 返回 "skipped" 状态
fi
  1. 添加到 state.json 工件数组

重要:使用两步 jq 模式避免问题 #1132 的转义错误。参见 jq-escaping-workarounds.md

# 步骤 1:更新时间戳
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  '(.active_projects[] | select(.project_number == {task_number})) |= . + {
    last_updated: $ts
  }' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json

# 步骤 2:添加工件(附加到数组)
jq --arg path "{artifact_path}" \
   --arg type "{artifact_type}" \
  '(.active_projects[] | select(.project_number == {task_number})).artifacts += [{"path": $path, "type": $type}]' \
  specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
  1. 使用 Edit 工具将链接添加到 TODO.md

剥离 specs/ 前缀TODO.md 在 specs/ 内):todo_link_path="${path#specs/}"

类型 TODO.md 中的格式
research - **Research**: [research-{NNN}.md]({todo_link_path})
plan - **Plan**: [implementation-{NNN}.md]({todo_link_path})
summary - **Summary**: [implementation-summary-{DATE}.md]({todo_link_path})

插入顺序

  • research:在 Language 行之后
  • plan:在 Research 行之后(如果没有 Research,则在 Language 行之后)
  • summary:在 Plan 行之后

返回:带有状态 “linked” 或 “skipped” 的 JSON 对象。


返回格式

preflight_update 返回:

{
  "status": "synced",
  "summary": "Updated task #{N} to [{STATUS}]",
  "previous_status": "not_started",
  "new_status": "researching"
}

postflight_update 返回:

{
  "status": "{target_status}",
  "summary": "Updated task #{N} to [{STATUS}] with {M} artifacts",
  "artifacts_linked": ["path1", "path2"],
  "previous_status": "researching",
  "new_status": "researched"
}

artifact_link 返回:

{
  "status": "linked|skipped",
  "summary": "Linked artifact to task #{N}" | "Link already exists",
  "artifact_path": "path/to/artifact.md",
  "artifact_type": "research"
}

错误处理

任务未找到

返回失败状态并建议验证任务编号。

无效状态转换

返回失败状态,包括当前状态和允许的转换。

文件写入失败

返回失败状态并建议检查权限。

jq 解析失败

如果 jq 命令因 INVALID_CHARACTER 或语法错误(问题 #1132)而失败:

  1. 使用 session_id 和原始命令记录到 errors.json
  2. 使用 jq-escaping-workarounds.md 中的两步模式重试
  3. 如果重试成功,记录恢复操作

集成说明

对于工作流命令:不要直接使用此技能。工作流技能现在内联处理自己的状态更新。

对于手动操作:使用此技能进行独立状态修正:

### 手动状态修正
调用 skill-status-sync,参数包括:
- operation: preflight_update 或 postflight_update
- task_number: {N}
- target_status: {valid_status}
- session_id: manual_correction
- artifacts: [{path, type}, ...](仅用于 postflight)

此技能确保:

  • 跨两个文件的原子更新
  • 一致的 jq/Edit 模式
  • 适当的错误处理
  • 直接执行,无需子代理开销