name: skill-typst-implementation description: 遵循计划实现Typst文档。用于Typst语言实现任务。 allowed-tools: Task, Bash, Edit, Read, Write
原始上下文(现在由子代理加载):
- .claude/context/project/typst/README.md
- .claude/context/project/typst/standards/typst-style-guide.md
- .claude/context/project/typst/standards/notation-conventions.md
- .claude/context/project/typst/standards/document-structure.md
- .claude/context/project/typst/patterns/theorem-environments.md
- .claude/context/project/typst/patterns/cross-references.md
- .claude/context/project/typst/templates/chapter-template.md
- .claude/context/project/typst/tools/compilation-guide.md
- .claude/context/project/logic/standards/notation-standards.md
原始工具(现在由子代理使用):
- Read, Write, Edit, Glob, Grep
- Bash(typst compile *, typst watch *)
Typst 实现技能
薄包装器,将Typst文档实现委托给 typst-implementation-agent 子代理。
重要:此技能实现了技能内部的后处理模式。在子代理返回后,此技能处理所有后处理操作(状态更新、工件链接、git提交),然后返回。这消除了技能返回和编排器之间的“继续”提示问题。
上下文参考
参考(不要急切加载):
- 路径:
.claude/context/core/formats/return-metadata-file.md- 元数据文件模式 - 路径:
.claude/context/core/patterns/postflight-control.md- 标记文件协议 - 路径:
.claude/context/core/patterns/file-metadata-exchange.md- 文件I/O助手 - 路径:
.claude/context/core/patterns/jq-escaping-workarounds.md- jq转义模式(问题 #1132)
注意:此技能是带有内部后处理的薄包装器。上下文由委托代理加载。
触发条件
此技能在以下情况激活:
- 任务语言是 “typst”
- /implement 命令针对Typst任务
- 需要使用Typst创建文档、论文或格式化输出
执行
0. 预飞行状态更新
在委托给子代理之前,将任务状态更新为 “implementing”。
参考:@.claude/context/core/patterns/inline-status-update.md
更新 state.json:
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg status "implementing" \
--arg sid "$session_id" \
'(.active_projects[] | select(.project_number == '$task_number')) |= . + {
status: $status,
last_updated: $ts,
session_id: $sid,
started: $ts
}' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
更新 TODO.md:使用Edit工具将状态标记从 [PLANNED] 更改为 [IMPLEMENTING]。
更新计划文件(如果存在):更新计划元数据中的Status字段:
# 查找最新计划文件(使用填充目录号)
padded_num=$(printf "%03d" "$task_number")
plan_file=$(ls -1 "specs/${padded_num}_${project_name}/plans/implementation-"*.md 2>/dev/null | sort -V | tail -1)
if [ -n "$plan_file" ] && [ -f "$plan_file" ]; then
sed -i "s/^\- \*\*Status\*\*: \[.*\]$/- **Status**: [IMPLEMENTING]/" "$plan_file"
fi
创建后处理标记:
# 确保任务目录存在
mkdir -p "specs/${padded_num}_${project_name}"
cat > "specs/${padded_num}_${project_name}/.postflight-pending" << EOF
{
"session_id": "${session_id}",
"skill": "skill-typst-implementation",
"task_number": ${task_number},
"operation": "implement",
"reason": "Postflight pending: status update, artifact linking, git commit",
"created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"stop_hook_active": false
}
EOF
1. 输入验证
验证必需输入:
task_number- 必须提供并存在于state.json中- 任务状态必须允许实现(planned, implementing, partial)
# 查找任务
task_data=$(jq -r --arg num "$task_number" \
'.active_projects[] | select(.project_number == ($num | tonumber))' \
specs/state.json)
# 验证存在
if [ -z "$task_data" ]; then
return error "Task $task_number not found"
fi
# 提取字段
language=$(echo "$task_data" | jq -r '.language // "general"')
status=$(echo "$task_data" | jq -r '.status')
project_name=$(echo "$task_data" | jq -r '.project_name')
description=$(echo "$task_data" | jq -r '.description // ""')
# 验证语言
if [ "$language" != "typst" ]; then
return error "Task $task_number is not a Typst task"
fi
# 验证状态
if [ "$status" = "completed" ]; then
return error "Task already completed"
fi
2. 上下文准备
准备委托上下文:
{
"session_id": "sess_{timestamp}_{random}",
"delegation_depth": 1,
"delegation_path": ["orchestrator", "implement", "skill-typst-implementation"],
"timeout": 3600,
"task_context": {
"task_number": N,
"task_name": "{project_name}",
"description": "{description}",
"language": "typst"
},
"plan_path": "specs/{NNN}_{SLUG}/plans/implementation-{NNN}.md",
"metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json"
}
3. 调用子代理
关键:您必须使用 Task 工具来生成子代理。
此技能frontmatter中的 agent 字段指定目标:typst-implementation-agent
必需工具调用:
Tool: Task (NOT Skill)
Parameters:
- subagent_type: "typst-implementation-agent"
- prompt: [Include task_context, delegation_context, plan_path]
- description: "Execute Typst implementation for task {N}"
不要 使用 Skill(typst-implementation-agent) - 这将失败。
代理位于 .claude/agents/,而不是 .claude/skills/。
Skill工具只能调用 .claude/skills/ 中的技能。
子代理将:
- 加载Typst特定上下文文件(样式指南、符号约定等)
- 创建/修改 .typ 文件
- 执行编译 (typst compile)
- 创建实现摘要
- 将元数据写入
specs/{NNN}_{SLUG}/.return-meta.json - 返回简要文本摘要(非JSON)
3a. 验证子代理返回格式
重要:检查子代理是否意外将JSON返回到控制台(v1模式)而不是写入文件(v2模式)。
如果子代理的文本返回解析为有效JSON,则记录警告:
# 检查子代理返回是否像JSON(以 { 开头且是有效JSON)
subagent_return="$SUBAGENT_TEXT_RETURN"
if echo "$subagent_return" | grep -q '^{' && echo "$subagent_return" | jq empty 2>/dev/null; then
echo "WARNING: Subagent returned JSON to console instead of writing metadata file."
echo "This indicates the agent may have outdated instructions (v1 pattern instead of v2)."
echo "The skill will continue by reading the metadata file, but this should be fixed."
fi
此验证:
- 不会导致操作失败(继续读取元数据文件)
- 记录警告以进行调试
- 指示子代理指令需要更新
- 允许优雅处理混合v1/v2代理
4. 解析子代理返回(读取元数据文件)
子代理返回后,读取元数据文件:
metadata_file="specs/${padded_num}_${project_name}/.return-meta.json"
if [ -f "$metadata_file" ] && jq empty "$metadata_file" 2>/dev/null; then
status=$(jq -r '.status' "$metadata_file")
artifact_path=$(jq -r '.artifacts[0].path // ""' "$metadata_file")
artifact_type=$(jq -r '.artifacts[0].type // ""' "$metadata_file")
artifact_summary=$(jq -r '.artifacts[0].summary // ""' "$metadata_file")
phases_completed=$(jq -r '.metadata.phases_completed // 0' "$metadata_file")
phases_total=$(jq -r '.metadata.phases_total // 0' "$metadata_file")
# 提取completion_data字段(如果存在)
completion_summary=$(jq -r '.completion_data.completion_summary // ""' "$metadata_file")
roadmap_items=$(jq -c '.completion_data.roadmap_items // []' "$metadata_file")
else
echo "Error: Invalid or missing metadata file"
status="failed"
fi
验证元数据包含必需字段:
- Status是以下之一:implemented, partial, failed, blocked
- Summary非空且<100个令牌
- Artifacts数组存在(源文件、编译的PDF、摘要)
- Metadata包含session_id, agent_type, 委托信息
5. 后处理状态更新
实现后,根据结果更新任务状态。
参考:@.claude/context/core/patterns/inline-status-update.md
如果 result.status == “implemented”:
更新state.json为 “completed” 并添加completion_data字段(用于问题 #1132的两步模式):
# 步骤1:更新状态和时间戳
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg status "completed" \
'(.active_projects[] | select(.project_number == '$task_number')) |= . + {
status: $status,
last_updated: $ts,
completed: $ts
}' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
# 步骤2:添加completion_summary(对完成的任务总是必需)
if [ -n "$completion_summary" ]; then
jq --arg summary "$completion_summary" \
'(.active_projects[] | select(.project_number == '$task_number')).completion_summary = $summary' \
specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
fi
# 步骤3:添加roadmap_items(如果存在且非空)
if [ "$roadmap_items" != "[]" ] && [ -n "$roadmap_items" ]; then
jq --argjson items "$roadmap_items" \
'(.active_projects[] | select(.project_number == '$task_number')).roadmap_items = $items' \
specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
fi
# 步骤4:过滤掉现有的摘要工件(使用 "| not" 模式以避免 != 转义 - 问题 #1132)
jq '(.active_projects[] | select(.project_number == '$task_number')).artifacts =
[(.active_projects[] | select(.project_number == '$task_number')).artifacts // [] | .[] | select(.type == "summary" | not)]' \
specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
# 步骤5:添加新的摘要工件
jq --arg path "$artifact_path" \
'(.active_projects[] | select(.project_number == '$task_number')).artifacts += [{"path": $path, "type": "summary"}]' \
specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
- 将状态标记从
[IMPLEMENTING]更改为[COMPLETED] - 添加摘要工件链接:
- **Summary**: [implementation-summary-{DATE}.md]({artifact_path})
更新计划文件(如果存在):将Status字段更新为 [COMPLETED] 并验证:
plan_file=$(ls -1 "specs/${padded_num}_${project_name}/plans/implementation-"*.md 2>/dev/null | sort -V | tail -1)
if [ -n "$plan_file" ] && [ -f "$plan_file" ]; then
# 首先尝试项目符号模式,然后非项目符号模式
sed -i 's/^\- \*\*Status\*\*: \[.*\]$/- **Status**: [COMPLETED]/' "$plan_file"
sed -i 's/^\*\*Status\*\*: \[.*\]$/**Status**: [COMPLETED]/' "$plan_file"
# 验证更新
if grep -qE '^\*\*Status\*\*: \[COMPLETED\]|^\- \*\*Status\*\*: \[COMPLETED\]' "$plan_file"; then
echo "Plan file status updated to [COMPLETED]"
else
echo "WARNING: Could not verify plan file status update"
fi
else
echo "INFO: No plan file found to update (directory: specs/${padded_num}_${project_name}/plans/)"
fi
如果 result.status == “partial”:
更新state.json并添加恢复点(保持状态为 “implementing”):
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg phase "$completed_phase" \
'(.active_projects[] | select(.project_number == '$task_number')) |= . + {
last_updated: $ts,
resume_phase: ($phase | tonumber + 1)
}' specs/state.json > /tmp/state.json && mv /tmp/state.json specs/state.json
TODO.md保持为 [IMPLEMENTING]。
更新计划文件(如果存在):将Status字段更新为 [PARTIAL] 并验证:
plan_file=$(ls -1 "specs/${padded_num}_${project_name}/plans/implementation-"*.md 2>/dev/null | sort -V | tail -1)
if [ -n "$plan_file" ] && [ -f "$plan_file" ]; then
# 首先尝试项目符号模式,然后非项目符号模式
sed -i 's/^\- \*\*Status\*\*: \[.*\]$/- **Status**: [PARTIAL]/' "$plan_file"
sed -i 's/^\*\*Status\*\*: \[.*\]$/**Status**: [PARTIAL]/' "$plan_file"
# 验证更新
if grep -qE '^\*\*Status\*\*: \[PARTIAL\]|^\- \*\*Status\*\*: \[PARTIAL\]' "$plan_file"; then
echo "Plan file status updated to [PARTIAL]"
else
echo "WARNING: Could not verify plan file status update"
fi
else
echo "INFO: No plan file found to update (directory: specs/${padded_num}_${project_name}/plans/)"
fi
失败时:不运行后处理。保持状态为 “implementing” 以重试。不更新计划文件(保持为 [IMPLEMENTING] 以重试)。
6. Git 提交
使用会话ID提交更改:
git add -A
git commit -m "task ${task_number}: complete implementation
Session: ${session_id}
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
7. 清理
后处理完成后移除标记和元数据文件:
rm -f "specs/${padded_num}_${project_name}/.postflight-pending"
rm -f "specs/${padded_num}_${project_name}/.postflight-loop-guard"
rm -f "specs/${padded_num}_${project_name}/.return-meta.json"
8. 返回简要摘要
返回简要文本摘要(非JSON)描述实现结果。
返回格式
此技能返回 简要文本摘要(非JSON)。JSON元数据写入文件并在内部处理。
成功返回示例:
Typst implementation completed for task 500:
- All 4 phases executed, document compiles cleanly
- Created PDF at Theories/Bimodal/typst/BimodalReference.pdf
- Created summary at specs/500_bimodal_docs/summaries/implementation-summary-20260118.md
- Status updated to [COMPLETED]
- Changes committed with session sess_1736700000_abc123
部分返回示例:
Typst implementation partially completed for task 500:
- Phases 1-2 of 3 executed
- Phase 3 blocked: unknown variable 'customcmd'
- Partial summary at specs/500_bimodal_docs/summaries/implementation-summary-20260118.md
- Status remains [IMPLEMENTING] - run /implement 500 to resume
错误处理
输入验证错误
如果任务未找到、语言错误或状态无效,立即返回失败状态。
子代理错误
逐字传递子代理的错误返回。
超时
如果子代理超时(默认3600秒),则返回部分状态。