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 检查点设置进行中状态
执行:
- 验证任务存在:
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
- 更新 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
- 更新 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 检查点设置最终状态并链接工件
执行:
- 更新 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
- 将工件添加到 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
-
更新 TODO.md 状态标记:
- 使用 Edit 更改状态:例如
[RESEARCHING]->[RESEARCHED]
- 使用 Edit 更改状态:例如
-
在 TODO.md 中链接工件:
- 在适当位置添加 research/plan/summary 链接
状态映射:
| state.json | TODO.md |
|---|---|
| researched | [RESEARCHED] |
| planned | [PLANNED] |
| implemented | [IMPLEMENTED] |
| partial | [PARTIAL] |
返回:带有 target_status 和 artifacts_linked 字段的 JSON 对象。
操作:artifact_link
目的:添加单个工件链接(幂等)
执行:
- 幂等性检查:
if grep -A 30 "^### {task_number}\." specs/TODO.md | grep -q "{artifact_path}"; then
echo "Link already exists"
# 返回 "skipped" 状态
fi
- 添加到 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
- 使用 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)而失败:
- 使用 session_id 和原始命令记录到 errors.json
- 使用
jq-escaping-workarounds.md中的两步模式重试 - 如果重试成功,记录恢复操作
集成说明
对于工作流命令:不要直接使用此技能。工作流技能现在内联处理自己的状态更新。
对于手动操作:使用此技能进行独立状态修正:
### 手动状态修正
调用 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 模式
- 适当的错误处理
- 直接执行,无需子代理开销