Receber por email
← Voltar para o catálogo

daily-brief

Operational knowledge for the daily-brief digest pipeline (this project). RSS/API fetchers, pluggable LLM enrichment (default claude CLI on Max; also anthropic/openai/deepseek/minimax API), trading section, HTML rendering, cross-platform scheduler integration (Windows Task Scheduler / macOS launchd / Linux cron). Load when the user asks about running daily / regenerating sections / debugging a fai

262estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add leiting-eric/DailyBrief

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/daily-brief/svg)](https://www.skillteca.com.br/skills/daily-brief)

Skills relacionadas

Ver todas de Automação →

Alerta por categoria

Receba novas skills de Automação toda segunda

1 email curto, só com as skills novas de Automação. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

daily-brief — Operational Skill

This project generates a single-page HTML daily digest covering tech / finance / politics / market data / community discussion. The pipeline runs locally via the OS scheduler (Windows Task Scheduler / macOS launchd / Linux cron, default 08:00 local time) and emits daily_reports/<YYYY-MM-DD>/<YYYY-MM-DD>.html + sidecar files (each date gets its own subdir). The date label uses the system local timezone by default — set REPORT_TZ (e.g. Asia/Shanghai, UTC) in .env.local to override.

Detailed architecture lives in code; this skill is a cheat sheet for operating and diagnosing, not a re-explanation of the system.

Project root assumption

All paths in this skill are relative to the project root (the directory that contains package.json, lib/, scripts/).

Before any command, ensure the working directory is the project root. Two cases:

  1. Claude Code session opened inside the project — already there, no action needed
  2. Session opened elsewhere — read the config file and cd:

``bash # Cross-platform Node one-liner (prints the project root path): node -e "const fs=require('fs'),os=require('os'),path=require('path');const cfg=path.join(os.homedir(),'.daily-brief-config');if(fs.existsSync(cfg))console.log(fs.readFileSync(cfg,'utf8').trim());else process.exit(1)" ``

Use the printed path: cd "$(...)" on bash / Set-Location (...) in PowerShell.

The config file is written by node scripts/install.mjs --global. If it's missing the user hasn't done a global install — tell them to run it.

Quick command reference

| Need | Command | Cost | |---|---|---| | Full pipeline | npm run daily | ~5-8 min, ~6 Sonnet calls | | Fetch sanity only (no LLM) | npm run dry-run | ~30s | | Re-render existing sidecar | npm run render [date] | <1s | | Re-run trading section | npm run regen-trading [date] | ~2 min, 1 LLM call | | Top-up missing summary | npm run regen-enrich <cat:sub> [date] | ~20-40s, 1 LLM call | | Open today's report in Chrome | npm run open | instant | | Sonnet quota + call history | npm run quota-report | instant |

[date] defaults to today's date in the report timezone (system local, or REPORT_TZ if set). The pipeline and the OS scheduler both run in local time, so the report's date label = the date when the trigger fired in the report timezone. A user with REPORT_TZ=Asia/Shanghai whose machine fires the trigger at 23:00 UTC-8 will get a "next-day Shanghai" file, e.g. daily_reports/2026-05-17/2026-05-17.html.

<cat:sub> accepted by regen-enrich: finance:news, politics:world, tech:ai-news. Single-source X 推文 (tech:x-viral) is enriched as part of daily only — no top-up path.

File map — where to change what

| Task | File | |---|---| | Add / disable / re-categorize a source | sources.config.json (project root — single source of truth; lib/sources/registry.ts is just a loader) | | Rename L1 tab labels | lib/output/render.ts CATEGORY_LABELS | | Reorder / rename L2 subcategories | SUBCATEGORY_ORDER + SUBCATEGORY_LABELS in same file | | Change per-source item cap | SOURCE_DISPLAY_LIMITS | | Change merged-timeline cap | MERGED_SUBGROUP_LIMITS | | Add a Sonnet enrichment prompt | lib/ai/enrich.ts — copy XVIRAL_SYSTEM_PROMPT pattern | | Wire an enrichment into pipeline | scripts/daily.ts — await enrichXxx(articles) in main() | | Add a new fetcher type | New file in lib/sources/ + branch in lib/sources/dispatch.ts | | Adjust HTML styling | inline <style> block in renderHtml() in lib/output/render.ts | | Change scheduler trigger time | node scripts/install.mjs --at HH:MM (re-registers) | | Wrapper script the scheduler invokes | scripts/run-daily.mjs |

How LLM enrichment works (mental model)

  • Each merged L2 subcategory gets a Sonnet pass: GH-trending (per-source), finance:news, politics:world, tech:ai-news, tech:x-viral.
  • Each pass = one batched Sonnet call for all items in that subgroup. Don't iterate per-item.
  • Sources with lang: "zh" in registry skip enrichment (already Chinese).
  • Failures are non-fatal: skipped articles just render without summary.

Diagnostic flow

Order matters — top-to-bottom:

"今天日报没出来" / "Chrome 没弹"

  1. Check scheduled task state — platform-specific:
  2. Windows: Get-ScheduledTaskInfo -TaskName DailyBrief → LastRunTime + LastTaskResult (0=success, 267009=running, else failed)
  3. macOS: launchctl list | grep com.daily-brief (PID column + last exit code)
  4. Linux: cron doesn't track per-job state; look at logs/cron.log
  5. Tail today's log (date = local, not UTC):

``bash node -e "const fs=require('fs'),d=new Date(),pad=n=>String(n).padStart(2,'0');console.log(fs.readFileSync('logs/daily-'+d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate())+'.log','utf8').split('\n').slice(-40).join('\n'))" ``

  1. Check report files exist: ls daily_reports/<date>/ (any platform) or Get-ChildItem daily_reports\<date>\ (Windows)

"某个源数据不对 / 0 条"

  1. Look at fetch lines near top of log — <id> <count> or <id> FAILED — <reason>
  2. If specific source failed: read its fetcher in lib/sources/<source>.ts
  3. If Cloudflare-related: see "LinuxDo lesson" below
  4. Single-source failure must never kill the run (try/catch per source in daily.ts)

"LLM 调用炸 / 中文摘要缺失"

  1. npm run quota-report — per-backend summary; for claude-cli shows 5h window, for API backends shows 24h spending
  2. If quota hot on claude-cli: wait or temporarily switch via .env.local (LLM_BACKEND=openai etc.)
  3. If specific phase missing summaries: npm run regen-enrich <cat:sub>
  4. Each call logged to logs/llm-calls.jsonl (legacy claude-calls.jsonl still read for backwards-compat) — grep "success":false, see errorCategory (quota / timeout / auth / other)
  5. Which backend is active = LLM_BACKEND env in .env.local; not set → claude-cli

"UI 出错 / 某个 tab 显示异常"

  1. npm run render (1 second) — often fixes display-only bugs
  2. If still wrong: read rendered HTML for the affected panel
  3. renderRawCategoryPanel / renderSubContent chain in render.ts is where panel structure lives

Recurring failure patterns (institutional knowledge)

LinuxDo / Cloudflare WAF

  • LinuxDo is behind Cloudflare and frequently flags datacenter-IP exits with "Just a moment..." challenges
  • Do NOT add aggressive retry to its fetcher — burst requests escalate the WAF flag, causing persistent blocks
  • May ship with enabled: false depending on current IP rep
  • Browser works because of cookies + JS challenge; curl can't do either
  • If re-enabling: keep single attempt, accept intermittent failures

Run-daily.mjs wrapper notes

  • Tees npm run daily stdout+stderr to logs/daily-<local-date>.log via stream pipes (real-time, not buffered)
  • Exit code from npm run daily is propagated to the OS scheduler
  • On exit 0: spawns npm run open detached so Chrome opens without blocking
  • Cross-platform: same .mjs file works on Windows / macOS / Linux

"X 推文 出现非英文"

  • API's lang=en param is best-effort; some slip through
  • Fix in lib/sources/attentionvc.ts isEnglish() — checks langsDetected (most reliable) + lang === "zxx" (image/code-only, kept)

"社区讨论 tab 偶发空白"

  • Was a JS scope bug: sub-tab/source-tab handlers used data-cat="tech" selector. Tech main panel AND community panel both had sub-content with data-cat="tech", so clicking AI 媒体 in tech panel deactivated cn-community in community panel
  • Fixed: handlers use btn.closest('.panel') + btn.closest('.sub-content'). If regression, look at inline <script> block at end of renderHtml()

Trading commentary "watchlist empty"

  • Sonnet occasionally returns valid JSON with empty watchlist. 1-shot retry built into lib/ai/trading-commentary.ts with stronger prompt
  • If retry also fails, render falls back to empty trading panel — run isn't abort
Compartilhar X LinkedIn