Incantory
Sign in

GitHubTrends

name: GitHubTrends description: 显示GitHub热门项目趋势,生成可视化仪表板。USE WHEN github trends, trending projects, hot repositories, popular github projects, generate dashboard, create webpage. version: 2.0.0

prompts.chatv10 stars · 0 forks · 0 makes≈12K tokens

Customization

Before executing, check for user customizations at: ~/.claude/skills/CORE/USER/SKILLCUSTOMIZATIONS/GitHubTrends/

If this directory exists, load and apply any PREFERENCES.md, configurations, or resources found there. These override default behavior. If the directory does not exist, proceed with skill defaults.

GitHubTrends - GitHub热门项目趋势

快速发现GitHub上最受欢迎的开源项目。


Philosophy

GitHub trending是发现优质开源项目的最佳途径。这个skill让老王我能快速获取当前最热门的项目列表,按时间周期(每日/每周)和编程语言筛选,帮助发现值得学习和贡献的项目。


Quick Start

# 查看本周最热门的项目(默认)
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly

# 查看今日最热门的项目
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts daily

# 按语言筛选
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=TypeScript
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=Python

# 指定显示数量
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --limit=20

When to Use This Skill

Core Triggers - Use this skill when user says:

Direct Requests

  • "show github trends" 或 "github trending"
  • "显示热门项目" 或 "看看有什么热门项目"
  • "what's trending on github" 或 "github hot projects"
  • "本周热门项目" 或 "weekly trending"
  • "今日热门项目" 或 "daily trending"

Discovery Requests

  • "discover popular projects" 或 "发现热门项目"
  • "show repositories trending" 或 "显示trending仓库"
  • "github上什么最火" 或 "what's hot on github"
  • "找点好项目看看" 或 "find good projects"

Language-Specific

  • "TypeScript trending projects" 或 "TypeScript热门项目"
  • "Python trending" 或 "Python热门项目"
  • "show trending Rust projects" 或 "显示Rust热门项目"
  • "Go语言热门项目" 或 "trending Go projects"

Dashboard & Visualization

  • "生成 GitHub trending 仪表板" 或 "generate trending dashboard"
  • "创建趋势网页" 或 "create trending webpage"
  • "生成交互式报告" 或 "generate interactive report"
  • "export trending dashboard" 或 "导出仪表板"
  • "可视化 GitHub 趋势" 或 "visualize github trends"

Core Capabilities

获取趋势列表

  • 每日趋势 - 过去24小时最热门项目
  • 每周趋势 - 过去7天最热门项目(默认)
  • 语言筛选 - 按编程语言过滤(TypeScript, Python, Go, Rust等)
  • 自定义数量 - 指定返回项目数量(默认10个)

生成可视化仪表板 🆕

  • 交互式HTML - 生成交互式网页仪表板
  • 数据可视化 - 语言分布饼图、Stars增长柱状图
  • 技术新闻 - 集成 Hacker News 技术资讯
  • 实时筛选 - 按语言筛选、排序、搜索功能
  • 响应式设计 - 支持桌面、平板、手机

项目信息

  • 项目名称和描述
  • Star数量和变化
  • 编程语言
  • 项目URL

Tool Usage

GetTrending.ts

Location: Tools/GetTrending.ts

功能: 从GitHub获取trending项目列表

参数:

  • period - 时间周期:daily 或 weekly(默认:weekly)
  • --language - 编程语言筛选(可选)
  • --limit - 返回项目数量(默认:10)

使用示例:

# 基本用法
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly

# 带参数
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=TypeScript --limit=15

# 简写
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts daily -l=Python

实现方式: 使用 GitHub官方trending页面:https://github.com/trending 通过 fetch API 读取页面内容并解析


GenerateDashboard.ts 🆕

Location: Tools/GenerateDashboard.ts

功能: 生成交互式数据可视化仪表板HTML文件

参数:

  • --period - 时间周期:daily 或 weekly(默认:weekly)
  • --language - 编程语言筛选(可选)
  • --limit - 返回项目数量(默认:10)
  • --include-news - 包含技术新闻
  • --news-count - 新闻数量(默认:10)
  • --output - 输出文件路径(默认:./github-trends.html)

使用示例:

# 基本用法 - 生成本周仪表板
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts

# 包含技术新闻
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts --include-news

# TypeScript 项目每日仪表板
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts \
  --period daily \
  --language TypeScript \
  --limit 20 \
  --include-news \
  --output ~/ts-daily.html

实现方式:

  • 获取 GitHub trending 项目数据
  • 获取 Hacker News 技术新闻
  • 使用 Handlebars 模板引擎渲染 HTML
  • 集成 Tailwind CSS 和 Chart.js
  • 生成完全独立的 HTML 文件(通过 CDN 加载依赖)

Output Format

# GitHub Trending Projects - Weekly (2025-01-19)

## 1. vercel/next.js - ⭐ 125,342 (+1,234 this week)
**Language:** TypeScript
**Description:** The React Framework for the Web
**URL:** https://github.com/vercel/next.js

## 2. microsoft/vscode - ⭐ 160,890 (+987 this week)
**Language:** TypeScript
**Description:** Visual Studio Code
**URL:** https://github.com/microsoft/vscode

...

---
📊 Total: 10 projects | Language: All | Period: Weekly

Supported Languages

常用编程语言筛选:

  • TypeScript - TypeScript项目
  • JavaScript - JavaScript项目
  • Python - Python项目
  • Go - Go语言项目
  • Rust - Rust项目
  • Java - Java项目
  • C++ - C++项目
  • Ruby - Ruby项目
  • Swift - Swift项目
  • Kotlin - Kotlin项目

Workflow Integration

这个skill可以被其他skill调用:

  • OSINT - 在调查技术栈时发现热门工具
  • Research - 研究特定语言生态系统的趋势
  • System - 发现有用的PAI相关项目

Technical Notes

数据来源: GitHub官方trending页面 更新频率: 每小时更新一次 无需认证: 使用公开页面,无需GitHub API token 解析方式: 通过HTML解析提取项目信息

错误处理:

  • 网络错误会显示友好提示
  • 解析失败会返回原始HTML供调试
  • 支持的语言参数不区分大小写

Future Enhancements

可能的未来功能:

  • 支持月度趋势(如果GitHub提供)
  • 按stars范围筛选(1k+, 10k+, 100k+)
  • 保存历史数据用于趋势分析
  • 集成到其他skill的自动化工作流

Voice Notification

When executing a workflow, do BOTH:

  1. Send voice notification:

    curl -s -X POST http://localhost:8888/notify \
      -H "Content-Type: application/json" \
      -d '{"message": "Running the GitHubTrends workflow"}' \
      > /dev/null 2>&1 &
    
  2. Output text notification:

    Running the **GitHubTrends** workflow...
    

Full documentation: ~/.claude/skills/CORE/SkillNotifications.md FILE:README.md

GitHubTrends Skill

快速发现GitHub上最受欢迎的开源项目,生成可视化仪表板!

功能特性

基础功能

  • ✅ 获取每日/每周热门项目列表
  • ✅ 按编程语言筛选(TypeScript, Python, Go, Rust等)
  • ✅ 自定义返回项目数量
  • ✅ 显示Star总数和周期增长
  • ✅ 无需GitHub API token

可视化仪表板 🆕

  • ✨ 交互式HTML - 生成交互式网页仪表板
  • 📊 数据可视化 - 语言分布饼图、Stars增长柱状图
  • 📰 技术新闻 - 集成 Hacker News 最新资讯
  • 🔍 实时筛选 - 按语言筛选、排序、搜索
  • 📱 响应式设计 - 支持桌面、平板、手机
  • 🎨 美观界面 - Tailwind CSS + GitHub 风格

快速开始

查看本周热门项目(默认)

bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly

查看今日热门项目

bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts daily

按语言筛选

# TypeScript热门项目
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=TypeScript

# Python热门项目
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=Python

# Go热门项目
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly -l=Go

指定返回数量

# 返回20个项目
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --limit=20

# 组合使用:返回15个TypeScript项目
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=TypeScript --limit=15

生成可视化仪表板 🆕

基本用法

# 生成本周趋势仪表板(默认)
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts

包含技术新闻

# 生成包含 Hacker News 的仪表板
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts --include-news

高级选项

# 生成 TypeScript 项目每日仪表板,包含 15 条新闻
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts \
  --period daily \
  --language TypeScript \
  --limit 20 \
  --include-news \
  --news-count 15 \
  --output ~/Downloads/ts-daily-trends.html

仪表板功能

生成的 HTML 文件包含:

  • 统计概览 - 总项目数、总 stars、top 项目
  • 语言分布图 - 饼图展示各语言占比
  • Stars 增长图 - 柱状图展示增长趋势
  • 项目卡片 - 美观的卡片式项目展示
  • 技术新闻 - Hacker News 最新资讯
  • 交互功能 - 筛选、排序、搜索
  • 响应式 - 自适应各种屏幕尺寸

输出示例

# GitHub Trending Projects - Weekly (2026-01-19)

📊 **Total:** 10 projects | **Language:** All | **Period:** Weekly

---

## 1. vercel/next.js - ⭐ 125,342 (+1,234 this week)
**Language:** TypeScript
**Description:** The React Framework for the Web
**URL:** https://github.com/vercel/next.js

## 2. microsoft/vscode - ⭐ 160,890 (+987 this week)
**Language:** TypeScript
**Description:** Visual Studio Code
**URL:** https://github.com/microsoft/vscode

...

参数说明

参数说明默认值可选值
period时间周期weeklydaily, weekly
--language编程语言筛选全部TypeScript, Python, Go, Rust, Java等
--limit返回项目数量10任意正整数

支持的语言

常用的编程语言都可以作为筛选条件:

  • TypeScript - TypeScript项目
  • JavaScript - JavaScript项目
  • Python - Python项目
  • Go - Go语言项目
  • Rust - Rust项目
  • Java - Java项目
  • C++ - C++项目
  • Ruby - Ruby项目
  • Swift - Swift项目
  • Kotlin - Kotlin项目

Skill 触发词

当你说以下任何内容时,这个skill会被触发:

  • "show github trends" / "github trending"
  • "显示热门项目" / "看看有什么热门项目"
  • "weekly trending" / "本周热门项目"
  • "daily trending" / "今日热门项目"
  • "TypeScript trending" / "Python trending"
  • "what's hot on github" / "github上什么最火"

技术实现

  • 数据源: GitHub官方trending页面 (https://github.com/trending)
  • 解析方式: HTML解析提取项目信息
  • 认证: 无需GitHub API token
  • 更新频率: 每小时更新一次

目录结构

~/.claude/skills/GitHubTrends/
├── SKILL.md              # Skill主文件
├── README.md             # 使用文档(本文件)
├── Tools/
│   └── GetTrending.ts    # 获取trending数据的工具
└── Workflows/
    └── GetTrending.md    # 工作流文档

注意事项

  1. 网络要求: 需要能访问GitHub官网
  2. 更新频率: 数据每小时更新,不是实时
  3. 解析准确性: GitHub页面结构变化可能影响解析,如遇问题请检查 /tmp/github-trending-debug-*.html
  4. 语言参数: 不区分大小写,--language=typescript 和 --language=TypeScript 效果相同

已知问题

  • GitHub trending页面的HTML结构复杂,某些项目的URL和名称可能解析不完整
  • 如果GitHub页面结构变化,工具可能需要更新解析逻辑

未来改进

  • 支持保存历史数据用于趋势分析
  • 按stars范围筛选(1k+, 10k+, 100k+)
  • 更智能的HTML解析(使用HTML解析库而非正则)
  • 集成到其他skill的自动化工作流

贡献

如果发现问题或有改进建议,欢迎提出!


Made with ❤️ by 老王 FILE:Tools/GetTrending.ts #!/usr/bin/env bun /**

  • GitHub Trending Projects Fetcher
  • 从GitHub获取trending项目列表
  • 支持每日/每周趋势,按语言筛选 */

import { $ } from "bun";

interface TrendingProject { rank: number; name: string; description: string; language: string; stars: string; starsThisPeriod: string; url: string; }

interface TrendingOptions { period: "daily" | "weekly"; language?: string; limit: number; }

function buildTrendingUrl(options: TrendingOptions): string { const baseUrl = "https://github.com/trending"; const since = options.period === "daily" ? "daily" : "weekly"; let url = ${baseUrl}?since=${since}; if (options.language) { url += &language=${encodeURIComponent(options.language.toLowerCase())}; } return url; }

function parseTrendingProjects(html: string, limit: number): TrendingProject[] { const projects: TrendingProject[] = []; try { const articleRegex = /<article[^>]>([\s\S]?)</article>/g; const articles = html.match(articleRegex) || []; const articlesToProcess = articles.slice(0, limit); articlesToProcess.forEach((article, index) => { try { const headingMatch = article.match(/<h[12][^>]>([\s\S]?)</h[12]>/); let repoName: string | null = null; if (headingMatch) { const headingContent = headingMatch[1]; const validLinkMatch = headingContent.match( /<a[^>]href="/([^/"/]+/[^/"/]+)"[^>]>(?![^<]login)/ ); if (validLinkMatch) { repoName = validLinkMatch[1]; } } if (!repoName) { const repoMatch = article.match( /<a[^>]href="/([a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)"[^>]>(?!.(?:login|stargazers|forks|issues))/ ); repoName = repoMatch ? repoMatch[1] : null; } const descMatch = article.match(/<p[^>]class="[^"]col-9[^"]"[^>]>([\s\S]?)</p>/); const description = descMatch ? descMatch[1] .replace(/<[^>]+>/g, "") .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, '"') .trim() .substring(0, 200) : "No description"; const langMatch = article.match(/<span[^>]itemprop="programmingLanguage"[^>]>([^<]+)</span>/); const language = langMatch ? langMatch[1].trim() : "Unknown"; const starsMatch = article.match(/<a[^>]href="/[^"]+/stargazers"[^>]>(\d[\d,])\sstars?/); const totalStars = starsMatch ? starsMatch[1] : "0"; const starsAddedMatch = article.match(/(\d[\d,])\sstars?\s(?:today|this week)/i); const starsAdded = starsAddedMatch ? +${starsAddedMatch[1]} : ""; if (repoName && !repoName.includes("login") && !repoName.includes("return_to")) { projects.push({ rank: index + 1, name: repoName, description, language, stars: totalStars, starsThisPeriod: starsAdded, url: https://github.com/${repoName}, }); } } catch (error) { console.error(解析第${index + 1}个项目失败:, error); } }); } catch (error) { console.error("解析trending项目失败:", error); } return projects; }

function formatProjects(projects: TrendingProject[], options: TrendingOptions): string { if (projects.length === 0) { return "# GitHub Trending - No Projects Found\n\n没有找到trending项目,可能是网络问题或页面结构变化。"; } const periodLabel = options.period === "daily" ? "Daily" : "Weekly"; const languageLabel = options.language ? Language: ${options.language} : "Language: All"; const today = new Date().toISOString().split("T")[0]; let output = # GitHub Trending Projects - ${periodLabel} (${today})\n\n; output += 📊 **Total:** ${projects.length} projects | **${languageLabel}** | **Period:** ${periodLabel}\n\n; output += ---\n\n; projects.forEach((project) => { output += ## ${project.rank}. ${project.name} - ⭐ ${project.stars}; if (project.starsThisPeriod) { output += (${project.starsThisPeriod} this ${options.period}); } output += \n; output += **Language:** ${project.language}\n; output += **Description:** ${project.description}\n; output += **URL:** ${project.url}\n\n; }); output += ---\n; output += 📊 Data from: https://github.com/trending\n; return output; }

async function main() { const args = process.argv.slice(2); let period: "daily" | "weekly" = "weekly"; let language: string | undefined; let limit = 10; for (const arg of args) { if (arg === "daily" || arg === "weekly") { period = arg; } else if (arg.startsWith("--language=")) { language = arg.split("=")[1]; } else if (arg.startsWith("-l=")) { language = arg.split("=")[1]; } else if (arg.startsWith("--limit=")) { limit = parseInt(arg.split("=")[1]) || 10; } } const options: TrendingOptions = { period, language, limit }; try { const url = buildTrendingUrl(options); console.error(正在获取 GitHub trending 数据: ${url}); const response = await fetch(url); if (!response.ok) { throw new Error(HTTP ${response.status}: ${response.statusText}); } const html = await response.text(); const projects = parseTrendingProjects(html, limit); const formatted = formatProjects(projects, options); console.log(formatted); if (projects.length === 0) { const debugFile = /tmp/github-trending-debug-${Date.now()}.html; await Bun.write(debugFile, html); console.error(\n调试: 原始HTML已保存到 ${debugFile}); } } catch (error) { console.error("❌ 获取trending数据失败:"); console.error(error); process.exit(1); } }

main(); FILE:Workflows/GetTrending.md

GetTrending Workflow

获取GitHub trending项目列表的工作流程。

Description

这个工作流使用 GetTrending.ts 工具从GitHub获取当前最热门的项目列表,支持按时间周期(每日/每周)和编程语言筛选。

When to Use

当用户请求以下任何内容时使用此工作流:

  • "show github trends" / "github trending"
  • "显示热门项目" / "看看有什么热门项目"
  • "weekly trending" / "本周热门项目"
  • "daily trending" / "今日热门项目"
  • "TypeScript trending" / "Python trending" / 按语言筛选
  • "what's hot on github" / "github上什么最火"

Workflow Steps

Step 1: 确定参数

向用户确认或推断以下参数:

  • 时间周期: daily (每日) 或 weekly (每周,默认)
  • 编程语言: 可选(如 TypeScript, Python, Go, Rust等)
  • 项目数量: 默认10个

Step 2: 执行工具

运行 GetTrending.ts 工具:

# 基本用法(本周,全部语言,10个项目)
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly

# 指定语言
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --language=TypeScript

# 指定数量
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts weekly --limit=20

# 组合参数
bun ~/.claude/skills/GitHubTrends/Tools/GetTrending.ts daily --language=Python --limit=15

Step 3: 显示结果

工具会自动格式化输出,包括:

  • 项目排名
  • 项目名称
  • Star总数和周期内增长
  • 编程语言
  • 项目描述
  • GitHub URL

Step 4: 后续操作(可选)

根据用户需求,可以:

  • 打开某个项目页面
  • 使用其他skill进一步分析项目
  • 将结果保存到文件供后续参考

Integration with Other Skills

  • OSINT: 在调查技术栈时发现热门工具
  • Research: 研究特定语言生态系统的趋势
  • Browser: 打开项目页面进行详细分析

Notes

  • 数据每小时更新一次
  • 无需GitHub API token
  • 使用公开的GitHub trending页面
  • 支持的语言参数不区分大小写 FILE:Tools/GenerateDashboard.ts #!/usr/bin/env bun /**
  • GitHub Trending Dashboard Generator
  • 生成交互式数据可视化仪表板
  • 使用方式:
  • ./GenerateDashboard.ts [options]
  • 选项:
  • --period - daily | weekly (默认: weekly)
  • --language - 编程语言筛选 (可选)
  • --limit - 项目数量 (默认: 10)
  • --include-news - 包含技术新闻
  • --news-count - 新闻数量 (默认: 10)
  • --theme - light | dark | auto (默认: auto)
  • --output - 输出文件路径 (默认: ./github-trends.html)
  • 示例:
  • ./GenerateDashboard.ts
  • ./GenerateDashboard.ts --period daily --language TypeScript --include-news
  • ./GenerateDashboard.ts --limit 20 --output ~/trends.html */

import Handlebars from 'handlebars'; import type { DashboardOptions, TrendingProject, TechNewsItem, TemplateData } from './Lib/types'; import { registerHelpers, renderTemplate } from './Lib/template-helpers'; import { analyzeData } from './Lib/visualization-helpers';

// 注册 Handlebars 辅助函数 registerHelpers();

/**

  • 构建 GitHub trending URL */ function buildTrendingUrl(options: DashboardOptions): string { const baseUrl = "https://github.com/trending"; const since = options.period === "daily" ? "daily" : "weekly"; let url = ${baseUrl}?since=${since};

if (options.language) { url += &language=${encodeURIComponent(options.language.toLowerCase())}; }

return url; }

/**

  • 解析 HTML 提取 trending 项目
  • (从 GetTrending.ts 复制的逻辑) */ async function getTrendingProjects(options: DashboardOptions): Promise<TrendingProject[]> { const url = buildTrendingUrl(options);

console.error(正在获取 GitHub trending 数据: ${url});

const response = await fetch(url); if (!response.ok) { throw new Error(HTTP ${response.status}: ${response.statusText}); }

const html = await response.text(); return parseTrendingProjects(html, options.limit); }

/**

  • 解析 HTML */ function parseTrendingProjects(html: string, limit: number): TrendingProject[] { const projects: TrendingProject[] = [];

try { const articleRegex = /<article[^>]>([\s\S]?)</article>/g; const articles = html.match(articleRegex) || []; const articlesToProcess = articles.slice(0, limit);

articlesToProcess.forEach((article, index) => {
  try {
    const headingMatch = article.match(/<h[12][^>]*>([\s\S]*?)<\/h[12]>/);
    let repoName: string | null = null;

    if (headingMatch) {
      const headingContent = headingMatch[1];
      const validLinkMatch = headingContent.match(
        /<a[^>]*href="\/([^\/"\/]+\/[^\/"\/]+)"[^>]*>(?![^<]*login)/
      );
      if (validLinkMatch) {
        repoName = validLinkMatch[1];
      }
    }

    if (!repoName) {
      const repoMatch = article.match(
        /<a[^>]*href="\/([a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+)"[^>]*>(?!.*(?:login|stargazers|forks|issues))/
      );
      repoName = repoMatch ? repoMatch[1] : null;
    }

    const descMatch = article.match(/<p[^>]*class="[^"]*col-9[^"]*"[^>]*>([\s\S]*?)<\/p>/);
    const description = descMatch
      ? descMatch[1]
          .replace(/<[^>]+>/g, "")
          .replace(/&amp;/g, "&")
          .replace(/&lt;/g, "<")
          .replace(/&gt;/g, ">")
          .replace(/&quot;/g, '"')
          .trim()
          .substring(0, 200)
      : "No description";

    const langMatch = article.match(/<span[^>]*itemprop="programmingLanguage"[^>]*>([^<]+)<\/span>/);
    const language = langMatch ? langMatch[1].trim() : "Unknown";

    // 提取stars总数 - GitHub 改了 HTML 结构,数字在 SVG 后面
    const starsMatch = article.match(/stargazers[^>]*>[\s\S]*?<\/svg>\s*([\d,]+)/);
    const totalStars = starsMatch ? starsMatch[1] : "0";

    // 尝试提取新增stars - 格式:XXX stars today/this week
    const starsAddedMatch = article.match(/(\d[\d,]*)\s+stars?\s+(?:today|this week)/);
    const starsAdded = starsAddedMatch ? `+${starsAddedMatch[1]}` : "";

    if (repoName && !repoName.includes("login") && !repoName.includes("return_to")) {
      projects.push({
        rank: index + 1,
        name: repoName,
        description,
        language,
        stars: totalStars,
        starsThisPeriod: starsAdded,
        url: `https://github.com/${repoName}`,
      });
    }
  } catch (error) {
    console.error(`解析第${index + 1}个项目失败:`, error);
  }
});

} catch (error) { console.error("解析trending项目失败:", error); }

return projects; }

/**

try { const response = await fetch(${HN_API}?tags=story&hitsPerPage=${count}); if (!response.ok) { throw new Error(HTTP ${response.status}: ${response.statusText}); }

const data = await response.json();

return data.hits.slice(0, count).map((hit: any) => ({
  id: hit.objectID,
  title: hit.title,
  url: hit.url || `https://news.ycombinator.com/item?id=${hit.objectID}`,
  source: 'hackernews',
  points: hit.points || 0,
  comments: hit.num_comments || 0,
  timestamp: new Date(hit.created_at).toISOString(),
  tags: hit._tags || []
}));

} catch (error) { console.error('获取 Hacker News 失败:', error); return []; } }

/**

  • 生成仪表板 */ async function generateDashboard(options: DashboardOptions): Promise { try { console.error('🚀 开始生成 GitHub Trending Dashboard...\n');

    // 1. 获取 GitHub Trending 数据 const projects = await getTrendingProjects(options); console.error(✅ 获取到 ${projects.length} 个项目);

    // 2. 获取技术新闻(如果启用) let news: TechNewsItem[] = []; if (options.includeNews) { news = await getTechNews(options.newsCount); console.error(✅ 获取到 ${news.length} 条新闻); }

    // 3. 分析数据 const analytics = analyzeData(projects); console.error(✅ 数据分析完成);

    // 4. 准备模板数据 const templateData: TemplateData = { title: 'GitHub Trending Dashboard', generatedAt: new Date().toLocaleString('zh-CN'), period: options.period === 'daily' ? 'Daily' : 'Weekly', projects, news, analytics, options };

    // 5. 渲染模板 const templatePath = ${import.meta.dir}/../Templates/dashboard.hbs; const templateContent = await Bun.file(templatePath).text(); const template = Handlebars.compile(templateContent); const html = template(templateData); console.error(✅ 模板渲染完成);

    // 6. 保存文件 await Bun.write(options.output, html); console.error(\n🎉 仪表板生成成功!); console.error(📄 文件路径: ${options.output}); console.error(\n💡 在浏览器中打开查看效果!);

} catch (error) { console.error('\n❌ 生成仪表板失败:'); console.error(error); process.exit(1); } }

/**

  • 解析命令行参数 */ function parseArgs(): DashboardOptions { const args = process.argv.slice(2);

const options: DashboardOptions = { period: 'weekly', limit: 10, output: './github-trends.html', includeNews: false, newsCount: 10, theme: 'auto' };

for (let i = 0; i < args.length; i++) { const arg = args[i];

switch (arg) {
  case '--period':
    options.period = args[++i] === 'daily' ? 'daily' : 'weekly';
    break;
  case '--language':
    options.language = args[++i];
    break;
  case '--limit':
    options.limit = parseInt(args[++i]) || 10;
    break;
  case '--include-news':
    options.includeNews = true;
    break;
  case '--news-count':
    options.newsCount = parseInt(args[++i]) || 10;
    break;
  case '--theme':
    options.theme = args[++i] === 'light' || args[++i] === 'dark' ? args[i] : 'auto';
    break;
  case '--output':
    options.output = args[++i];
    break;
  default:
    if (arg.startsWith('--output=')) {
      options.output = arg.split('=')[1];
    } else if (arg.startsWith('--language=')) {
      options.language = arg.split('=')[1];
    } else if (arg.startsWith('--limit=')) {
      options.limit = parseInt(arg.split('=')[1]) || 10;
    }
}

}

return options; }

/**

  • 主函数 */ async function main() { const options = parseArgs(); await generateDashboard(options); }

// 如果直接运行此脚本 if (import.meta.main) { main(); }

// 导出供其他模块使用 export { generateDashboard }; export type { DashboardOptions }; FILE:Tools/GetTechNews.ts #!/usr/bin/env bun /**

  • Tech News Fetcher
  • 从 Hacker News 和其他来源获取技术新闻
  • 使用方式:
  • ./GetTechNews.ts [count]
  • 参数:
  • count - 获取新闻数量 (默认: 10)
  • 示例:
  • ./GetTechNews.ts
  • ./GetTechNews.ts 20 */

import Parser from 'rss-parser'; import type { TechNewsItem } from './Lib/types';

const HN_API = 'https://hn.algolia.com/api/v1/search'; const parser = new Parser();

/**

  • 从 Hacker News Algolia API 获取新闻 */ async function getHackerNews(count: number): Promise<TechNewsItem[]> { try { const response = await fetch(${HN_API}?tags=front_page&hits=${count}); if (!response.ok) { throw new Error(HTTP ${response.status}: ${response.statusText}); }

    const data = await response.json();

    return data.hits.map((hit: any) => ({ id: hit.objectID, title: hit.title, url: hit.url || https://news.ycombinator.com/item?id=${hit.objectID}, source: 'hackernews', points: hit.points || 0, comments: hit.num_comments || 0, timestamp: new Date(hit.created_at).toISOString(), tags: hit._tags || [] })); } catch (error) { console.error('获取 Hacker News 失败:', error); return []; } }

/**

  • 从 Hacker News RSS 获取新闻(备用方案) */ async function getHackerNewsRSS(count: number): Promise<TechNewsItem[]> { try { const feed = await parser.parseURL('https://news.ycombinator.com/rss');

    return feed.items.slice(0, count).map((item: any) => ({ id: item.guid || item.link, title: item.title || 'No title', url: item.link, source: 'hackernews', timestamp: item.pubDate || new Date().toISOString(), tags: ['hackernews', 'rss'] })); } catch (error) { console.error('获取 Hacker News RSS 失败:', error); return []; } }

/**

  • 获取技术新闻(主函数) */ async function getTechNews(count: number = 10): Promise<TechNewsItem[]> { console.error(正在获取技术新闻(${count}条)...);

// 优先使用 Hacker News API let news = await getHackerNews(count);

// 如果失败,尝试 RSS 备用 if (news.length === 0) { console.error('Hacker News API 失败,尝试 RSS...'); news = await getHackerNewsRSS(count); }

console.error(✅ 获取到 ${news.length} 条新闻); return news; }

/**

  • CLI 入口 */ async function main() { const args = process.argv.slice(2); const count = parseInt(args[0]) || 10;

try { const news = await getTechNews(count);

// 输出 JSON 格式(便于程序调用)
console.log(JSON.stringify(news, null, 2));

} catch (error) { console.error('❌ 获取新闻失败:'); console.error(error); process.exit(1); } }

// 如果直接运行此脚本 if (import.meta.main) { main(); }

// 导出供其他模块使用 export { getTechNews }; export type { TechNewsItem }; FILE:Tools/Lib/types.ts /**

  • GitHubTrends - 类型定义
  • 定义所有 TypeScript 接口和类型 */

/**

  • GitHub Trending 项目 */ export interface TrendingProject { rank: number; name: string; description: string; language: string; stars: string; starsThisPeriod: string; url: string; }

/**

  • 技术新闻条目 */ export interface TechNewsItem { id: string; title: string; url: string; source: string; // 'hackernews', 'reddit', etc. points?: number; comments?: number; timestamp: string; tags: string[]; }

/**

  • 仪表板生成选项 */ export interface DashboardOptions { period: 'daily' | 'weekly'; language?: string; limit: number; output: string; includeNews: boolean; newsCount: number; theme: 'light' | 'dark' | 'auto'; }

/**

  • 数据分析结果 */ export interface Analytics { languageDistribution: Record<string, number>; totalStars: number; topProject: TrendingProject; growthStats: { highest: TrendingProject; average: number; }; }

/**

  • Trending 查询选项(用于 GetTrending.ts) */ export interface TrendingOptions { period: "daily" | "weekly"; language?: string; limit: number; }

/**

  • 图表数据 */ export interface ChartData { labels: string[]; data: number[]; colors: string[]; }

/**

  • 模板渲染数据 / export interface TemplateData { title: string; generatedAt: string; period: string; projects: TrendingProject[]; news?: TechNewsItem[]; analytics: Analytics; options: DashboardOptions; } FILE:Tools/Lib/template-helpers.ts /*
  • Template Helpers
  • Handlebars 自定义辅助函数 */

import Handlebars from 'handlebars';

/**

  • 注册所有自定义辅助函数 */ export function registerHelpers(): void { // 格式化数字(添加千位分隔符) Handlebars.registerHelper('formatNumber', (value: number) => { return value.toLocaleString(); });

// 截断文本 Handlebars.registerHelper('truncate', (str: string, length: number = 100) => { if (str.length <= length) return str; return str.substring(0, length) + '...'; });

// 格式化日期 Handlebars.registerHelper('formatDate', (dateStr: string) => { const date = new Date(dateStr); return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }); });

// JSON 序列化(用于内嵌数据) Handlebars.registerHelper('json', (context: any) => { return JSON.stringify(context); });

// 条件判断 Handlebars.registerHelper('eq', (a: any, b: any) => { return a === b; });

Handlebars.registerHelper('ne', (a: any, b: any) => { return a !== b; });

Handlebars.registerHelper('gt', (a: number, b: number) => { return a > b; });

Handlebars.registerHelper('lt', (a: number, b: number) => { return a < b; }); }

/**

  • 渲染模板 */ export async function renderTemplate( templatePath: string, data: any ): Promise { const templateContent = await Bun.file(templatePath).text(); const template = Handlebars.compile(templateContent); return template(data); }

export default { registerHelpers, renderTemplate }; FILE:Tools/Lib/visualization-helpers.ts /**

  • Visualization Helpers
  • 数据分析和可视化辅助函数 */

import type { TrendingProject, Analytics } from './types';

/**

  • 分析项目数据 */ export function analyzeData(projects: TrendingProject[]): Analytics { // 语言分布统计 const languageDistribution: Record<string, number> = {}; projects.forEach(project => { const lang = project.language; languageDistribution[lang] = (languageDistribution[lang] || 0) + 1; });

// 总 stars 数 const totalStars = projects.reduce((sum, project) => { return sum + parseInt(project.stars.replace(/,/g, '') || 0); }, 0);

// 找出 top project const topProject = projects.reduce((top, project) => { const topStars = parseInt(top.stars.replace(/,/g, '') || 0); const projStars = parseInt(project.stars.replace(/,/g, '') || 0); return projStars > topStars ? project : top; }, projects[0]);

// 增长统计 const projectsWithGrowth = projects.filter(p => p.starsThisPeriod); const growthValues = projectsWithGrowth.map(p => parseInt(p.starsThisPeriod.replace(/[+,]/g, '') || 0) );

const highestGrowth = projectsWithGrowth.reduce((highest, project) => { const highestValue = parseInt(highest.starsThisPeriod.replace(/[+,]/g, '') || 0); const projValue = parseInt(project.starsThisPeriod.replace(/[+,]/g, '') || 0); return projValue > highestValue ? project : highest; }, projectsWithGrowth[0] || projects[0]);

const averageGrowth = growthValues.length > 0 ? Math.round(growthValues.reduce((a, b) => a + b, 0) / growthValues.length) : 0;

// 提取唯一语言列表(用于筛选) const languages = Object.keys(languageDistribution).sort();

// 生成图表数据 const growthData = projects.slice(0, 10).map(p => ({ name: p.name.split('/')[1] || p.name, growth: parseInt(p.starsThisPeriod.replace(/[+,]/g, '') || 0) }));

return { languageDistribution, totalStars, topProject, growthStats: { highest: highestGrowth, average: averageGrowth }, languages, growthData }; }

/**

  • 格式化 stars 数字 */ export function formatStars(starsStr: string): number { return parseInt(starsStr.replace(/,/g, '') || 0); }

/**

  • 解析增长数值 */ export function parseGrowth(growthStr: string): number { if (!growthStr) return 0; return parseInt(growthStr.replace(/[+,]/g, '') || 0); }

export default { analyzeData, formatStars, parseGrowth }; FILE:Templates/dashboard.hbs

<!-- 统计概览 -->
<section class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
  <div class="stat-card rounded-xl p-6 text-white shadow-lg">
    <h3 class="text-lg font-semibold opacity-90">项目总数</h3>
    <p class="text-4xl font-bold mt-2">{{projects.length}}</p>
    <p class="text-sm opacity-75 mt-1">{{period}} 热门趋势</p>
  </div>

  <div class="bg-gradient-to-br from-green-500 to-emerald-600 rounded-xl p-6 text-white shadow-lg">
    <h3 class="text-lg font-semibold opacity-90">总 Stars 数</h3>
    <p class="text-4xl font-bold mt-2">{{analytics.totalStars}}</p>
    <p class="text-sm opacity-75 mt-1">所有项目总计</p>
  </div>

  <div class="bg-gradient-to-br from-orange-500 to-red-500 rounded-xl p-6 text-white shadow-lg">
    <h3 class="text-lg font-semibold opacity-90">最热项目</h3>
    <p class="text-xl font-bold mt-2 truncate">{{analytics.topProject.name}}</p>
    <p class="text-sm opacity-75 mt-1">{{analytics.topProject.stars}} stars</p>
  </div>
</section>

<!-- 筛选和搜索 -->
<section class="bg-white rounded-xl shadow-sm p-6 mb-8">
  <div class="flex flex-wrap gap-4 items-center">
    <div class="flex-1 min-w-64">
      <label class="block text-sm font-medium text-gray-700 mb-1">搜索项目</label>
      <input
        type="text"
        id="searchInput"
        placeholder="按名称或描述搜索..."
        class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-github-accent focus:border-transparent"
        oninput="filterProjects()"
      >
    </div>

    <div>
      <label class="block text-sm font-medium text-gray-700 mb-1">语言筛选</label>
      <select
        id="languageFilter"
        class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-github-accent focus:border-transparent"
        onchange="filterProjects()"
      >
        <option value="all">全部语言</option>
        {{#each analytics.languages}}
          <option value="{{this}}">{{this}}</option>
        {{/each}}
      </select>
    </div>

    <div>
      <label class="block text-sm font-medium text-gray-700 mb-1">排序方式</label>
      <select
        id="sortSelect"
        class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-github-accent focus:border-transparent"
        onchange="sortProjects()"
      >
        <option value="rank">排名</option>
        <option value="stars">总 Stars</option>
        <option value="growth">本期增长</option>
      </select>
    </div>
  </div>
</section>

<!-- 语言分布图表 -->
<section class="bg-white rounded-xl shadow-sm p-6 mb-8">
  <h2 class="text-2xl font-bold text-gray-900 mb-4">📊 语言分布</h2>
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
    <div>
      <canvas id="languageChart"></canvas>
    </div>
    <div>
      <canvas id="growthChart"></canvas>
    </div>
  </div>
</section>

<!-- Trending Projects -->
<section class="mb-8">
  <h2 class="text-2xl font-bold text-gray-900 mb-4">🔥 热门项目</h2>
  <div id="projects-container" class="grid grid-cols-1 gap-4">
    {{#each projects}}
    <div class="project-card bg-white rounded-xl shadow-sm p-6 border border-gray-200"
         data-rank="{{rank}}"
         data-language="{{language}}"
         data-stars="{{stars}}"
         data-growth="{{starsThisPeriod}}"
         data-name="{{name}}"
         data-description="{{description}}">
      <div class="flex items-start justify-between">
        <div class="flex-1">
          <div class="flex items-center gap-3 mb-2">
            <span class="text-2xl font-bold text-github-accent">#{{rank}}</span>
            <h3 class="text-xl font-semibold text-gray-900">
              <a href="{{url}}" target="_blank" class="hover:text-github-accent">{{name}}</a>
            </h3>
            <span class="badge bg-blue-100 text-blue-800">{{language}}</span>
          </div>
          <p class="text-gray-600 mb-3">{{description}}</p>
          <div class="flex items-center gap-4 text-sm text-gray-500">
            <span>⭐ {{stars}} stars</span>
            {{#if starsThisPeriod}}
              <span class="text-green-600 font-semibold">(+{{starsThisPeriod}} this {{../period}})</span>
            {{/if}}
          </div>
        </div>
        <a href="{{url}}" target="_blank" class="px-4 py-2 bg-github-accent text-white rounded-lg hover:bg-blue-600 transition font-medium">
          View →
        </a>
      </div>
    </div>
    {{/each}}
  </div>
</section>

<!-- Tech News -->
{{#if news}}
<section class="mb-8">
  <h2 class="text-2xl font-bold text-gray-900 mb-4">📰 技术资讯</h2>
  <div class="grid grid-cols-1 gap-4">
    {{#each news}}
    <div class="news-item bg-white rounded-xl shadow-sm p-5 hover:shadow-md transition">
      <div class="flex items-start justify-between">
        <div class="flex-1">
          <h3 class="text-lg font-semibold text-gray-900 mb-1">
            <a href="{{url}}" target="_blank" class="hover:text-github-accent">{{title}}</a>
          </h3>
          <div class="flex items-center gap-4 text-sm text-gray-500">
            <span class="text-orange-600">📰 {{source}}</span>
            {{#if points}}
              <span>⬆️ {{points}} points</span>
            {{/if}}
            {{#if comments}}
              <span>💬 {{comments}} comments</span>
            {{/if}}
          </div>
        </div>
      </div>
    </div>
    {{/each}}
  </div>
</section>
{{/if}}

生成交互式数据可视化仪表板的工作流程。

Description

这个工作流使用 GenerateDashboard.ts 工具从 GitHub 获取 trending 项目,并生成交互式 HTML 仪表板,支持:

  • 项目卡片展示
  • 语言分布饼图
  • Stars 增长柱状图
  • 技术新闻列表
  • 实时筛选、排序、搜索功能

When to Use

当用户请求以下任何内容时使用此工作流:

  • "生成 GitHub trending 仪表板"
  • "创建趋势网页"
  • "生成可视化报告"
  • "export trending dashboard"
  • "生成交互式网页"

Workflow Steps

Step 1: 确定参数

向用户确认或推断以下参数:

  • 时间周期: daily (每日) 或 weekly (每周,默认)
  • 编程语言: 可选(如 TypeScript, Python, Go, Rust等)
  • 项目数量: 默认10个
  • 包含新闻: 是否包含技术新闻
  • 新闻数量: 默认10条
  • 输出路径: 默认 ./github-trends.html

Step 2: 执行工具

运行 GenerateDashboard.ts 工具:

# 基本用法(本周,10个项目)
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts

# 指定语言和新闻
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts \
  --period weekly \
  --language TypeScript \
  --limit 20 \
  --include-news \
  --news-count 15 \
  --output ~/trends.html

# 每日趋势
bun ~/.claude/skills/GitHubTrends/Tools/GenerateDashboard.ts \
  --period daily \
  --output ~/daily-trends.html

Step 3: 显示结果

工具会自动:

  1. 获取 GitHub trending 数据
  2. 获取技术新闻(如果启用)
  3. 分析数据生成统计信息
  4. 渲染 HTML 模板
  5. 保存到指定路径

Step 4: 验证和打开

生成的 HTML 文件包含:

  • ✅ 响应式布局
  • ✅ 项目卡片展示
  • ✅ 语言分布饼图
  • ✅ Stars 增长柱状图
  • ✅ 实时筛选功能
  • ✅ 排序功能
  • ✅ 搜索功能
  • ✅ 技术新闻列表

Example Usage

Example 1: 基本仪表板

User: "生成本周 GitHub trending 仪表板"

Assistant:
运行 GenerateDashboard 工具...
[执行命令,生成 /tmp/github-trends.html]
✅ 仪表板生成成功!已在浏览器中打开。

Example 2: 包含新闻的仪表板

User: "生成 TypeScript 项目的每日趋势,包含新闻"

Assistant:
生成 TypeScript 每日趋势仪表板,包含技术新闻...
[执行命令:--period daily --language TypeScript --include-news]
✅ 仪表板已生成到 ~/Downloads/ts-daily-trends.html

Example 3: 自定义输出

User: "生成一个包含 20 个项目的仪表板,保存到桌面"

Assistant:
生成 20 个项目的趋势仪表板...
[执行命令:--limit 20 --output ~/Desktop/github-trends.html]
✅ 完成!文件已保存到桌面

Tool Options

参数说明默认值可选值
--period时间周期weeklydaily, weekly
--language编程语言筛选全部TypeScript, Python, Go, Rust等
--limit返回项目数量10任意正整数
--include-news包含技术新闻false-
--news-count新闻数量10任意正整数
--theme主题autolight, dark, auto
--output输出文件路径./github-trends.html任意路径

Output Features

数据可视化

  • 语言分布饼图: 展示各编程语言的项目占比
  • Stars 增长柱状图: 展示前 10 名项目的 stars 增长

交互功能

  • 搜索: 按项目名称或描述搜索
  • 筛选: 按编程语言筛选
  • 排序: 按排名、总 stars、周期内增长排序

响应式设计

  • 支持桌面、平板、手机
  • 使用 Tailwind CSS 构建美观界面
  • GitHub 风格配色

Error Handling

如果遇到错误:

  1. 网络错误: 检查网络连接,确保能访问 GitHub
  2. 解析失败: GitHub 页面结构可能变化,工具会显示调试信息
  3. 文件写入失败: 检查输出路径的写权限

Voice Notification

执行此工作流时发送语音通知:

curl -s -X POST http://localhost:8888/notify \
  -H "Content-Type: application/json" \
  -d '{"message": "正在生成 GitHub Trending Dashboard..."}' \
  > /dev/null 2>&1 &

并输出文本通知:

Running the **GenerateDashboard** workflow from the **GitHubTrends** skill...

Integration with Other Skills

  • Browser: 验证生成的 HTML 页面效果
  • System: 保存仪表板快照到 MEMORY/
  • OSINT: 分析技术栈趋势

Notes

  • 数据每小时更新一次(GitHub trending 更新频率)
  • 生成的 HTML 是完全独立的,无需服务器
  • 所有依赖通过 CDN 加载(Tailwind CSS, Chart.js)
  • 支持离线查看(图表已内嵌数据)

Advanced Usage

批量生成

# 生成多个语言的仪表板
for lang in TypeScript Python Go Rust; do
  bun Tools/GenerateDashboard.ts \
    --language $lang \
    --output ~/trends-$lang.html
done

定时任务

# 每小时生成一次快照
# 添加到 crontab:
0 * * * * cd ~/.claude/skills/GitHubTrends && bun Tools/GenerateDashboard.ts --output ~/trends-$(date +%H).html

定制主题

通过修改 Templates/dashboard.hbs 可以自定义:

  • 配色方案
  • 布局结构
  • 添加新的图表类型
  • 添加新的交互功能