feat: add election calendar with CII scoring integration#221
Open
Jacob-Strokus wants to merge 1257 commits intokoala73:mainfrom
Open
feat: add election calendar with CII scoring integration#221Jacob-Strokus wants to merge 1257 commits intokoala73:mainfrom
Jacob-Strokus wants to merge 1257 commits intokoala73:mainfrom
Conversation
Add Turkish (tr) as the 14th supported language with full translation of all 1,134 locale keys, locale loader, tr-TR formatting, and flag mapping. Update documentation to reflect 14 languages.
Move pattern from beforeSend extension-only check to ignoreErrors array. All 16 events were iOS Safari with no stack trace — stale cached assets after deploys, not actionable bugs.
…ions - Add i18n keys for all 9 strategic posture theater names (Iran Theater, Baltic Theater, Taiwan Strait, etc.) across all 14 languages - Wire StrategicPosturePanel to use t() for theater display names with fallback to English if key is missing - Include webcam region button translations (ALL, MIDEAST, EUROPE, etc.) that were missing from deployed locale files Fixes koala73#121
- CIIPanel: use existing t('components.cii.noSignals') for empty state
- CountryBriefPage: localize level badge and trend indicator labels
- ETFFlowsPanel: localize summary labels, table headers, net direction
- LiveWebcamsPanel: localize region filter tab labels
- MacroSignalsPanel: localize verdict, signal names, and bullish count
- StrategicRiskPanel: localize score levels, trend label, and trend values
Add Ollama as the primary summarization provider for desktop builds, sitting before Groq/OpenRouter in the fallback chain. This enables fully local, unlimited LLM inference via Ollama's OpenAI-compatible endpoint (/v1/chat/completions). Changes across six layers: - runtime-config: OLLAMA_API_URL + OLLAMA_MODEL secret keys, aiOllama feature toggle (default on), URL validation - sidecar: allowlist + endpoint probe validation (tries /v1/models then /api/tags) - api/ollama-summarize.js: new handler mirroring Groq/OpenRouter with shared Redis cache keys - summarization.ts: tryOllama() + updated chain order in normal, beta, and translation paths (Ollama → Groq → OpenRouter → Browser T5) - RuntimeConfigPanel: signup URLs + i18n help text for new keys - desktop-readiness: aiOllama in key-backed features + readiness check https://claude.ai/code/session_01AGg9fG6LZ8Y6XhvLszdfeY
…ayers Three test files covering Ollama integration: api/ollama-summarize.test.mjs (9 tests): - Fallback signal when unconfigured, on API error, on empty response - Success path with correct provider label and response shape - Model selection via OLLAMA_MODEL env / default fallback - Network error handling (ECONNREFUSED) - Translate mode prompt verification tests/summarization-chain.test.mjs (7 tests): - Ollama success short-circuits chain (Groq never called) - Ollama fail → Groq success fallback - Full fallback when both unconfigured - Provider label correctness for Ollama and Groq - Uniform response shape across providers - Identical fallback signal shapes src-tauri/sidecar/local-api-server.test.mjs (8 new tests): - OLLAMA_API_URL and OLLAMA_MODEL accepted via env-update allowlist - Unknown keys rejected (403) - Validation via /v1/models probe (reachable mock) - Validation via /api/tags native fallback - OLLAMA_MODEL pass-through validation - Non-http protocol rejection (422) - Auth-required behavior preserved with token https://claude.ai/code/session_01AGg9fG6LZ8Y6XhvLszdfeY
Server-side: extract shared CORS, validation, caching, prompt building, and response shaping into api/_summarize-handler.js factory. Each endpoint (Groq, OpenRouter, Ollama) becomes a thin wrapper calling createSummarizeHandler() with a provider config: credentials, API URL, model, headers, and provider label. Client-side: replace three near-identical tryOllama/tryGroq/tryOpenRouter functions with a single tryApiProvider() driven by an API_PROVIDERS config array. Add runApiChain() helper that loops the chain with progress callbacks. Simplify translateText() from three copy-pasted blocks to a single loop over the same provider array. - groq-summarize.js: 297 → 30 lines - openrouter-summarize.js: 295 → 33 lines - ollama-summarize.js: 289 → 34 lines - summarization.ts: 336 → 239 lines - New _summarize-handler.js: 315 lines (shared) - Net: -566 lines of duplication removed Adding a new LLM provider now requires only a provider config object in the endpoint file + one entry in the API_PROVIDERS array. Tests: 13 new tests for the shared factory (cache key, dedup, handler creation, fallback, error casing, HTTP methods). All 42 existing tests pass unchanged. https://claude.ai/code/session_01AGg9fG6LZ8Y6XhvLszdfeY
- Use for...of entries() instead of index-based loops in summarization.ts to satisfy strict noUncheckedIndexedAccess (7 TS18048/TS2345 errors) - Replace fragile API_PROVIDERS[1] with .find(p => p.name === groq) - Add OLLAMA_API_URL and OLLAMA_MODEL to SUPPORTED_SECRET_KEYS in main.rs so keychain secrets are injected into sidecar on desktop startup
…and Ollama UX - Split settings window into 3 tabs: LLMs (Ollama/Groq/OpenRouter), API Keys (data feeds), and Debug & Logs - Add featureFilter option to RuntimeConfigPanel for rendering subsets - Consolidate keychain to single JSON vault entry (1 macOS prompt vs 20) - Add Ollama model discovery with /api/tags + /v1/models fallback - Strip <think> reasoning tokens from Ollama responses - Suppress thinking with think:false in Ollama request body - Parallel secret verification with 15s global timeout - Fix manual model input overlapping dropdown (CSS grid-area + hidden-input class) - Add loading spinners to settings tab panels - Suppress notification popups when settings window is open - Filter embed models from Ollama dropdown - Fix settings window black screen flash with inline dark background
Add local LLM support mentions across feature descriptions, talking points, screenshot suggestions, and changelog. New dedicated section for Ollama/LM Studio as feature koala73#11.
DeckGLMap: guard updateLayers/debounce/raf against null maplibreMap, null out references in destroy() to prevent post-destroy setProps crash. main.ts: filter contentWindow.postMessage (Facebook WebView), vertex shader compile (GPU driver), objectStoreNames (iOS background), Unexpected identifier https (Safari 16), _0x obfuscated vars (extensions), WKWebView deallocated (Tauri lifecycle).
…koala73#124) ## Summary Extracts shared summarization logic (CORS, validation, caching, prompt building) into a reusable `_summarize-handler.js` factory, then uses it to add Ollama as the first provider in the fallback chain. This reduces code duplication across Groq, OpenRouter, and the new Ollama endpoint while maintaining identical behavior. **Fallback chain is now:** Ollama → Groq → OpenRouter → Browser T5 ## Type of change - [x] New feature - [x] Refactor / code cleanup - [x] API endpoints (`/api/*`) ## Affected areas - [x] AI Insights / World Brief - [x] Desktop app (Tauri) - [x] API endpoints (`/api/*`) - [x] Config / Settings ## Changes ### New Files - **`api/_summarize-handler.js`** – Shared handler factory with: - `createSummarizeHandler(providerConfig)` – Creates edge handlers for any LLM provider - `getCacheKey()` – Stable cache key generation (extracted from per-provider code) - `deduplicateHeadlines()` – Headline deduplication logic (extracted from per-provider code) - Unified prompt building for brief/analysis/translate modes with tech/full variants - CORS, validation, caching, and error handling pipeline - **`api/ollama-summarize.js`** – New Ollama endpoint (34 lines): - Calls local/remote Ollama instance via OpenAI-compatible `/v1/chat/completions` - Reads `OLLAMA_API_URL` and `OLLAMA_MODEL` from environment - Shares Redis cache with Groq/OpenRouter (same cache key strategy) - Returns fallback signal when unconfigured or API fails - **`api/ollama-summarize.test.mjs`** – Unit tests for Ollama endpoint: - Fallback signal when `OLLAMA_API_URL` not configured - Success response with provider="ollama" - Error handling (API errors, empty responses) - Model selection via `OLLAMA_MODEL` env - **`api/_summarize-handler.test.mjs`** – Unit tests for shared factory: - Cache key stability and variation by mode/variant/lang/geoContext - Headline deduplication logic - Handler creation with missing credentials - API provider calls and response shaping - **`tests/summarization-chain.test.mjs`** – Integration tests for fallback chain: - Ollama success short-circuits (no downstream calls) - Ollama failure → Groq success - Both fail → fallback signals propagate ### Modified Files **`api/groq-summarize.js`** & **`api/openrouter-summarize.js`** - Replaced ~290 lines of duplicated logic with single call to `createSummarizeHandler()` - Now thin wrappers: 26 lines (Groq) and 28 lines (OpenRouter) - Identical behavior, zero functional changes **`src/services/summarization.ts`** - Updated fallback chain: `Ollama → Groq → OpenRouter → Browser T5` - Refactored `tryGroq()` and `tryOpenRouter()` into unified `tryApiProvider()` function - Added `API_PROVIDERS` config array for provider ordering - Updated `SummarizationProvider` type to include `'ollama'` **`src-tauri/sidecar/local-api-server.mjs`** - Added `OLLAMA_API_URL` and `OLLAMA_MODEL` to `ALLOWED_ENV_KEYS` - Added validation for `OLLAMA_API_URL` in `validateSecretAgainstProvider()`: - Probes `/v1/models` (OpenAI-compatible endpoint) - Falls back to `/api/tags` (native Ollama endpoint) - Returns "Ollama endpoint verified" or "Ollama endpoint verified (native API
…buffers Toggling cables/pipelines off then on caused deck.gl assertion failure because the cached PathLayer had its WebGL resources destroyed on removal.
…USNI News, Oryx OSINT, UK MOD)
…keychain vault - Ollama/LM Studio integration with auto model discovery and 4-tier fallback chain - Settings window split into LLMs, API Keys, and Debug tabs - Consolidated keychain vault (1 OS prompt instead of 20+) - README expanded with privacy architecture, summarization chain docs - CHANGELOG updated with full v2.5.0 release notes - 5 new defense/intel RSS feeds, Koeberg nuclear plant added
Removes circular dev→prod dependency. The new polymarketPlugin() mirrors the edge function logic locally: validates params, fetches from gamma-api.polymarket.com, and gracefully returns [] when Cloudflare JA3 blocks server-side TLS (expected behavior).
The Vite dev plugin was hardcoding `{ videoId: null }` with a TODO,
causing LiveNewsPanel to never resolve actual live streams during local
development. Replace the stub with the same fetch-and-scrape approach
used by the production edge function (api/youtube/live.js): fetch the
channel's /live page and extract videoId + isLive from the HTML.
https://claude.ai/code/session_01684qa7XvS7sf9CShqU8zNg
Store the interval ID returned by setInterval in a new clockIntervalId field and clear it in App.destroy(). Previously, the interval was never stored or cleared, causing DOM writes to double on each Vite HMR reload. https://claude.ai/code/session_0111CXxXM5qKR83UAdUTQDyL
npm install regenerated the lockfile to reflect the current version (2.5.0) and license field from package.json. https://claude.ai/code/session_01684qa7XvS7sf9CShqU8zNg
…eived load Inline a minimal HTML skeleton (header bar, map placeholder, panels grid) with critical CSS directly in index.html so the page shows a structured layout immediately instead of a blank screen while JavaScript boots. - Dark theme skeleton with hardcoded colors matching CSS variables - Light theme support via [data-theme="light"] selectors - Shimmer animation on placeholder lines for visual feedback - 6 skeleton panels in a responsive grid matching the real layout - Map section with radial gradient matching the map background - Skeleton is automatically replaced when App.renderLayout() sets innerHTML - Marked aria-hidden="true" for screen reader accessibility Expected gain: perceived load time drops to <0.5s. https://claude.ai/code/session_01Fxk8GMRn2cEUq3ThC2a8e5
Replace the static LOCALE_LOADERS map (14 explicit dynamic imports) with import.meta.glob for lazy loading. English is now statically imported as the always-needed fallback; all other 13 locales are loaded on demand. - Statically import en.json so it's bundled eagerly (no extra fetch) - Use import.meta.glob with negative pattern to lazy-load non-English locales only when the user actually switches language - Add manualChunks rule to prefix lazy locale chunks with `locale-` - Exclude locale-*.js from service worker precache via globIgnores - Add CacheFirst runtime caching for locale files when loaded on demand SW precache reduced from 43 entries (5587 KiB) to 29 entries (4840 KiB), saving ~747 KiB from the initial download. https://claude.ai/code/session_01TfRgC5GWsv51swxRSGxxeJ
… filters (koala73#393) PR koala73#382 accidentally removed the maplibregl.FilterSpecification type cast, causing tsc to infer (string | string[])[] which doesn't satisfy setFilter's parameter type. This broke the Vercel build.
…#392) - Add to tech variant security feed group - Add to main variant global feeds as type: 'cyber' - Add www.ransomware.live to RSS proxy allowlist - Set source tier to 3 (specialty)
Runs npm run typecheck (tsc --noEmit) on every PR to catch type errors before merge. Would have prevented the koala73#382 regression.
…73#395) Linux AppImage (koala73#370, koala73#257): - Upgrade CI from Ubuntu 22.04 to 24.04 (GLib 2.80 fixes g_task_set_static_name symbol mismatch) - Set GDK_BACKEND=wayland,x11 when WAYLAND_DISPLAY detected (fixes GTK init on niri/river) - Disable WebKit bubblewrap sandbox in AppImage context (FUSE mount breaks it → blank screen) - Set GTK_IM_MODULE to built-in simple context in AppImage (prevents host module conflicts) RSS proxy: - Add 32 missing domains to allowlist (EuroNews lang variants, international news feeds) - Normalize www prefix in domain validation (prevents entire class of www/non-www mismatch 403s) Console cleanup: - TrendingKeywords: console.log → console.debug for suppressed terms (30+ noisy log lines) - PostHog: add ui_host for reverse proxy setup (fixes /ingest/ 404s)
…73#396) Add a "Streaming" section to the GENERAL settings tab with a quality dropdown (Auto / Low 360p / Medium 480p / High / HD 720p). The setting persists to localStorage and applies to all live streams: - LiveWebcamsPanel: appends vq= to direct embeds, passes through proxy - LiveNewsPanel: sets quality via YT.Player API onReady + desktop proxy - YouTube embed proxy: accepts vq param, calls setPlaybackQuality() Closes koala73#365
…koala73#400) * fix: sort tariff datapoints newest-first in trade policy panel * fix: update tests broken by cachedFetchJson migration - Restore "Strip unterminated" comment in summarize-article.ts that tests use to locate the unterminated tag stripping section - Update ACLED tests to check for cachedFetchJson instead of removed getCachedJson/setCachedJson patterns
…ala73#399) * fix: sort tariff datapoints newest-first in trade policy panel * fix: update tests broken by cachedFetchJson migration - Restore "Strip unterminated" comment in summarize-article.ts that tests use to locate the unterminated tag stripping section - Update ACLED tests to check for cachedFetchJson instead of removed getCachedJson/setCachedJson patterns * fix: sort supply chain chokepoints by disruption score descending
* fix: sort tariff datapoints newest-first in trade policy panel * fix: update tests broken by cachedFetchJson migration - Restore "Strip unterminated" comment in summarize-article.ts that tests use to locate the unterminated tag stripping section - Update ACLED tests to check for cachedFetchJson instead of removed getCachedJson/setCachedJson patterns * chore: bump version to 2.5.9 and make pre-push hook executable * docs: update README with supply chain intel, universal CII, Happy Monitor, security hardening, and recent features
…oise filters (koala73#402) - CSS.escape() on data-news-id querySelector to prevent SyntaxError when news item IDs contain special characters (WORLDMONITOR-5J) - typeof guard on this.player.destroy() for partially-initialized YouTube players (WORLDMONITOR-5C/5B) - 11 new ignoreErrors patterns for IndexedDB races, browser vendor internals, and extension-injected errors - beforeSend filter for blob: URL extension frames
…7 locales (koala73#403) The header.settings i18n key was incorrectly set to "PANELS" (and its translations) for the settings modal title. The modal contains General, Panels, and Sources tabs — the overall title should be "SETTINGS".
…3#404) * fix: sequential Yahoo calls, sector fallback, and missing try-catch guards - list-commodity-quotes: replace Promise.all with fetchYahooQuotesBatch to prevent Yahoo 429 - get-sector-summary: add Yahoo Finance fallback when FINNHUB_API_KEY is missing - list-etf-flows: sequential fetch loop + add missing try-catch around cachedFetchJson - get-macro-signals: replace unnecessary Promise.allSettled([single]) with direct await * fix: tighten AI summary prompts to 2 sentences / 60 words max Summaries were often verbose walls of text despite "2-3 sentences" in the prompt. Changed to "2 concise sentences MAX (under 60 words total)" across all brief, analysis, and fallback prompts. Reduced max_tokens from 150 to 100 to hard-cap output length.
…uards (koala73#406) - list-commodity-quotes: replace Promise.all with fetchYahooQuotesBatch to prevent Yahoo 429 - get-sector-summary: add Yahoo Finance fallback when FINNHUB_API_KEY is missing - list-etf-flows: sequential fetch loop + add missing try-catch around cachedFetchJson - get-macro-signals: replace unnecessary Promise.allSettled([single]) with direct await
…sistence (koala73#407) - Show rate-limited message instead of generic "Failed to load" on Markets, ETF, Commodities, and Sector panels when Yahoo returns 429 - fetchYahooQuotesBatch returns rateLimited flag; early-exit after 3 misses - ETF panel skips retry loop when rate-limited, shows specific i18n message - Fallback Finnhub symbols through Yahoo when API key missing - 401-retry in runtime fetch patch for stale sidecar token after restart - diagFetch auth helper for settings window diagnostic endpoints - Verbose toggle writes to writable dataDir instead of read-only app bundle
* chore: bump v2.5.10 and update README for recent fixes Version 2.5.9 → 2.5.10. Roadmap entries for: - Yahoo Finance rate-limit UX across all market panels - Sidecar auth resilience (401-retry, settings diagFetch) - Verbose toggle persistence to writable data directory - Finnhub-to-Yahoo fallback routing * chore: add v2.5.10 changelog entry
…oala73#347) (koala73#410) showOfflineMessage() and showEmbedError() replaced innerHTML without cleaning up this.player, so initializePlayer() bailed early on the next channel switch — leaving a black screen. destroyPlayer() is idempotent so the onError path won't double-destroy. Co-authored-by: N Cho-chin <Niboshi-Wasabi@users.noreply.github.com>
Fixes: - Linux AppImage black screen on WebKit/GStreamer (koala73#411) - Destroy live news player before showing offline/error message (koala73#410)
Launch the built AppImage under Xvfb after the Linux build to catch startup crashes and render failures automatically. Uploads a screenshot artifact for visual inspection.
…oala73#414) The squash merge of koala73#413 put smoke test steps into build-desktop.yml instead of the intended standalone workflow. This commit: - Reverts build-desktop.yml to its original state - Adds test-linux-app.yml as a separate Linux-only smoke test workflow
Author
|
awesome. Ill work on this today and put in a PR to address the Final review. Cheers |
* fix(ci): use weston+XWayland for Linux smoke test instead of pure Wayland Previous attempt used GDK_BACKEND=wayland which caused GTK init panic (tao requires X11). Now: weston headless with XWayland provides X11 through a real compositor. Falls back to Xvfb if weston fails. Also uploads weston/app logs as artifacts for debugging. * refactor(ci): use xwfb-run for Linux smoke test display xwfb-run (from xwayland-run package) is purpose-built for this: Xwayland on a headless Wayland compositor, replaces xvfb-run. Falls back to plain Xvfb if xwfb-run is unavailable. Uploads display-server and app logs as artifacts.
Only run CI on PRs from branches within the repo, not from external forks. Prevents unnecessary action minutes from contributor PRs.
* ci(linux): add AppImage smoke test to desktop build Launch the built AppImage under Xvfb after the Linux build to catch startup crashes and render failures automatically. Uploads a screenshot artifact for visual inspection. * Optimize Wingbits API usage and panel polling
…oala73#419) Linux had no keyring backend feature enabled — keyring v3 fell back to in-memory mock store. Secrets appeared to save but were lost on restart. Added `linux-native-sync-persistent` (kernel keyutils + D-Bus Secret Service combo) and `crypto-rust` for Secret Service encryption. This uses GNOME Keyring or KDE Wallet on desktop Linux for persistent storage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Type of change
Affected areas
/api/*)Checklist
api/rss-proxy.jsallowlist (if adding feeds)npm run typecheck)Screenshots