Web实现技能Skill skill-web-implementation

这个技能是一个薄包装器,用于实现基于Astro、Tailwind和TypeScript的网络变化。它通过委托给子代理来处理前端网页开发任务,包括页面、组件、布局的创建和修改,并自动执行状态更新、工件链接和Git提交等后处理操作。适用于Astro框架、Tailwind CSS、TypeScript项目,帮助提高开发效率和代码质量。关键词:网络实现、Astro、Tailwind、TypeScript、前端开发、网页开发、状态管理、Git提交、代理委托、自动化流程。

前端开发 0 次安装 0 次浏览 更新于 3/22/2026

名称: skill-web-implementation 描述: 根据计划实现网络(Astro/Tailwind/TypeScript)变化。调用以处理网络语言实现任务。 允许工具: Task, Bash, Edit, Read, Write, Read(/tmp/.json), Bash(rm:)

原始上下文(现在由子代理加载):

- .opencode/context/project/web/README.md

- .opencode/context/project/web/domain/astro-framework.md

- .opencode/context/project/web/domain/tailwind-v4.md

- .opencode/context/project/web/standards/web-style-guide.md

- .opencode/context/project/web/patterns/astro-component.md

- .opencode/context/project/web/patterns/tailwind-patterns.md

- .opencode/context/project/web/patterns/accessibility-patterns.md

- .opencode/context/project/web/standards/performance-standards.md

- .opencode/context/project/web/tools/astro-cli-guide.md

- .opencode/context/project/web/tools/pnpm-guide.md

原始工具(现在由子代理使用):

- Read, Write, Edit, Glob, Grep

- Bash(pnpm build, pnpm check, npx astro check)


Web实现技能

薄包装器,将网络(Astro/Tailwind/TypeScript)实现委托给 web-implementation-agent 子代理。

重要: 此技能实现了技能内部的后处理模式。在子代理返回后, 此技能处理所有后处理操作(状态更新、工件链接、git提交)然后返回。 这消除了技能返回和协调器之间的“继续”提示问题。

上下文引用

引用(不要急切加载):

  • 路径: .opencode/context/core/formats/return-metadata-file.md - 元数据文件模式
  • 路径: .opencode/context/core/patterns/postflight-control.md - 标记文件协议
  • 路径: .opencode/context/core/patterns/file-metadata-exchange.md - 文件I/O助手
  • 路径: .opencode/context/core/patterns/jq-escaping-workarounds.md - jq转义模式(问题 #1132)

注意:此技能是一个具有内部后处理的薄包装器。上下文由委托的代理加载。

触发条件

此技能在以下情况激活:

  • 任务语言是“web”
  • /implement 命令针对网络(Astro/Tailwind/TypeScript)任务
  • 页面、组件、布局或网页样式需要创建或修改

执行

0. 预检状态更新

在委托给子代理之前,将任务状态更新为“implementing”。

引用: @.opencode/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: 使用编辑工具将状态标记从 [PLANNED] 更改为 [IMPLEMENTING]

更新计划文件(如果存在):更新计划元数据中的状态字段:

# 查找最新计划文件
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

创建后处理标记:

# 确保任务目录存在
padded_num=$(printf "%03d" "$task_number")
mkdir -p "specs/${padded_num}_${project_name}"

cat > "specs/${padded_num}_${project_name}/.postflight-pending" << EOF
{
  "session_id": "${session_id}",
  "skill": "skill-web-implementation",
  "task_number": ${task_number},
  "operation": "implement",
  "reason": "后处理待定:状态更新、工件链接、git提交",
  "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_number 未找到"
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" != "web" ]; then
  return error "任务 $task_number 不是网络任务"
fi

# 验证状态
if [ "$status" = "completed" ]; then
  return error "任务已完成"
fi

2. 上下文准备

准备委托上下文:

{
  "session_id": "sess_{timestamp}_{random}",
  "delegation_depth": 1,
  "delegation_path": ["orchestrator", "implement", "skill-web-implementation"],
  "timeout": 3600,
  "task_context": {
    "task_number": N,
    "task_name": "{project_name}",
    "description": "{description}",
    "language": "web"
  },
  "plan_path": "specs/{NNN}_{SLUG}/plans/implementation-{NNN}.md",
  "metadata_file_path": "specs/{NNN}_{SLUG}/.return-meta.json"
}

3. 调用子代理

关键: 您必须使用 Task 工具来生成子代理。

此技能前驱中的 agent 字段指定了目标:web-implementation-agent

必需工具调用:

工具: Task(不是 Skill)
参数:
  - subagent_type: "web-implementation-agent"
  - prompt: [包括 task_context, delegation_context, plan_path]
  - description: "为任务 {N} 执行网络实现"

不要使用 Skill(web-implementation-agent) - 这会失败。 代理位于 .opencode/agents/,而不是 .opencode/skills/。 Skill 工具只能调用来自 .opencode/skills/ 的技能。

子代理将:

  • 加载网络特定上下文文件(Astro框架、Tailwind v4、样式指南等)
  • 创建/修改 .astro, .ts, .tsx, .css 文件
  • 执行构建验证(pnpm build, pnpm check)
  • 处理 TypeScript 和 Astro 错误
  • 创建实现摘要
  • 将元数据写入 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 "警告:子代理将 JSON 返回到控制台而不是写入元数据文件。"
    echo "这表明代理可能有过时的指令(v1 模式而不是 v2)。"
    echo "技能将继续读取元数据文件,但这应修复。"
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 "错误:无效或缺少元数据文件"
    status="failed"
fi

验证元数据包含必需字段:

  • 状态是其中之一:implemented, partial, failed, blocked
  • 摘要非空且 <100 个令牌
  • 工件数组存在(源文件、摘要)
  • 元数据包含 session_id, agent_type, 委托信息

5. 后处理状态更新

实现后,根据结果更新任务状态。

引用: @.opencode/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

更新 TODO.md:

  • 将状态标记从 [IMPLEMENTING] 更改为 [COMPLETED]
  • TODO.md 剥离 specs/ 前缀(TODO.md 在 specs/ 内): todo_link_path="${artifact_path#specs/}"
  • 添加摘要工件链接: - **Summary**: [implementation-summary-{DATE}.md]({todo_link_path})

更新计划文件(如果存在):将状态字段更新为 [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"
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]

更新计划文件(如果存在):将状态字段更新为 [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"
fi

失败时: 不要运行后处理。保持状态为 “implementing” 以便重试。不要更新计划文件(保留为 [IMPLEMENTING] 以便重试)。

6. Git提交

使用会话ID提交更改:

git add -A
git commit -m "任务 ${task_number}: 完成实现

会话: ${session_id}

共同作者: 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 元数据写入文件并在内部处理。

成功返回示例:

任务10的网络实现完成:
- 所有3个阶段执行,构建通过干净
- 创建关于页面,包含英雄部分和团队网格
- 在 specs/10_create_about_page/summaries/implementation-summary-20260205.md 创建摘要
- 状态更新为 [COMPLETED]
- 使用会话 sess_1770319142_a293c5 提交更改

部分返回示例:

任务10的网络实现部分完成:
- 3个阶段中的第1-2阶段执行
- 第3阶段被阻止:ContactForm 组件中的 TypeScript 错误
- 在 specs/10_create_about_page/summaries/implementation-summary-20260205.md 部分摘要
- 状态保持 [IMPLEMENTING] - 运行 /implement 10 以恢复

错误处理

输入验证错误

如果任务未找到、语言错误或状态无效,立即返回失败状态。

子代理错误

逐字传递子代理的错误返回。

超时

如果子代理超时(默认3600秒),返回部分状态。