feat: 早报系统重构与功能增强

- 新增常驻调度器 daily/scheduler.py + run-scheduler.ps1(定时生成/推送)
- 新增 daily/bridge_manager.py:Windows 兼容的 Cursor SDK 桥接
- 新增 skills/daily-featured-pick 首推 Skill 与叙事轴/去重逻辑
- 新闻抓取窗口、GitHub 搜索、企微 delta 模式等多项改进
- 补充设计文档与 superpowers 计划/规范
- 新增对应测试(scheduler、featured_pick、github_search、news_fetch_window 等)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 18:12:00 +08:00
parent 6192dd4e2a
commit 6ea2a4e4c6
35 changed files with 4389 additions and 359 deletions

View File

@@ -510,23 +510,26 @@ def _format_skill_section(items: list[dict[str, Any]], *, hot: bool = False) ->
def generate_report() -> tuple[str, str, Path, Path]:
trending_n = env_int("DAILY_TRENDING_LIMIT", 150)
hot_n = max(env_int("DAILY_HOT_LIMIT", 150), compare_depth())
# Hot/Trending 前排同 source 极密,需更深抓取才能凑够展示用的唯一 source
trending_n = env_int("DAILY_TRENDING_LIMIT", 400)
hot_n = max(env_int("DAILY_HOT_LIMIT", 400), compare_depth())
compare_n = compare_depth()
skill_pool = max(10, env_int("DAILY_WECOM_SKILL_POOL", 200))
wecom_trending = env_int("DAILY_WECOM_TRENDING", 10)
wecom_hot = env_int("DAILY_WECOM_HOT", 10)
pad_pool = wecom_pad_pool_size(max(wecom_trending, wecom_hot, 10))
skill_pool = max(10, env_int("DAILY_WECOM_SKILL_POOL", 400))
wecom_trending = env_int("DAILY_WECOM_TRENDING", 5)
wecom_hot = env_int("DAILY_WECOM_HOT", 5)
pad_pool = wecom_pad_pool_size(max(wecom_trending, wecom_hot, 5))
skill_pool = max(skill_pool, pad_pool)
github_limit = env_int("DAILY_GITHUB_TRENDING_LIMIT", 10)
wecom_github = env_int("DAILY_WECOM_GITHUB_TRENDING", env_int("DAILY_WECOM_REPOS", 10))
github_fetch_n = max(github_limit, compare_n, wecom_github, pad_pool)
wecom_github = env_int("DAILY_WECOM_GITHUB_TRENDING", env_int("DAILY_WECOM_REPOS", 5))
# 周去重后顶刊 stickyHTML/~30 条不够补满;深池默认 100Search 已分页)
github_pool = max(pad_pool, env_int("DAILY_GITHUB_POOL", 100))
github_fetch_n = max(github_limit, compare_n, wecom_github, github_pool)
emerging_limit = env_int("DAILY_GITHUB_EMERGING_LIMIT", 10)
wecom_emerging = env_int("DAILY_WECOM_GITHUB_EMERGING", 10)
emerging_fetch_n = max(emerging_limit, compare_n, wecom_emerging, pad_pool)
wecom_emerging = env_int("DAILY_WECOM_GITHUB_EMERGING", 5)
emerging_fetch_n = max(emerging_limit, compare_n, wecom_emerging, github_pool)
topic_limit = env_int("DAILY_GITHUB_TOPIC_LIMIT", 10)
wecom_topic = env_int("DAILY_WECOM_GITHUB_TOPIC", 10)
topic_fetch_n = max(topic_limit, compare_n, wecom_topic, pad_pool)
wecom_topic = env_int("DAILY_WECOM_GITHUB_TOPIC", 5)
topic_fetch_n = max(topic_limit, compare_n, wecom_topic, github_pool)
feed = load_feed(force=True)
prev_ids = _load_snapshot()
@@ -576,10 +579,21 @@ def generate_report() -> tuple[str, str, Path, Path]:
}
pool = max(board_pool_size(), skill_pool, pad_pool)
recent_shown = load_recent_shown_keys(date_str)
from daily.skills_group import expand_skill_recent_keys
skill_recent = expand_skill_recent_keys(
recent_shown["skills_trending"] | recent_shown["skills_hot"]
)
# GitHub 三榜共用周去重:任一类出现过的 repo 各榜都不再展示
github_recent = (
recent_shown["github_trending"]
| recent_shown["github_emerging"]
| recent_shown["github_topic"]
)
selected_trending = board_select(
board="skills_trending",
items=trending,
recent_keys=recent_shown["skills_trending"],
recent_keys=skill_recent,
limit=wecom_trending,
pool_size=pool,
kind="skill",
@@ -587,7 +601,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
selected_hot = board_select(
board="skills_hot",
items=hot,
recent_keys=recent_shown["skills_hot"],
recent_keys=skill_recent,
limit=wecom_hot,
pool_size=pool,
kind="skill",
@@ -595,23 +609,25 @@ def generate_report() -> tuple[str, str, Path, Path]:
selected_github = board_select(
board="github_trending",
items=github_trending,
recent_keys=recent_shown["github_trending"],
recent_keys=github_recent,
limit=wecom_github,
pool_size=pool,
kind="github",
)
github_recent |= {str(r.get("repo") or "") for r in selected_github if r.get("repo")}
selected_emerging = board_select(
board="github_emerging",
items=github_emerging,
recent_keys=recent_shown["github_emerging"],
recent_keys=github_recent,
limit=wecom_emerging,
pool_size=pool,
kind="github",
)
github_recent |= {str(r.get("repo") or "") for r in selected_emerging if r.get("repo")}
selected_topic = board_select(
board="github_topic",
items=github_topic,
recent_keys=recent_shown["github_topic"],
recent_keys=github_recent,
limit=wecom_topic,
pool_size=pool,
kind="github",
@@ -842,7 +858,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
gt_pad = board_select(
board="skills_trending",
items=trending,
recent_keys=recent_shown["skills_trending"],
recent_keys=skill_recent,
limit=pad_pool,
pool_size=pool,
kind="skill",
@@ -850,7 +866,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
gh_pad = board_select(
board="skills_hot",
items=hot,
recent_keys=recent_shown["skills_hot"],
recent_keys=skill_recent,
limit=pad_pool,
pool_size=pool,
kind="skill",
@@ -858,12 +874,17 @@ def generate_report() -> tuple[str, str, Path, Path]:
wecom_github_items = [_prepare_github_item(item) for item in selected_github]
wecom_emerging_items = [_prepare_github_item(item) for item in selected_emerging]
wecom_topic_items = [_prepare_github_item(item) for item in selected_topic]
github_pad_recent = (
recent_shown["github_trending"]
| recent_shown["github_emerging"]
| recent_shown["github_topic"]
)
wecom_github_pad = [
_prepare_github_item(item)
for item in board_select(
board="github_trending",
items=github_trending,
recent_keys=recent_shown["github_trending"],
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
@@ -874,7 +895,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
for item in board_select(
board="github_emerging",
items=github_emerging,
recent_keys=recent_shown["github_emerging"],
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",
@@ -885,7 +906,7 @@ def generate_report() -> tuple[str, str, Path, Path]:
for item in board_select(
board="github_topic",
items=github_topic,
recent_keys=recent_shown["github_topic"],
recent_keys=github_pad_recent,
limit=pad_pool,
pool_size=pool,
kind="github",