Commit 518b835c authored by 谢宇轩's avatar 谢宇轩

feat: support push

parent 6d415fe0
......@@ -15,6 +15,8 @@ Fetch latest articles from configured news sources, archive them to Obsidian vau
| Preview latest (read-only) | `node scripts/harvest.js <source_id> <count> --preview` |
| Preview with full body | `node scripts/harvest.js <source_id> <count> --preview --full` |
| Finalize Chinese summaries | `node scripts/finalize.js "<dayDir>"` |
| Push a day directory to News Hub | `node scripts/push.js "<dayDir>"` |
| Check push sync status | `node scripts/push.js "<dayDir>" --status` |
| Merge a summary batch | `node scripts/summary-add.js "<dayDir>"` |
| Check summary coverage | `node scripts/summary-add.js "<dayDir>" --status` |
| Add source | `node scripts/source-manage.js add` |
......@@ -93,6 +95,12 @@ Before running a harvest, the agent MUST verify/edit these fields:
|-------|-----------|-------------|
| `vaultPath` | ✅ Yes | Absolute path to the Obsidian vault root. Must exist and be writable. Replace the template placeholder `/path/to/your/obsidian/vault`. |
| `registryWindowDays` | Optional | Dedup sliding window in days (default `7`). |
| `push.enabled` | Optional | Enable pushing finalized archives to the News Hub backend (default `false`). |
| `push.endpoint` | Optional* | News Hub API base URL, e.g. `http://localhost:8080/api/v1`. *Required when `push.enabled` is `true`. |
| `push.appId` / `appKeyId` / `appSecret` | Optional* | News Hub App credentials (3-header auth). *Required when `push.enabled` is `true`. |
| `push.batchSize` | Optional | Articles per push batch (default `10`, API max 10). |
| `push.autoPushAfterFinalize` | Optional | When `true` (default), `finalize.js` auto-chains into `push.js`. Set `false` to push manually only. |
| `push.retry` | Optional | `{ maxAttempts, baseDelayMs }` for exponential backoff on 5xx/network errors (defaults `5` / `1000`). |
| `chromium.cdpPort` | Optional | CDP debug port (default `9222`). Only relevant for `browser` sources. |
| `chromium.headless` | Optional | Launch headless (`true`, default) or with a window (`false`). Set `false` if a site's anti-bot detects headless. |
| `chromium.executablePath` | Optional | Full path to the browser binary. Set only if auto-discovery fails (non-standard install location). `null` = auto-discover. |
......@@ -266,6 +274,20 @@ node scripts/finalize.js "<dayDir>"
```
This writes each `<中文标题>.md`, patches the sentinel links in the 原文.md files, updates `registry.json` + `index.md` with real titles, and removes `.manifest.json` + `.summaries.json`.
> **Auto-push (optional).** If `config.push.enabled` is `true`, finalize automatically chains into `push.js`, which uploads the day directory to the News Hub backend (images to MinIO via `POST /assets`, then articles via `POST /articles`). A push failure **never** aborts finalize — the local archive is already complete; re-push with `node scripts/push.js "<dayDir>"` once the backend is reachable. To push manually instead, set `push.autoPushAfterFinalize: false`.
### Flow C — Push to News Hub (finalize → remote sync)
After a day directory is finalized, push it to the News Hub backend:
```bash
node scripts/push.js "<dayDir>" # push (resumes from failures via .syncstate.json)
node scripts/push.js "<dayDir>" --status # read-only sync status report
node scripts/push.js "<dayDir>" --force # ignore ledger, re-push all articles
```
`push.js` reads `registry.json` for metadata, parses each 原文.md / 摘要.md (markdown + the four summary sections), uploads images to MinIO (SHA-256 deduped), and batch-pushes articles (≤10/batch, idempotent via `Idempotency-Key`). It writes a `.syncstate.json` ledger per day directory so re-running resumes only failed/missing articles. Exit code `2` means partial failure (some articles still in error). See the backend API at `news-hub/docs/API.md`.
### Flow B — Preview (read-only, no archive)
For "返回最新文章数据" / "看看最新文章" requests where the user does **not** ask to save:
......
{
"vaultPath": "/path/to/your/obsidian/vault",
"registryWindowDays": 7,
"push": {
"enabled": false,
"endpoint": "http://localhost:8080/api/v1",
"appId": "",
"appKeyId": "",
"appSecret": "",
"batchSize": 10,
"autoPushAfterFinalize": true,
"retry": { "maxAttempts": 5, "baseDelayMs": 1000 }
},
"chromium": {
"cdpPort": 9222,
"headless": true,
......
......@@ -202,6 +202,37 @@ function main() {
console.error(`\n✅ Done: ${patched} finalized, ${skipped} skipped`);
console.error(` Registry + index updated, temp files removed`);
// 6. Auto-push to News Hub if enabled and configured. Push failures do NOT
// abort finalize (the archive is already complete and re-pushable), so
// a backend hiccup never leaves the local archive in a bad state.
maybeAutoPush(dayDir);
}
// Chain into push.js when config.push.enabled && autoPushAfterFinalize.
// Runs push.js as a child process so a push crash can't take down finalize.
function maybeAutoPush(dayDir) {
const cfgPath = path.join(__dirname, '..', 'config.json');
let cfg;
try { cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8')); }
catch (e) { return; } // no config → skip silently
const p = cfg.push;
if (!p || !p.enabled || !p.autoPushAfterFinalize) return;
if (!p.endpoint || !p.appId || !p.appKeyId || !p.appSecret) {
console.error(`\n⚠️ Push enabled but config incomplete (endpoint/appId/appKeyId/appSecret) — skipping.`);
console.error(` Run manually once configured: node scripts/push.js "${dayDir}"`);
return;
}
console.error(`\n📤 Auto-pushing to News Hub (config.push.autoPushAfterFinalize = true)`);
const { spawnSync } = require('child_process');
const r = spawnSync(process.execPath, [path.join(__dirname, 'push.js'), dayDir], {
stdio: ['ignore', 'inherit', 'inherit'], // stdout/stderr → this process
});
if (r.status !== 0) {
console.error(`\n⚠️ Push exited with code ${r.status} — local archive is unaffected.`);
console.error(` Fix the issue and re-run: node scripts/push.js "${dayDir}"`);
}
}
if (require.main === module) {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment