← back to Allnewsdaily
Add prod static-wire mode: WIRE_STATIC=1 serves pre-built data/wire.json (no Ollama on prod); scripts/build-wire.js + scripts/push-wire.sh keep it fresh from this Mac's Ollama
98297054f98b43e080b5b28dd36fac247c09d656 · 2026-09-09 11:28:58 -0700 · Steve Abrams
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177CKXFpA1rVH3Sk24fgRZ9
Files touched
M .gitignoreM lib/aggregate.jsA scripts/build-wire.jsA scripts/push-wire.shM server.js
Diff
commit 98297054f98b43e080b5b28dd36fac247c09d656
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 9 11:28:58 2026 -0700
Add prod static-wire mode: WIRE_STATIC=1 serves pre-built data/wire.json (no Ollama on prod); scripts/build-wire.js + scripts/push-wire.sh keep it fresh from this Mac's Ollama
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177CKXFpA1rVH3Sk24fgRZ9
---
.gitignore | 1 +
lib/aggregate.js | 24 +++++++++++++++++++++++-
scripts/build-wire.js | 18 ++++++++++++++++++
scripts/push-wire.sh | 15 +++++++++++++++
server.js | 20 +++++++++++++++-----
5 files changed, 72 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index 78cd896..4f9b69c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ build/
data/live-status.json
data/paraphrase-cache.json
+data/wire.json
diff --git a/lib/aggregate.js b/lib/aggregate.js
index 6fcf3b9..c37afcb 100644
--- a/lib/aggregate.js
+++ b/lib/aggregate.js
@@ -89,4 +89,26 @@ async function rebuild() {
function getWire() { return WIRE; }
function meta() { return loadFeeds(); }
-module.exports = { rebuild, getWire, meta };
+const WIRE_JSON = path.join(__dirname, '..', 'data', 'wire.json');
+
+// Persist the current wire to data/wire.json (used by scripts/build-wire.js).
+function writeWireFile() {
+ const w = getWire();
+ const out = { columns: w.columns, splash: w.splash, updatedAt: w.updatedAt, sources: w.sources, sourcesOk: w.sourcesOk };
+ fs.writeFileSync(WIRE_JSON, JSON.stringify(out));
+ return out;
+}
+
+// Load a pre-built wire snapshot into memory (prod static mode — no Ollama needed).
+function loadStaticWire() {
+ try {
+ const w = JSON.parse(fs.readFileSync(WIRE_JSON, 'utf8'));
+ if (w && Array.isArray(w.columns)) {
+ WIRE = { ...w, building: false };
+ return true;
+ }
+ } catch (e) { /* file missing/invalid — leave WIRE as-is */ }
+ return false;
+}
+
+module.exports = { rebuild, getWire, meta, writeWireFile, loadStaticWire, WIRE_JSON };
diff --git a/scripts/build-wire.js b/scripts/build-wire.js
new file mode 100755
index 0000000..67f57a4
--- /dev/null
+++ b/scripts/build-wire.js
@@ -0,0 +1,18 @@
+#!/usr/bin/env node
+'use strict';
+// Build the wire (fetch free feeds + rewrite headlines via local Ollama) and write data/wire.json.
+// Runs on a machine that HAS Ollama (this Mac). The prod server (WIRE_STATIC=1) just serves the file.
+const { rebuild, writeWireFile, WIRE_JSON } = require('../lib/aggregate');
+
+(async () => {
+ const t0 = Date.now();
+ const w = await rebuild();
+ const stories = (w.columns || []).reduce((n, c) => n + c.items.length, 0);
+ if (stories === 0) {
+ console.error(`[build-wire] refusing to write empty wire (sources ${w.sourcesOk}/${w.sources}) — keeping previous snapshot`);
+ process.exit(1);
+ }
+ const out = writeWireFile();
+ console.log(`[build-wire] wrote ${WIRE_JSON} — ${stories} stories, ${w.sourcesOk}/${w.sources} sources, ${Date.now() - t0}ms`);
+ process.exit(0);
+})().catch((e) => { console.error('[build-wire] failed', e.message); process.exit(1); });
diff --git a/scripts/push-wire.sh b/scripts/push-wire.sh
new file mode 100755
index 0000000..1fa20ed
--- /dev/null
+++ b/scripts/push-wire.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+# Rebuild the wire locally (needs Ollama) then rsync ONLY data/wire.json to prod.
+# Runs from a launchd job on this Mac every ~10 min. Reversible: unload the job to stop.
+set -euo pipefail
+cd "$(dirname "$0")/.."
+PROD="${PROD_HOST:-root@45.61.58.125}"
+REMOTE="/root/Projects/allnewsdaily/data/wire.json"
+
+node scripts/build-wire.js || { echo "[push-wire] build failed, not pushing"; exit 1; }
+
+# only push a non-empty, valid file
+node -e "const w=require('./data/wire.json'); if(!w.columns||!w.columns.length){process.exit(2)}" || { echo "[push-wire] wire.json invalid, not pushing"; exit 2; }
+
+rsync -az -e "ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new" data/wire.json "$PROD:$REMOTE"
+echo "[push-wire] pushed $(date -u +%FT%TZ) → $PROD:$REMOTE"
diff --git a/server.js b/server.js
index f988975..b3efbb7 100644
--- a/server.js
+++ b/server.js
@@ -3,7 +3,10 @@ const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const { GUIDES } = require('./content/guides');
-const { rebuild, getWire, meta } = require('./lib/aggregate');
+const { rebuild, getWire, meta, loadStaticWire } = require('./lib/aggregate');
+// On prod (no Ollama) set WIRE_STATIC=1: serve the pre-built data/wire.json, refreshed by an
+// external pusher (scripts/build-wire.js on a machine that HAS Ollama). Never fetches/rewrites here.
+const WIRE_STATIC = process.env.WIRE_STATIC === '1';
const app = express();
const PORT = process.env.PORT || 9788;
@@ -320,8 +323,15 @@ app.listen(PORT, () => {
console.log(`outlets loaded: ${loadOutlets().length}`);
runChecker();
setInterval(runChecker, POLL_INTERVAL_MS);
- // Build the wire (fetch feeds + rewrite headlines) now, then refresh on an interval.
- rebuild().then((w) => console.log(`[wire] first build: ${w.sourcesOk}/${w.sources} sources, ${(w.columns || []).reduce((n, c) => n + c.items.length, 0)} stories`))
- .catch((e) => console.error('[wire] first build error', e.message));
- setInterval(() => { rebuild().catch(() => {}); }, WIRE_REFRESH_MS);
+ if (WIRE_STATIC) {
+ // Prod: serve the pre-built snapshot; re-read the file as the pusher refreshes it.
+ const ok = loadStaticWire();
+ console.log(`[wire] static mode — loaded ${ok ? (getWire().columns || []).reduce((n, c) => n + c.items.length, 0) + ' stories' : 'NO snapshot yet'}`);
+ setInterval(() => { loadStaticWire(); }, 60000);
+ } else {
+ // Dev / builder host (has Ollama): fetch feeds + rewrite headlines, refresh on interval.
+ rebuild().then((w) => console.log(`[wire] first build: ${w.sourcesOk}/${w.sources} sources, ${(w.columns || []).reduce((n, c) => n + c.items.length, 0)} stories`))
+ .catch((e) => console.error('[wire] first build error', e.message));
+ setInterval(() => { rebuild().catch(() => {}); }, WIRE_REFRESH_MS);
+ }
});
← 4563468 Drudge-style front page: live free-RSS wire rewritten into o
·
back to Allnewsdaily
·
wire-push: robust node resolution for launchd; add wire-push f1da61c →