---
name: gh-workflow-generator
description: "快速生成带 GitHub Actions Workflow 的自动化采集项目。当用户想要创建定时采集、数据处理、自动化发布的 GitHub 仓库时触发。"
---

<role>
你是一个 GitHub 自动化项目架构师。帮助用户快速搭建带有完整 CI/CD 流水线的数据采集项目。
</role>

<purpose>
通过引导式问答收集用户需求，生成完整的项目模板，包括 GitHub Actions Workflow、采集脚本、处理逻辑和发布配置。
</purpose>

<trigger>
```text
触发词/示例：
- 创建采集项目
- 生成 GitHub Workflow
- 搭建自动化流水线
- 定时采集数据
- gh-workflow-generator
- 自动化采集项目
- 创建带 workflow 的仓库
- 生成数据采集脚手架
```
</trigger>

<gsd:workflow>
  <gsd:meta>
    <name>gh-workflow-generator</name>
    <trigger>采集项目、Workflow、自动化流水线、定时采集、数据采集脚手架</trigger>
    <requires>Read, Write, Edit, Glob, Bash, AskUserQuestion, Skill</requires>
    <stateFile>.gh-workflow-state.json</stateFile>
    <checkpoints>
      <checkpoint order="1">已检查 github-repo-publish skill</checkpoint>
      <checkpoint order="2">已收集数据源需求</checkpoint>
      <checkpoint order="3">API Key 验证通过</checkpoint>
      <checkpoint order="4">用户确认生成的 AI Prompt</checkpoint>
      <checkpoint order="5">项目文件生成完成</checkpoint>
      <checkpoint order="6">测试用例通过</checkpoint>
      <checkpoint order="7">Git 仓库创建并推送成功</checkpoint>
      <checkpoint order="8">Workflow 运行验证成功</checkpoint>
    </checkpoints>
    <constraints>
      <constraint>脚本使用 Node.js (ESM)，不是 Shell</constraint>
      <constraint>先生成函数 + 测试用例，测试通过后组装</constraint>
      <constraint>API Key 必须通过测试脚本验证后才能继续</constraint>
      <constraint>必须创建真实的 .env 文件，不只是 .env.example</constraint>
      <constraint>Workflow 推送后必须自动验证运行状态</constraint>
      <constraint>自动修复失败最多 3 次后让用户协助</constraint>
      <constraint>所有 GitHub 操作自动化，不需要用户确认</constraint>
      <constraint>每个阶段完成后必须更新状态文件</constraint>
      <constraint>启动时检查状态文件，支持中断恢复</constraint>
    </constraints>
  </gsd:meta>

  <gsd:recovery>
    <detection>
      启动时检查项目目录下是否存在 .gh-workflow-state.json 文件
    </detection>
    <stateFileSchema>
{
  "phase": "collect",           // 当前阶段名称
  "phaseOrder": 1,              // 阶段序号
  "checkpoint": "需求收集完成",  // 当前 checkpoint 描述
  "collected": {                // 已收集的用户输入
    "dataSource": "GitHub API",
    "frequency": "*/30 * * * *",
    "aiProvider": "openai",
    "projectName": "my-collector"
  },
  "nextStep": "验证 API Key",   // 下一步要执行的操作
  "projectDir": "/path/to/project",  // 项目目录
  "updatedAt": "2026-03-25T10:30:00Z"
}
    </stateFileSchema>
    <action>
      1. 读取状态文件内容
      2. 向用户展示当前进度：
         📊 检测到未完成的流程
         当前进度：Phase {phaseOrder}/6 - {checkpoint}
         上次更新：{updatedAt}
      3. 使用 AskUserQuestion 询问用户：
         - 继续执行（从 nextStep 开始）
         - 重新开始（删除状态文件，从头开始）
      4. 如果选择继续，恢复 collected 数据，跳转到对应 phase
      5. 如果选择重新开始，删除状态文件，执行 Phase 0
    </action>
    <stateUpdate>
      每个阶段完成后必须执行：
      1. 更新状态文件的 phase、phaseOrder、checkpoint
      2. 更新 nextStep 为下一阶段的第一步
      3. 更新 updatedAt 为当前时间
      4. 将新收集的数据合并到 collected 对象
    </stateUpdate>
    <cleanup>
      流程全部完成后：
      1. 删除 .gh-workflow-state.json 文件
      2. 或重命名为 .gh-workflow-state.completed.json 归档
    </cleanup>
  </gsd:recovery>

  <gsd:goal>通过引导式问答，帮助用户创建一个完整的 GitHub 自动化采集项目</gsd:goal>

  <gsd:phase name="preflight" order="0">
    <gsd:step>检查状态文件是否存在，存在则执行恢复流程</gsd:step>
    <gsd:step>检查 github-repo-publish skill 是否安装</gsd:step>
    <gsd:step>未安装则自动安装</gsd:step>
    <gsd:step>创建初始状态文件（如果不存在）</gsd:step>
    <gsd:checkpoint>环境预检完成</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "preflight"
      phaseOrder: 0
      checkpoint: "环境预检完成"
      nextStep: "收集用户需求"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>

  <gsd:phase name="collect" order="1">
    <gsd:step>询问用户想监控什么数据源</gsd:step>
    <gsd:step>询问采集频率和执行模式</gsd:step>
    <gsd:step>询问是否需要 AI 处理</gsd:step>
    <gsd:step>收集对应的 API Key（根据 AI 选择）</gsd:step>
    <gsd:step>询问项目名称</gsd:step>
    <gsd:checkpoint>需求收集完成</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "collect"
      phaseOrder: 1
      checkpoint: "需求收集完成"
      collected: { dataSource, frequency, aiProvider, apiKey, projectName }
      nextStep: "创建 .env 文件并验证 API Key"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>

  <gsd:phase name="validate" order="2">
    <gsd:step>创建项目目录</gsd:step>
    <gsd:step>创建 .env 文件（真实文件，非 .env.example）</gsd:step>
    <gsd:step>生成 API 测试脚本（scripts/test-api.mjs）</gsd:step>
    <gsd:step>运行测试脚本验证 API 连通性</gsd:step>
    <gsd:step>如果验证失败，提示用户重新输入 API Key</gsd:step>
    <gsd:checkpoint>API 验证通过</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "validate"
      phaseOrder: 2
      checkpoint: "API 验证通过"
      collected: { projectDir }
      nextStep: "生成 AI Prompt"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>

  <gsd:phase name="prompt" order="3">
    <gsd:step>根据数据源生成 AI Prompt</gsd:step>
    <gsd:step>展示 Prompt 让用户确认或修改</gsd:step>
    <gsd:checkpoint>用户确认 Prompt</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "prompt"
      phaseOrder: 3
      checkpoint: "用户确认 Prompt"
      collected: { aiPrompt }
      nextStep: "生成项目文件结构"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>

  <gsd:phase name="generate" order="4">
    <gsd:step>生成项目文件结构</gsd:step>
    <gsd:step>生成采集函数 + 测试用例</gsd:step>
    <gsd:step>运行测试验证</gsd:step>
    <gsd:checkpoint>项目生成并验证通过</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "generate"
      phaseOrder: 4
      checkpoint: "项目生成并验证通过"
      nextStep: "Git 初始化并创建仓库"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>

  <gsd:phase name="publish" order="5">
    <gsd:step>Git init + commit</gsd:step>
    <gsd:step>调用 github-repo-publish 创建仓库</gsd:step>
    <gsd:step>配置 GitHub Secrets</gsd:step>
    <gsd:checkpoint>仓库创建并推送成功</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "publish"
      phaseOrder: 5
      checkpoint: "仓库创建并推送成功"
      collected: { repoUrl }
      nextStep: "触发并验证 Workflow 运行"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>

  <gsd:phase name="verify" order="6">
    <gsd:step>触发 GitHub Workflow 运行</gsd:step>
    <gsd:step>轮询检查 Workflow 运行状态</gsd:step>
    <gsd:step>如果失败，分析错误日志</gsd:step>
    <gsd:step>尝试自动修复（最多 3 次）</gsd:step>
    <gsd:step>多次失败后让用户协助排查</gsd:step>
    <gsd:checkpoint>Workflow 运行成功</gsd:checkpoint>
    <gsd:stateUpdate>
      phase: "verify"
      phaseOrder: 6
      checkpoint: "Workflow 运行成功"
      status: "completed"
      nextStep: "清理状态文件，流程完成"
      updatedAt: "{{current_time}}"
    </gsd:stateUpdate>
  </gsd:phase>
</gsd:workflow>

## 进度展示模板

在执行过程中，使用以下格式向用户展示当前进度：

```
📊 gh-workflow-generator 进度

✅ Phase 0: 环境预检
✅ Phase 1: 需求收集
🔄 Phase 2: API 验证 ← 当前
⬜ Phase 3: Prompt 生成
⬜ Phase 4: 项目生成
⬜ Phase 5: 仓库创建
⬜ Phase 6: Workflow 验证
```

**恢复时的展示格式**：

```
📊 检测到未完成的流程

当前进度：Phase 2/6 - API 验证
上次更新：2026-03-25 10:30:00
项目目录：/Users/xxx/my-collector

已收集信息：
- 数据源：GitHub API
- 采集频率：*/30 * * * *
- AI 处理：OpenAI

下一步：验证 API Key
```

# gh-workflow-generator

一个泛化的 GitHub 自动化采集 Skill，让任何开发者可以快速创建一个带 GitHub Actions Workflow 的自动化采集项目。

## 参考案例

- [trending-skills](https://github.com/Aradotso/trending-skills) - GitHub Trending 自动生成 Skills

## 执行流程

### Phase 0: 环境预检

**目标**：确保依赖 skill 已安装，检查是否有未完成的流程

**步骤**：
1. **检查状态文件是否存在**
   - 如果存在 `.gh-workflow-state.json`，执行恢复流程
   - 向用户展示当前进度，询问是否继续
2. 检查 `github-repo-publish` skill 是否安装
3. 未安装则自动安装（不询问用户）
4. 创建初始状态文件（如果不存在）

```bash
# 检查状态文件
if [ -f ".gh-workflow-state.json" ]; then
  echo "检测到未完成的流程"
  cat .gh-workflow-state.json
fi

# 检查 skill 是否存在
j-skills list -g | grep github-repo-publish || j-skills install github-repo-publish -g
```

**状态文件初始化**：

```json
{
  "phase": "preflight",
  "phaseOrder": 0,
  "checkpoint": "环境预检完成",
  "collected": {},
  "nextStep": "收集用户需求",
  "projectDir": "{{current_project_dir}}",
  "updatedAt": "{{current_time}}"
}
```

**Checkpoint**：环境预检完成

---

### Phase 1: 需求收集与 API 验证

**目标**：收集用户需求并验证 API Key

**步骤**：
1. 询问用户想监控什么数据源
2. 询问采集频率
3. 询问是否需要 AI 处理
4. **如果需要 AI 处理，立即收集对应的 API Key**
5. **创建 `.env` 文件（不只是 `.env.example`）**
6. **运行测试脚本验证 API 连通性**
7. **验证失败则重新询问 API Key**

**必要交互 1** - 需求收集（使用 AskUserQuestion）：

```javascript
{
  questions: [
    {
      header: "数据源",
      question: "你想监控什么数据源？",
      options: [
        { label: "GitHub API", description: "GitHub 仓库、Issue、PR 等" },
        { label: "REST API", description: "任意 REST API 端点" },
        { label: "RSS/Atom", description: "RSS 或 Atom 订阅源" },
        { label: "网页抓取", description: "需要解析 HTML 的网页" },
        { label: "自定义", description: "其他数据源" }
      ]
    },
    {
      header: "采集频率",
      question: "采集频率是多少？",
      options: [
        { label: "每 15 分钟", description: "cron: '*/15 * * * *'" },
        { label: "每 30 分钟", description: "cron: '*/30 * * * *'" },
        { label: "每小时", description: "cron: '0 * * * *'" },
        { label: "每天", description: "cron: '0 0 * * *'" }
      ]
    },
    {
      header: "AI 处理",
      question: "是否需要 AI 处理采集的数据？",
      options: [
        { label: "是，使用 OpenAI", description: "使用 OpenAI API 处理" },
        { label: "是，使用 Claude", description: "使用 Anthropic Claude API" },
        { label: "否", description: "仅存储原始数据" }
      ]
    }
  ]
}
```

**必要交互 2** - API Key 收集（如果选择了 AI 处理）：

```javascript
// 如果选择 OpenAI
{
  header: "OpenAI API Key",
  question: "请输入你的 OpenAI API Key（将以 sk- 开头）:",
  inputType: "password"  // 密码输入
}

// 如果选择 Claude
{
  header: "Claude API Key",
  question: "请输入你的 Anthropic API Key:",
  inputType: "password"
}
```

**API 验证步骤**：

1. **创建 `.env` 文件**（真实文件，不只是示例）：

```bash
# 在项目目录下创建 .env
cat > .env << EOF
# AI API Key（由 gh-workflow-generator 自动配置）
OPENAI_API_KEY=${用户输入的Key}

# GitHub Token（用于 gh CLI）
GH_TOKEN=${从环境获取或用户输入}
EOF
```

2. **创建测试脚本** `scripts/test-api.mjs`：

```javascript
#!/usr/bin/env node
/**
 * API 连通性测试脚本
 * 验证 API Key 是否有效
 */

import 'dotenv/config';

const AI_PROVIDER = process.env.AI_PROVIDER || 'openai';

async function testOpenAI() {
  const apiKey = process.env.OPENAI_API_KEY;
  if (!apiKey) {
    throw new Error('OPENAI_API_KEY 未配置');
  }

  const response = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
    },
    body: JSON.stringify({
      model: 'gpt-4o-mini',
      messages: [{ role: 'user', content: 'hello world' }],
      max_tokens: 10
    })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`OpenAI API 错误: ${error.error?.message || response.statusText}`);
  }

  console.log('✅ OpenAI API 连接成功');
  return true;
}

async function testClaude() {
  const apiKey = process.env.ANTHROPIC_API_KEY;
  if (!apiKey) {
    throw new Error('ANTHROPIC_API_KEY 未配置');
  }

  const response = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': apiKey,
      'anthropic-version': '2023-06-01'
    },
    body: JSON.stringify({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 10,
      messages: [{ role: 'user', content: 'hello world' }]
    })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Claude API 错误: ${error.error?.message || response.statusText}`);
  }

  console.log('✅ Claude API 连接成功');
  return true;
}

// 执行测试
try {
  if (AI_PROVIDER === 'openai') {
    await testOpenAI();
  } else if (AI_PROVIDER === 'claude') {
    await testClaude();
  } else {
    console.log('⏭️  跳过 AI API 测试（未启用 AI 处理）');
  }
  process.exit(0);
} catch (error) {
  console.error('❌ API 验证失败:', error.message);
  process.exit(1);
}
```

3. **运行测试**：

```bash
# 安装依赖
npm install dotenv

# 运行 API 测试
node scripts/test-api.mjs

# 如果失败，提示用户重新输入 API Key
```

**验证失败处理**：
- 如果测试失败，输出错误信息
- 询问用户是否重新输入 API Key
- 最多重试 3 次
- 3 次失败后让用户手动检查

**Checkpoint**：API 验证通过

---

### Phase 2: Prompt 生成

**目标**：生成 AI Prompt 并让用户确认

**步骤**：
1. 根据数据源类型生成 AI Prompt 模板
2. 展示 Prompt 让用户确认
3. 用户可修改 Prompt
4. **将确认的 Prompt 保存到 `.ai-prompt.txt` 文件**

**Prompt 模板示例**（根据数据源类型）：

```markdown
# GitHub API 数据源

你是一个数据采集助手。请处理以下 GitHub 数据：

1. 提取关键信息（名称、描述、星标数、语言等）
2. 生成结构化的 Markdown 文档
3. 输出格式：YAML frontmatter + Markdown 正文

数据源：{DATA_SOURCE}
```

**必要交互**：
- 展示生成的 Prompt
- 用户确认或修改

**Prompt 确认后**：

```bash
# 保存用户确认的 Prompt 到文件（供 process.mjs 读取）
echo "${用户确认的Prompt}" > .ai-prompt.txt
```

**Checkpoint**：用户确认 Prompt

---

### Phase 3: 项目生成

**目标**：生成完整的项目文件

**步骤**：
1. 生成项目目录结构
2. 生成采集函数（`scripts/collect.mjs`）
3. 生成测试用例（`scripts/__tests__/collect.test.mjs`）
4. 运行测试验证
5. 测试通过后生成 Workflow

**生成的项目结构**：

```
<project-name>/
├── .github/
│   └── workflows/
│       └── collect.yml      # GitHub Actions Workflow
├── scripts/
│   ├── collect.mjs          # 数据采集（Node.js ESM）
│   ├── process.mjs          # 数据处理（AI 分析）
│   ├── test-api.mjs         # API 连通性测试脚本
│   ├── verify-workflow.mjs  # Workflow 验证脚本
│   └── __tests__/
│       ├── collect.test.mjs # 采集测试
│       └── process.test.mjs # 处理测试
├── trending/                # AI 分析报告（不是 skills/）
│   └── <owner>-<repo>/
│       └── README.md        # 不是 SKILL.md
├── output/                  # 原始数据（JSON）
│   └── trending.json
├── .ai-prompt.txt           # 用户确认的 Prompt
├── README.md
├── package.json
├── .env                     # 真实的环境变量
└── .gitignore
```

### 输出格式规范

**文件夹结构**：
```
trending/
├── <owner>-<repo>/
│   └── README.md
```

**命名规则**：
- 文件夹名：`<owner>-<repo>`（将 `/` 替换为 `-`）
- 文件名：`README.md`（不是 SKILL.md）

**YAML Frontmatter 格式**：
```yaml
---
name: {repo.name}
full_name: {repo.full_name}
owner: {repo.owner}
url: {repo.url}
language: {repo.language}
stars: {repo.stars}
forks: {repo.forks}
today_stars: {repo.today_stars}
rank: {repo.rank}
date: {YYYY-MM-DD}
text: |
  {AI 生成的分析内容}
  - 每行缩进 2 个空格
  - 不要包含 ```markdown 代码块标记
  - 直接是纯文本内容
---
```

**正文格式**：
```markdown
# {repo.full_name}

{repo.description}

{AI 分析内容（与 text 字段相同）}

---

> 采集时间: {date} | 排名: #{rank} | 今日新增: {today_stars} ⭐
```

**重要约束**：
1. `text` 字段不要包含代码块标记（` ```markdown ` 或 ` ``` `）
2. AI 分析内容直接输出，不要有"AI 分析"之类的标题
3. 元数据全部放在 YAML frontmatter 中

**TDD 流程**：
1. 先生成 `collect.mjs` 函数
2. 生成 `collect.test.mjs` 测试用例
3. 运行 `node --test` 验证
4. 测试通过后继续

### process.mjs 模板

**数据处理脚本**（调用 AI 生成仓库分析报告）：

```javascript
#!/usr/bin/env node

/**
 * 数据处理脚本：调用 AI 生成仓库分析报告
 */

import 'dotenv/config';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';

const AI_PROVIDER = process.env.AI_PROVIDER || 'qwen';
const QWEN_API_KEY = process.env.QWEN_API_KEY;
const QWEN_API_URL = 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions';

if (!QWEN_API_KEY) {
  console.error('❌ 错误：未找到 QWEN_API_KEY 环境变量');
  process.exit(1);
}

// 确保 trending 目录存在
if (!existsSync('trending')) {
  mkdirSync('trending', { recursive: true });
  console.log('📁 Created trending directory');
}

// 读取采集的数据
const trendingData = JSON.parse(readFileSync('output/trending.json', 'utf-8'));
console.log(`📊 Processing ${trendingData.repos.length} repos with ${AI_PROVIDER} AI...`);

/**
 * 调用 AI API 生成仓库分析
 */
async function analyzeRepo(repo, aiPrompt) {
  // 使用用户确认的 Prompt，或使用默认 Prompt
  const prompt = aiPrompt || `你是一个 GitHub 项目分析专家。请分析以下 GitHub 仓库并生成简洁的分析报告。

## 仓库信息

- **名称**: ${repo.full_name}
- **描述**: ${repo.description || '暂无描述'}
- **语言**: ${repo.language}
- **星标数**: ${repo.stars.toLocaleString()}
- **今日新增**: ${(repo.today_stars || 0).toLocaleString()} stars

## 分析要求

请从以下维度进行分析（直接输出内容，不要代码块标记）：

1. **项目定位**（50-100字）- 这个项目是做什么的？解决什么问题？

2. **核心功能**（3-5 个要点）

3. **技术特点**（50-100字）

4. **适用场景**（3-5 个场景）

5. **推荐理由**（50-100字）

请用 Markdown 格式输出，简洁明了，直接开始内容，不要使用代码块标记。`;

  const response = await fetch(QWEN_API_URL, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${QWEN_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      model: 'qwen-turbo',
      messages: [{ role: 'user', content: prompt }],
      max_tokens: 1000,
      temperature: 0.7
    })
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`AI API error: ${response.status} - ${errorText}`);
  }

  const data = await response.json();
  return data.choices[0].message.content;
}

/**
 * 生成 Markdown 文件
 */
function generateMarkdown(repo, analysis) {
  const date = new Date().toISOString().split('T')[0];

  // 清理分析文本（移除代码块标记）
  const cleanAnalysis = analysis
    .replace(/```markdown\n?/gi, '')
    .replace(/```\n?/g, '')
    .trim();

  return `---
name: ${repo.name}
full_name: ${repo.full_name}
owner: ${repo.owner}
url: ${repo.url}
language: ${repo.language}
stars: ${repo.stars}
forks: ${repo.forks}
today_stars: ${repo.today_stars || 0}
rank: ${repo.rank}
date: ${date}
text: |
${cleanAnalysis.split('\n').map(line => '  ' + line).join('\n')}
---

# ${repo.full_name}

${repo.description || '暂无描述'}

${cleanAnalysis}

---

> 采集时间: ${date} | 排名: #${repo.rank} | 今日新增: ${(repo.today_stars || 0).toLocaleString()} ⭐
`;
}

// 读取用户确认的 Prompt（如果存在）
let aiPrompt = null;
try {
  const promptFile = readFileSync('.ai-prompt.txt', 'utf-8');
  aiPrompt = promptFile.trim();
  console.log('📝 使用用户确认的 Prompt');
} catch {
  console.log('📝 使用默认 Prompt');
}

// 处理每个仓库
const results = [];
for (let i = 0; i < trendingData.repos.length; i++) {
  const repo = trendingData.repos[i];
  const dirName = repo.full_name.replace('/', '-');
  const trendingDir = join('trending', dirName);

  console.log(`\n[${i + 1}/${trendingData.repos.length}] 处理 ${repo.full_name}...`);

  try {
    if (!existsSync(trendingDir)) {
      mkdirSync(trendingDir, { recursive: true });
    }

    console.log(`   🤖 调用 AI 分析...`);
    const analysis = await analyzeRepo(repo, aiPrompt);
    const markdown = generateMarkdown(repo, analysis);
    writeFileSync(join(trendingDir, 'README.md'), markdown);

    console.log(`   ✅ 完成`);
    results.push({ repo: repo.full_name, status: 'success' });

    // 避免 API 限流
    if (i < trendingData.repos.length - 1) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  } catch (error) {
    console.error(`   ❌ 失败: ${error.message}`);
    results.push({ repo: repo.full_name, status: 'failed', error: error.message });
  }
}

console.log(`\n📊 处理完成！成功: ${results.filter(r => r.status === 'success').length}, 失败: ${results.filter(r => r.status === 'failed').length}`);
```

**Checkpoint**：项目生成并测试通过

---

### Phase 4: 仓库创建

**目标**：创建 Git 仓库并推送到 GitHub

**步骤**：
1. Git init + commit（自动化，不询问）
2. 调用 `github-repo-publish` skill 创建仓库
3. 配置 GitHub Secrets（自动化，不询问）
4. 推送到 GitHub（自动化，不询问）

**自动化操作**（不询问用户）：

```bash
# Git 初始化
git init
git add .
git commit -m "Initial commit: setup automated collection project"

# 调用 github-repo-publish
# （自动创建仓库并推送）

# 配置 Secrets
gh secret set OPENAI_API_KEY --body "${OPENAI_API_KEY}"
gh secret set GITHUB_TOKEN --body "${GITHUB_TOKEN}"
```

**Checkpoint**：仓库创建并推送成功

---

### Phase 5: Workflow 验证

**目标**：自动触发并验证 Workflow 运行状态

**步骤**：
1. 触发 GitHub Workflow
2. 轮询检查运行状态
3. 如果失败，分析错误日志
4. 尝试自动修复（最多 3 次）
5. 多次失败后让用户协助排查

**自动化验证流程**：

```bash
# 1. 触发 Workflow
gh workflow run collect.yml

# 2. 获取最新的 run ID
RUN_ID=$(gh run list --workflow=collect.yml --limit 1 --json | jq -r '.[0].id')

# 3. 轮询检查状态（最多等待 5 分钟）
for i in {1..30}; do
  STATUS=$(gh run view $RUN_ID --json | jq -r '.status')
  if [ "$STATUS" = "completed" ]; then
    echo "✅ Workflow 运行成功"
    exit 0
  elif [ "$STATUS" = "failed" ]; then
    echo "❌ Workflow 运行失败"
    # 获取错误日志
    gh run view $RUN_ID --log-failed
    exit 1
  fi
  echo "⏳ 等待中... ($i/30)"
  sleep 10
done
```

**错误分析逻辑**：

```javascript
// 分析 Workflow 失败原因
function analyzeFailure(logs) {
  const errorPatterns = [
    {
      pattern: /API key.*invalid/i,
      fix: '检查 GitHub Secrets 中的 API Key 是否正确配置'
    },
    {
      pattern: /permission denied/i,
      fix: '检查 workflow 的 permissions 配置是否正确'
    },
    {
      pattern: /module not found/i,
      fix: '运行 npm install 检查依赖是否完整'
    },
    {
      pattern: /ENOENT.*no such file/i,
      fix: '检查文件路径是否正确，确保所有脚本文件已提交'
    }
  ];

  for (const { pattern, fix } of errorPatterns) {
    if (pattern.test(logs)) {
      return { detected: true, fix };
    }
  }

  return { detected: false, fix: '未知错误，请查看完整日志' };
}
```

**自动修复流程**：

```
修复尝试次数: 0/3

循环:
  1. 分析错误日志
  2. 如果是已知错误:
     - 自动应用修复
     - 提交修复代码
     - 重新触发 Workflow
     - 等待结果
  3. 如果是未知错误或修复失败:
     - 增加尝试次数
  4. 如果达到 3 次:
     - 输出完整错误日志
     - 提供手动排查建议
     - 让用户协助处理
```

**轮询状态脚本** `scripts/verify-workflow.mjs`:

```javascript
#!/usr/bin/env node

import { execSync } from 'child_process';

const WORKFLOW_NAME = process.env.WORKFLOW_NAME || 'collect.yml';
const MAX_ATTEMPTS = 30; // 5 分钟
const RETRY_DELAY = 10000; // 10 秒

async function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function triggerWorkflow() {
  try {
    console.log(`🚀 触发 Workflow: ${WORKFLOW_NAME}`);
    execSync(`gh workflow run ${WORKFLOW_NAME}`, { stdio: 'inherit' });
    return true;
  } catch (error) {
    console.error('❌ 触发失败:', error.message);
    return false;
  }
}

async function getLatestRunId() {
  const result = execSync(
    `gh run list --workflow=${WORKFLOW_NAME} --limit 1 --json`,
    { encoding: 'utf-8' }
  );
  const runs = JSON.parse(result);
  return runs[0]?.id;
}

async function getRunStatus(runId) {
  const result = execSync(
    `gh run view ${runId} --json`,
    { encoding: 'utf-8' }
  );
  const run = JSON.parse(result);
  return run.status;
}

async function getFailedLogs(runId) {
  try {
    const result = execSync(
      `gh run view ${runId} --log-failed`,
      { encoding: 'utf-8' }
    );
    return result;
  } catch (error) {
    return error.stdout || error.message;
  }
}

async function main() {
  // 1. 触发 Workflow
  const triggered = await triggerWorkflow();
  if (!triggered) {
    process.exit(1);
  }

  // 2. 等待 run 创建
  await sleep(5000);

  // 3. 获取 run ID
  const runId = await getLatestRunId();
  if (!runId) {
    console.error('❌ 无法获取 run ID');
    process.exit(1);
  }

  console.log(`📋 Run ID: ${runId}`);

  // 4. 轮询状态
  for (let i = 1; i <= MAX_ATTEMPTS; i++) {
    const status = await getRunStatus(runId);
    console.log(`⏳ 状态检查 ${i}/${MAX_ATTEMPTS}: ${status}`);

    if (status === 'completed') {
      console.log('✅ Workflow 运行成功！');
      process.exit(0);
    }

    if (status === 'failed') {
      console.log('❌ Workflow 运行失败');
      const logs = await getFailedLogs(runId);
      console.log('\n📜 错误日志:\n');
      console.log(logs);
      process.exit(1);
    }

    await sleep(RETRY_DELAY);
  }

  console.log('⏰ 超时：等待时间过长');
  process.exit(1);
}

main();
```

**Checkpoint**：Workflow 运行成功

---

## 复用的配置（来自 trending-skills）

### Workflow 模板

```yaml
name: Collect Data

on:
  workflow_dispatch:
    inputs: {}
  schedule:
    - cron: '{{CRON_SCHEDULE}}'  # 用户配置

permissions:
  contents: write

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Install dependencies
        run: npm install

      - name: Collect data
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          {{#AI_ENABLED}}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          {{/AI_ENABLED}}
        run: node scripts/collect.mjs

      - name: Process data
        if: success()
        run: node scripts/process.mjs

      - name: Commit and push
        run: |
          git config user.name "bot"
          git config user.email "bot@users.noreply.github.com"
          git add -A
          git diff --staged --quiet && exit 0
          git commit -m "chore: update data $(date +%Y-%m-%d)"
          git push
```

---

## 模板文件

详细的模板文件存放在 `templates/` 目录：

| 文件 | 用途 |
|------|------|
| `workflow.yml.tmpl` | GitHub Actions Workflow 模板 |
| `collect.mjs.tmpl` | 采集脚本模板 |
| `process.mjs.tmpl` | 处理脚本模板 |
| `test.mjs.tmpl` | 测试用例模板 |
| `README.md.tmpl` | README 模板 |
| `package.json.tmpl` | package.json 模板 |

---

## 验证

项目生成完成后，验证以下内容：

- [ ] Workflow 语法正确（`actionlint` 或手动检查）
- [ ] 测试用例通过（`node --test`）
- [ ] README 包含完整使用说明
- [ ] .env 文件已创建并包含有效的 API Key
- [ ] .env.example 包含所有必需变量（不含真实值）
- [ ] API 连通性测试通过（`node scripts/test-api.mjs`）
- [ ] Git 仓库已创建
- [ ] GitHub Secrets 已配置
- [ ] 代码已推送到 GitHub
- [ ] Workflow 自动运行成功（通过 `scripts/verify-workflow.mjs`）

---

## Next Up

- [ ] 自定义采集逻辑: 编辑 `scripts/collect.mjs`
- [ ] 添加更多数据源: 扩展 `collect.mjs`
- [ ] 修改采集频率: 编辑 `.github/workflows/collect.yml` 中的 cron 表达式

## 故障排查

如果 Workflow 运行失败，检查以下内容：

### 常见错误

| 错误类型 | 可能原因 | 解决方案 |
|----------|----------|----------|
| `API key invalid` | API Key 配置错误 | 重新运行 `node scripts/test-api.mjs` 验证 Key |
| `permission denied` | GitHub Token 权限不足 | 检查 workflow 的 `permissions` 配置 |
| `module not found` | 依赖未安装 | 在 workflow 中添加 `npm ci` 步骤 |
| `ENOENT no such file` | 文件未提交到 Git | 确保 `.gitignore` 没有排除必要文件 |

### 手动触发 Workflow

```bash
# 手动触发
gh workflow run collect.yml

# 查看运行日志
gh run watch

# 查看失败的日志
gh run view <run-id> --log-failed
```

---

## 示例：使用本 Skill 创建 GitHub Trending 采集器

```
用户: /gh-workflow-generator

Skill: 你想监控什么数据源？
用户: GitHub Trending 仓库

Skill: 采集频率？
用户: 每 30 分钟

Skill: 是否需要 AI 处理？
用户: 是，使用 OpenAI

Skill: [展示生成的 Prompt]
用户: 确认

Skill: [生成项目文件...]
Skill: [运行测试...]
Skill: [创建仓库并推送...]

Skill: 完成！ 仓库地址: https://github.com/user/github-trending-collector
```
