Skill255 estrellas del repoactualizado today
daily-brief
Daily-brief is a local HTML digest generator covering technology, finance, politics, and markets that runs on a schedule via your operating system's native scheduler (Windows Task Scheduler, macOS launchd, or Linux cron). Load this skill when diagnosing pipeline failures, managing LLM backends and API quotas, configuring scheduler integration, regenerating specific report sections, adding or disabling content sources, or troubleshooting why sections display incorrect data.
Instalar en Claude Code
Copiargit clone --depth 1 https://github.com/leiting-eric/DailyBrief /tmp/daily-brief && cp -r /tmp/daily-brief/.claude/skills/daily-brief ~/.claude/skills/daily-briefDespués abre una sesión nueva de Claude Code; el skill carga automáticamente.
Definición
SKILL.md
# 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:
- **Windows**: `Get-ScheduledTaskInfo -TaskName DailyBrief` → `LastRunTime` + `LastTaskResult` (`0`=success, `267009`=running, else failed)
- **macOS**: `launchctl list | grep com.daily-brief` (PID column + last exit code)
- **Linux**: cron doesn't track per-job state; look at `logs/cron.log`
2. 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'))"
```
3. 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`
###