- Adds body.kiosk-mode class on fullscreen entry/exit
- Hides: #server-panel, #tab-agents, #tab-guardian, tab buttons
- Hides bottom bar: Home Assistant, Agents, Memory, Proxmox
- Falls back to INTEL tab if agents/guardian was active on kiosk entry
- All elements remain visible in normal/tablet mode
- /api/do now includes do_server key with jarvis-do agent metrics
(CPU, RAM, disk, uptime from Tailscale-connected DO server agent)
- Front page JARVIS SERVER panel has WEB HOST section with live
CPU/RAM/DISK bars from DO server agent data
- Panel title updated to show 10.48.200.211 (JARVIS VM IP)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Site checks use external URLs instead of 127.0.0.1 loopback (JARVIS
no longer shares a server with the websites)
- JARVIS site URL updated to port 1972
- Fixed syntax error in DO server ping exec call
- Removed Host header injection (not needed for external checks)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three issues caused periodic worker saturation:
1. Network section pinged 5 private LAN IPs (10.48.200.x) unreachable
from DO — each failed after 1s timeout = 5s wasted per run.
Replaced with a fast DB query on registered_agents.
2. pve_api_get() had no CURLOPT_CONNECTTIMEOUT — added 3s limit so
unreachable Proxmox fails fast instead of blocking the full 8s.
3. Ollama curl timeout reduced from 5s→3s total, added 2s connect limit.
Cron interpreter also changed from lsphp85 to php8.3 in crontab
(done directly on server) — lsphp85 adds ~8s LSAPI startup overhead
and consumes a PHP worker slot; php8.3 runs standalone.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A single SyntaxError in the 1668-line monolith kills every panel
(proven by the apostrophe bug on 2026-06-17). Split into:
panels/jarvis-arc.js (608 lines) — Arc Reactor, Intel, Comms, Guardian
panels/jarvis-agents.js (715 lines) — Missions, Directives, Memory,
Clearance, Agents tab, Sites, Vision
panels/jarvis-assistant.js (345 lines) — Chat History, Suggestions,
Mobile, Command Palette, Topo map
A parse error in any one file now fails only that group of panels.
escHtml() stays in jarvis-arc.js (loads first) and remains global.
All other dependencies (api, speak, addMessage) come from jarvis-app.js.
Version param bumped to ?v=20260617b to force Cloudflare cache miss.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
public_html/agent/ is what agents download for self-update.
It was 5 days out of date — missing the version-in-heartbeat fix
and all other v3.1 changes. Now mirrors agent/jarvis-agent.py exactly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Heartbeat was sending {} — version only appeared in registration.
Agents that never re-register (most of them) stayed NULL in the DB.
Now every heartbeat carries {"version": AGENT_VERSION} so agent.php
can update the column on every check-in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
update_agent_seen() now updates version column when agents include it
in their heartbeat payload. Previously version was only stored on
registration, leaving the Workers tab showing NULL for agents that
hadn't re-registered since v3.1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guardian anomaly alerts and SITREP are pure text reasoning — Groq's
llama-3.3-70b-versatile handles them at near-zero cost with lower
latency. Vision Protocol image analysis stays on Claude (claude-opus-
4-8) because Groq has no vision models. Text-only sysinfo snapshots
(no image captured) also move to Groq.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
One untagged script tag is enough for Cloudflare Rocket Loader to
activate its bootstrap and inject mainScript.js, which declares
mainScriptFlag. When mainScript.js loads twice (script + eval), it
throws SyntaxError: Identifier 'mainScriptFlag' has already been
declared. All script tags now have data-cfasync=false.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
facts_collector was checking https://jarvis.orbishosting.com from the
DO server itself — traffic routes through Cloudflare CDN which can
return 524 timeouts. All sites are hosted on this same OLS instance,
so check via http://127.0.0.1 with a Host header instead. This gives
direct OLS response without CDN overhead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ON DUPLICATE KEY UPDATE was not touching updated_at, so if a site's
status didn't change MySQL never fired the ON UPDATE trigger and the
row timestamp stayed 6 days stale. do_server.php's 15-min freshness
window then returned empty sites.
Also fixes $fresh() querying WHERE fact_category= (non-existent column)
instead of WHERE category=, which always returned no rows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both endpoints tried to require a non-existent includes/auth.php and call
AuthMiddleware::requireAuth() — auth is already handled by api.php before
any endpoint file runs. This caused 500 errors on /api/metrics (which
blocked agent sparklines) and /api/suggestions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jarvis-protocols.js had a syntax error (apostrophe in single-quoted string)
that Cloudflare was caching (4h TTL). Adding ?v=20260617 to all JS script
tags forces a cache miss so the browser gets the fixed file immediately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'What's playing on Jellyfin' — the apostrophe inside the single-quoted
string caused a SyntaxError that prevented the entire file from loading,
making checkArcStatus and all other panel functions undefined.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
agent/list and agent/status are browser-facing and need $_SESSION loaded
to verify auth. Only skip session_start() for machine-agent sub-actions
(heartbeat, metrics, ha_state, command_result, register) that fire every
10-30s. Previous fix skipped session for all agent/* causing the agents
panel to return 401 to the browser.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Agent heartbeats (every 10s from 13 agents) were creating empty session files
because session_start() ran unconditionally. Over months this produced millions
of 0-byte files in the session directory, causing PHP session GC to hang and
making all browser API calls intermittently timeout (panels show offline/empty).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- sendMessage() was fetching /api.php?action=chat which bypasses the
/api/* rewrite rule; api.php parsed endpoint as "api.php" → 404.
Fixed to /api/chat so the rewrite routes it correctly to chat.php.
- agent.php HA entity map INSERT used non-existent fact_type column,
causing PDOException on every agent heartbeat. Fixed to use the
correct (category, fact_key, fact_value) columns.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#1 Voice waveform: Web Audio API drives wave-bar heights in real time
#2 Ambient dim mode: panels fade to 12% after 90s idle
#6 Streaming AI replies: Groq tokens via SSE; frontend ReadableStream
#7 Quick-note capture: N key / "note: text" saves to kb_facts instantly
#8 Cancel in-flight request: AbortController + CANCEL button
#9 Accent color themes: Stark Blue / Widow Red / Hulk Green, localStorage
#10 Browser push notifications: critical alerts when tab is backgrounded
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#3 Live Voice Transcript: Real-time subtitle bar at bottom of screen shows
what JARVIS hears as you speak. Interim results appear word-by-word via
SpeechRecognition.onresult interim events; bar fades 3.2s after final result.
#4 Keyboard Shortcuts: Global keydown handler (skips input fields):
F5=refresh all, Esc=close modals/overlays, M=mute mic toggle,
Space=focus chat input, 1/2/3/4=switch HOME/ALERTS/NEWS/AGENTS tabs.
Shortcut hints added to Ctrl+K palette footer.
#5 Agent Topology Map: TOPOLOGY button in AGENTS tab switches from card
view to animated ring-based canvas showing all agents by type (Proxmox=green
inner ring, HA=yellow mid ring, Linux/Windows=blue outer ring). Live particles
flow hub→agents; offline nodes shown in red. Reads from rendered agent cards.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HA toggle broken after modularization: separate <script src> files are
deferred by Cloudflare Rocket Loader, so inline onchange handlers fire
before toggleHA() is defined. Fix: add data-cfasync="false" to all
four JARVIS script tags to prevent Rocket Loader interference.
Network map cleanup:
- Deduplicate agent devices by hostname — two homeassistant agents
(10.48.200.97 and 172.30.32.1) now show as one node; prefer online
over offline, then most-recently-seen
- Offline agents excluded from inner rings — jellyfin (offline June 3)
and mini_it12 (offline June 12) no longer appear on the map
- DB-pinned devices (Yealink phones) unaffected; still show in devices ring
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#11 Smart Morning Briefing: auto-speaks once per day before noon — fetches
tasks, appointments, active alerts, and weather, composes a ~2-sentence TTS
summary. Stored in localStorage (jarvis_brief_YYYY-MM-DD) to fire only once.
#12 Quick Command Palette (Ctrl+K): frosted-glass overlay with 20 pre-loaded
commands across 6 groups (Network/Agents/Planner/Media/Smart Home/System).
Fuzzy filter as you type, arrow-key navigation, Enter to fire. Matches are
highlighted. Backdrop click or Escape to close.
#13 Live Boot Animation: stat bars and numbers now count from 0 on first render
via tickTo() change. Arc Reactor rings spin in with staggered delays (0.08s
per ring) on login using boot-spin CSS class + @keyframes arcBootSpin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Mobile UI: 3-button bottom nav with panel switcher
- Chat history search: search modal with keyword query
- News filtering: category filter with localStorage persistence
- Proactive reminders: planner/appointment alerts at login and every 5 min
- Proactive alerts: polls every 60s, speaks new critical/warning alerts
- Agent sparklines: 2h CPU+MEM sparkline on each online agent card
- Tier source badge: KB/GROQ/CLAUDE/OLLAMA pill shown after each reply
- VM suggestions: 24h resource analysis via voice command
- HA scene control: fuzzy-match scene activation via voice
- Jellyfin control: pause/stop/next/previous via voice and KB
- Pattern suggestions: usage_patterns table + proactive chips every 30 min
- Multi-step commands: compound "X and Y" command parsing (Tier 0.5)
- Arc Reactor health: warning=amber/1.2s, critical=red/0.6s pulse encoding
- Cross-session history: last 6 turns loaded from prior session
- Restart agent: voice command to restart any JARVIS agent
- New endpoints: history.php, metrics.php, suggestions.php, jellyfin.php
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ha.php: GET scenes action returns live scene list from HA; POST scene_activate triggers by entity_id
- chat.php: ha_scene intent fetches all scenes live, fuzzy token-matches against message, calls scene.turn_on; falls back to listing available scenes if no match
- KB intents: 14 patterns covering good night/morning/goodbye/kitchen lights/ocean dawn/porch + generic activate/run/trigger/set scene
Scenes available: Good Night, Good Morning, Good Morning Work, Goodbye, Kitchen Lights On/Off, Front Porch Lights, Office Ocean Dawn, Master Bedroom
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Proactive alerts (#1): polls every 60s; baselines on load so old alerts are silent; speaks new critical/warning alerts aloud if voice active; adds chat bubble for all new alerts
- Jellyfin control (#2): pause/stop/next/previous via voice — auto-detects active session; 12 KB intents; jellyfin.php control action uses Jellyfin General Commands API
- Agent sparklines (#6): metrics.php returns 2h CPU+MEM history per agent; SVG polyline sparklines rendered in each agent card (cyan=CPU, green=MEM); non-blocking fetch so existing view shows instantly
- Agent health CCR (#7): updated hourly cloud routine to current 13-agent roster, removed ollama-ai and alien-pc, added all active agents with correct IPs/IDs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Voice commands (#3): say "restart the homebridge agent" or "restart mediastack agent" → queues restart_service to that agent; lists options if no hostname matched; 6 KB intents added
- Persistent context (#4): chat.php now loads last 6 turns from most recent prior session before current session history, giving JARVIS memory across page reloads
- Proactive reminders (#5): 3s after login, auto-announces overdue tasks / tasks due today / upcoming appointments; 5-min interval checks for appointments starting within 15 min and speaks alert once
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of crash-looping with KeyError when config has old key names,
load_config() now detects and migrates automatically:
- server_url -> jarvis_url
- api_key -> registration_key
- adds hostname from gethostname() if missing
- adds ssl_verify (false if URL is a bare IP)
- falls back to /opt/jarvis-agent/config.json if /etc path missing
Migrated config is saved in place so the fix is permanent.
Agents self-update within 24h via the existing update_url mechanism.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two issues:
1. NM_OPEN_RE regex was too narrow — phrases like "show me the network",
"open the network", "show network status" did not match, so they fell
through to the API which returned text but never opened the map.
Broadened regex to catch natural network-related phrases.
2. When the network_scan intent IS triggered via API, the map never opened
because the API response handler only processed reply/arc_job.
chat.php now returns open_network_map:true for network_scan intent,
and the client calls openNetMap() when that flag is present.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detects nordlynx WireGuard interface on hosts that run NordVPN and
includes active/inactive status in the metrics payload. JARVIS alerts.php
will generate a critical alert and auto-restart nordvpnd if it goes down.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After writing the updated script, _stop_event.set() caused a clean exit
(code 0). SCM failure recovery only fires on non-zero exit, so the service
stayed down permanently after every auto-update.
Fix: set _update_restart=True before signalling stop; SvcDoRun() checks
the flag after main() returns and calls sys.exit(1), which triggers the
sc.exe failure recovery chain (restart/5s/10s/30s configured at install).