Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/daily-digest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
# Web content fetching adds ~60-120 s of HTTP requests on incremental runs;
# the first-ever run (fetching 50 articles) may need up to 20 min.
timeout-minutes: 25
timeout-minutes: 30

steps:
- name: Checkout
Expand All @@ -38,14 +38,19 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ANTHROPIC_MODEL: ${{ secrets.ANTHROPIC_MODEL }}
DIGEST_REPO: ${{ github.repository }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: pnpm start

- name: Commit digest files
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add digests/
git add digests/ feed.xml
if git diff --cached --quiet; then
echo "No new digest files to commit"
else
Expand Down
198 changes: 198 additions & 0 deletions config/sources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# agents-radar 追踪来源设定
# 编辑此档即可增减追踪标的,无需修改程式码

# ============================================================
# 报告分组
# ============================================================
groups:
# ── AI CLI 工具(原版 CLI_REPOS)──────────────────────────
- id: ai-cli
name: "AI CLI 工具"
reportFile: "ai-cli.md"
issueLabel: "digest"
issueEmoji: "📊"
promptStyle: "cli"
repos:
- id: claude-code
repo: anthropics/claude-code
name: Claude Code
- id: codex
repo: openai/codex
name: OpenAI Codex
- id: gemini-cli
repo: google-gemini/gemini-cli
name: Gemini CLI
- id: kimi-cli
repo: MoonshotAI/kimi-cli
name: Kimi Code CLI
- id: opencode
repo: anomalyco/opencode
name: OpenCode
- id: qwen-code
repo: QwenLM/qwen-code
name: Qwen Code

# ── OpenClaw 生态(原版 OPENCLAW + PEERS)─────────────────
- id: ai-agents
name: "OpenClaw 生态"
reportFile: "ai-agents.md"
issueLabel: "openclaw"
issueEmoji: "🦞"
promptStyle: "peer"
# 第一个 repo 作为主角(深度报告),其余为 peers
primaryRepo: openclaw
repos:
- id: openclaw
repo: openclaw/openclaw
name: OpenClaw
paginated: true
- id: nanobot
repo: HKUDS/nanobot
name: NanoBot
paginated: true
- id: zeroclaw
repo: zeroclaw-labs/zeroclaw
name: Zeroclaw
- id: picoclaw
repo: sipeed/picoclaw
name: PicoClaw
paginated: true
- id: nanoclaw
repo: qwibitai/nanoclaw
name: NanoClaw
- id: ironclaw
repo: nearai/ironclaw
name: IronClaw
- id: lobsterai
repo: netease-youdao/LobsterAI
name: LobsterAI
- id: tinyclaw
repo: TinyAGI/tinyclaw
name: TinyClaw
- id: copaw
repo: agentscope-ai/CoPaw
name: CoPaw
- id: zeptoclaw
repo: qhkm/zeptoclaw
name: ZeptoClaw
- id: easyclaw
repo: gaoyangz77/easyclaw
name: EasyClaw

# ── MCP 生态系统(新增)────────────────────────────────────
- id: mcp-ecosystem
name: "MCP 生态系统"
reportFile: "ai-mcp.md"
issueLabel: "mcp"
issueEmoji: "🔌"
promptStyle: "cli"
repos:
- id: mcp-spec
repo: modelcontextprotocol/modelcontextprotocol
name: MCP 规范
paginated: true
- id: mcp-ts-sdk
repo: modelcontextprotocol/typescript-sdk
name: MCP TypeScript SDK
- id: mcp-py-sdk
repo: modelcontextprotocol/python-sdk
name: MCP Python SDK
- id: mcp-servers
repo: modelcontextprotocol/servers
name: MCP 官方 Servers
paginated: true
- id: github-mcp
repo: github/github-mcp-server
name: GitHub MCP Server
- id: context7
repo: upstash/context7
name: Context7

# ============================================================
# Claude Code Skills(特殊追踪,无日期过滤)
# ============================================================
skills:
repo: anthropics/skills

# ============================================================
# 网站内容追踪
# ============================================================
websites:
anthropic:
name: "Anthropic (Claude)"
sitemapUrl: "https://www.anthropic.com/sitemap.xml"
prefixes:
- /news/
- /research/
- /engineering/
- /learn/
metadataOnly: false

openai:
name: "OpenAI"
sitemapUrl: "https://openai.com/sitemap.xml"
subSitemapNames:
- research
- publication
- release
- company
- engineering
- milestone
- learn-guides
- safety
- product
subSitemapTemplate: "https://openai.com/sitemap.xml/{name}/"
metadataOnly: true

# ============================================================
# GitHub Trending 搜寻关键字
# ============================================================
trending:
searchQueries:
- query: "topic:llm"
label: llm
- query: "topic:ai-agent"
label: ai-agent
- query: "topic:mcp-server"
label: mcp-server
- query: "topic:rag"
label: rag
- query: "topic:vector-database"
label: vector-db
- query: "topic:large-language-model"
label: llm-model
- query: "topic:machine-learning"
label: ml

# ============================================================
# 通知频道(环境变量启用)
# ============================================================
notifications:
slack:
enabled: false
discord:
enabled: false
telegram:
enabled: false

# ============================================================
# LLM 设定
# ============================================================
llm:
# Kimi Code API(兼容 Anthropic SDK)
defaultBaseUrl: "https://api.kimi.com/coding/"
defaultModel: "kimi-k2-0711-preview"
concurrency: 5
defaultMaxTokens: 4096
trendingMaxTokens: 6144
webMaxTokens: 8192

# ============================================================
# RSS Feed 设定
# ============================================================
rss:
title: "agents-radar AI 生态日报"
description: "每日 AI 编码工具、MCP 生态、开源趋势追踪"
link: "https://howardpen9.github.io/agents-radar/"
language: "zh-CN"
maxItems: 30
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"manifest": "tsx src/generate-manifest.ts"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.36.3"
"@anthropic-ai/sdk": "^0.36.3",
"yaml": "^2.8.2"
},
"devDependencies": {
"@eslint/js": "^9",
Expand Down
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* Config loader — reads config/sources.yaml and provides typed access.
* Env vars override notification settings and LLM endpoint.
*/

import fs from "node:fs";
import path from "node:path";
import { parse as parseYaml } from "yaml";
import type { RepoConfig } from "./github.ts";

// ── Types ────────────────────────────────────────────────

export interface GroupConfig {
id: string;
name: string;
reportFile: string;
issueLabel: string;
issueEmoji: string;
promptStyle: "cli" | "peer";
primaryRepo?: string; // For peer groups: id of the primary project
repos: RepoConfig[];
}

export interface WebsiteConfig {
name: string;
sitemapUrl: string;
prefixes?: string[];
subSitemapNames?: string[];
subSitemapTemplate?: string;
metadataOnly?: boolean;
}

export interface SearchQuery {
query: string;
label: string;
}

export interface LlmConfig {
defaultBaseUrl: string;
defaultModel: string;
concurrency: number;
defaultMaxTokens: number;
trendingMaxTokens: number;
webMaxTokens: number;
}

export interface RssConfig {
title: string;
description: string;
link: string;
language: string;
maxItems: number;
}

export interface RadarConfig {
groups: GroupConfig[];
skills: { repo: string };
websites: Record<string, WebsiteConfig>;
trending: { searchQueries: SearchQuery[] };
notifications: {
slack: { enabled: boolean };
discord: { enabled: boolean };
telegram: { enabled: boolean };
};
llm: LlmConfig;
rss: RssConfig;
}

// ── Loader ───────────────────────────────────────────────

let _config: RadarConfig | null = null;

export function loadConfig(configPath?: string): RadarConfig {
if (_config) return _config;

const file = configPath ?? path.join(process.cwd(), "config", "sources.yaml");
const raw = fs.readFileSync(file, "utf-8");
const parsed = parseYaml(raw) as RadarConfig;

// Validate groups
for (const group of parsed.groups) {
if (!group.id || !group.repos?.length) {
throw new Error(`Invalid group: missing id or repos in "${group.id ?? "unknown"}"`);
}
for (const repo of group.repos) {
if (!repo.repo.includes("/")) {
throw new Error(`Invalid repo format (need owner/repo): ${repo.repo}`);
}
}
}

// Env overrides for notifications
if (process.env["SLACK_WEBHOOK_URL"]) {
parsed.notifications.slack.enabled = true;
}
if (process.env["DISCORD_WEBHOOK_URL"]) {
parsed.notifications.discord.enabled = true;
}
if (process.env["TELEGRAM_BOT_TOKEN"] && process.env["TELEGRAM_CHAT_ID"]) {
parsed.notifications.telegram.enabled = true;
}

_config = parsed;
return parsed;
}

/** Get all repos across all groups as flat list with RepoConfig shape. */
export function getAllRepos(config: RadarConfig): RepoConfig[] {
return config.groups.flatMap((g) => g.repos);
}

/** Get search queries from config (falls back to hardcoded if missing). */
export function getSearchQueries(config: RadarConfig): Array<{ q: string; label: string }> {
return config.trending.searchQueries.map((sq) => ({
q: sq.query,
label: sq.label,
}));
}
Loading