GitHubTrends
--- name: GitHubTrends description: 显示GitHub热门项目趋势,生成可视化仪表板。USE WHEN github trends, trending projects, hot repositories, popular github projects, generate dashboard
Description
name: GitHubTrends description: 显示GitHub热门项目趋势,生成可视化仪表板。USE WHEN github trends, trending projects, hot repositories, popular github projects, generate dashboard, create webpage. version: 2.0.0
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:
-
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 & -
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 |
时间周期 | weekly |
daily, 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 # 工作流文档
注意事项
- 网络要求: 需要能访问GitHub官网
- 更新频率: 数据每小时更新,不是实时
- 解析准确性: GitHub页面结构变化可能影响解析,如遇问题请检查
/tmp/github-trending-debug-*.html - 语言参数: 不区分大小写,
--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(/&/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";
// 提取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; }
/**
- 获取技术新闻 */ async function getTechNews(count: number): Promise<TechNewsItem[]> { const HN_API = 'https://hn.algolia.com/api/v1/search_by_date';
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
🚀 GitHub Trending Dashboard
周期: {{period}} | 生成时间: {{generatedAt}}
<!-- 统计概览 -->
<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: 显示结果
工具会自动:
- 获取 GitHub trending 数据
- 获取技术新闻(如果启用)
- 分析数据生成统计信息
- 渲染 HTML 模板
- 保存到指定路径
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 |
时间周期 | weekly |
daily, weekly |
--language |
编程语言筛选 | 全部 | TypeScript, Python, Go, Rust等 |
--limit |
返回项目数量 | 10 | 任意正整数 |
--include-news |
包含技术新闻 | false | - |
--news-count |
新闻数量 | 10 | 任意正整数 |
--theme |
主题 | auto |
light, dark, auto |
--output |
输出文件路径 | ./github-trends.html |
任意路径 |
Output Features
数据可视化
- 语言分布饼图: 展示各编程语言的项目占比
- Stars 增长柱状图: 展示前 10 名项目的 stars 增长
交互功能
- 搜索: 按项目名称或描述搜索
- 筛选: 按编程语言筛选
- 排序: 按排名、总 stars、周期内增长排序
响应式设计
- 支持桌面、平板、手机
- 使用 Tailwind CSS 构建美观界面
- GitHub 风格配色
Error Handling
如果遇到错误:
- 网络错误: 检查网络连接,确保能访问 GitHub
- 解析失败: GitHub 页面结构可能变化,工具会显示调试信息
- 文件写入失败: 检查输出路径的写权限
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 可以自定义:
- 配色方案
- 布局结构
- 添加新的图表类型
- 添加新的交互功能
Reviews (0)
No reviews yet. Be the first to review!
Comments (0)
No comments yet. Be the first to share your thoughts!