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).
The LocalSystem service account cannot access per-user Python installs
(AppData\Local\Programs\Python\...). When a per-user install is detected,
automatically install Python system-wide before proceeding.
- Detect per-user Python (AppData in path) and trigger system-wide install
- Extract system Python install logic into Install-PythonSystemWide function
- Check winget exit code before marking install successful
- Split pip install and postinstall into separate steps; pip failure is fatal,
postinstall failure is a warning (service DLLs may already be registered)
- Use $LASTEXITCODE check on pip rather than try/catch (external process)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the scheduled-task approach (required user to stay logged in) with a
proper Windows Service using pywin32. The service runs as LocalSystem, starts
at boot, and auto-restarts on failure — no PowerShell window needed.
Agent changes (jarvis-agent-windows.py):
- Add Windows Service class via pywin32 (JarvisAgentService)
- Cleanly handles SvcStop by setting a threading.Event
- main() loop uses _stop_event.wait() instead of time.sleep() so stop is immediate
- self_update() signals the stop event when running as a service (SCM restarts it)
- __main__ block dispatches to SCM entry point or HandleCommandLine (install/stop/remove)
- Falls back to direct run if pywin32 not installed (for debugging)
Installer changes (install-windows.ps1):
- pip install pywin32 + postinstall (registers service runner DLLs)
- Python search prefers system-wide install (accessible by LocalSystem)
- Downloads Python 3.11 directly from python.org for Win 8.1 machines without winget
- Removes legacy JARVIS-Agent scheduled task if present
- Registers JARVISAgent service with --startup auto
- Configures sc.exe failure recovery (restart at 5s/10s/30s)
- Updated management commands in summary (Start-Service, Stop-Service, etc.)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add version column to registered_agents table
- Agents send version on registration (Linux 3.1, Windows 3.0, macOS 3.0)
- workers_list API returns latest_versions per platform
- Workers tab: VERSION column with green check (up-to-date) or red (outdated)
- Outdated agents highlight row and show blue UPDATE button
- Up-to-date agents show dimmed UPDATE button
- Update button dispatches update command immediately
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Old installer wrote to /opt/jarvis-agent/config.json with server_url/api_key/
heartbeat_interval keys and pre-registered with JARVIS. Agent v3.0 expects:
- Config at /etc/jarvis-agent/config.json with jarvis_url/registration_key/
hostname/poll_interval/heartbeat_every keys
- api_key stored by agent itself in /var/lib/jarvis-agent/state.json
- Agent self-registers at startup using registration_key
Also adds: imagemagick install (headless screenshot support), apk support
for Alpine/WireGuard, copies to /usr/local/bin/jarvis-agent.py.
Previously agents only registered when api_key was missing (first run).
After updating to v3.0 with screenshot capability, restarted agents never
refreshed their capabilities in the DB. Now register() is called every
startup — server does UPDATE on existing agent_id so api_key is preserved.
self_update(cfg) and shell allow_shell_commands check both referenced cfg
from run() scope, but execute_command() is a standalone function. Fixed by
calling load_config() locally in each branch that needs it.
A ParseError or fatal in any endpoint file now returns JSON 500 for that
endpoint only. switch replaced with data-driven map. All other endpoints
continue working normally when one is broken.
Arc Reactor was running from /opt/jarvis-arc with no version tracking.
Added to deploy/ so all fixes (metrics_json→metric_data, flat JSON parsing,
disk mount key fix) are captured. WG configs are runtime-generated secrets
and must not be committed.
Swap: replace grid-column reassignment with named grid-template-areas
(grid-column approach caused leftPanel to disappear and mis-position).
"left center right" <-> "right center left" cleanly swaps both columns.
Collapsible: clicking any panel-title collapses/expands that panel.
Chevron rotates -90deg when collapsed. State persists in localStorage.
All interactive elements in title bars (+ buttons etc) still work.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Broke entire JS block — side panels, data loading, everything.
synthesis.length>1500 ternary had bare newlines inside single quotes.
Replaced with \n escape sequences.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
const ts = ts() in loadVision caused TDZ ReferenceError crashing gallery.
visionRunScreenshot now fetches online agents from agents_list API when
no screenshots exist yet (previously showed No agents online falsely).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ARC REACTOR tab had HTML and PHP API handlers but no JS load function,
causing ReferenceError on every tab click. Adds all three missing functions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rename memory section CAT_COLORS to MEM_CAT_COLORS to avoid SyntaxError
that prevented doLogin from being defined, locking users out of admin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DB: missions, mission_steps, mission_runs tables
- reactor.py v7.0.0: handle_run_mission, _execute_mission, mission_trigger_loop (schedule/guardian_event/email_keyword triggers), {{template}} substitution across steps, full CRUD REST endpoints
- arc.php: missions/mission_get/mission_runs/mission_create/mission_update/mission_delete/mission_run/mission_toggle actions
- admin/index.php: Mission Ops tab with visual workflow builder (trigger config, step cards with ↑↓, JSON payload editor, continue-on-failure flag), run history with step-level detail, enable/disable toggle
- index.html: MISSIONS tab with collapsible mission cards, RUN NOW button per mission, live run result feedback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- chat.php: Add Tier 0.9a (gmail_triage), Tier 0.9b (remote_exec) detection;
refactor arc submit into arcSubmitJob() helper; natural-language triggers for
email triage (check my email, triage inbox) and remote exec (restart X on Y,
run X on Y, get logs from X on Y)
- arc.php: Add triage and triage_action endpoints (read/update email_triage table)
- index.html: Add COMMS tab with triage card UI (filter bar, category badges,
draft reply viewer, copy/dismiss actions); loadComms() with 8s polling;
onArcJobStarted() routes gmail_triage jobs to COMMS tab
- admin/index.php: Add GMAIL TRIAGE section under COMMUNICATIONS nav; triage_list/
triage_action/triage_run PHP actions; loadTriage() JS with full table + draft
modal; triageRunNow() submits gmail_triage job to Arc Reactor
Arc Reactor v2.0:
- research handler: DDG search → async page fetch → trafilatura extraction → Claude synthesis
- tool_loop handler: multi-step agent loop (up to 200 iter) with web_search, fetch_url, jarvis_agents, jarvis_alerts, current_time tools
- llm handler: multi-provider router (Claude/Groq/Ollama)
- /jobs/recent endpoint for HUD polling
- Phase 1 handlers preserved (ping/echo/shell)
chat.php — Tier 0.9 Intel Protocol (before KB intent engine):
- Detects: research/investigate/deep-dive/look up/find out about → research job
- Detects: step-by-step/figure out/analyze and report → tool_loop job
- Returns arc_job ID in response for UI polling
- Depth modifiers: quick/standard/deep
index.html:
- INTEL tab in right panel tab bar
- Research result cards with expand/collapse, synthesis, sources, status
- Live polling (4s) when INTEL tab is active + active jobs present
- Auto-switches to INTEL tab when research is triggered from chat
- intelPrompt() pre-fills chat input for new research
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Python asyncio daemon (/opt/jarvis-arc/reactor.py) running on 127.0.0.1:7474
- systemd service (jarvis-arc) auto-starts with MySQL dependency
- arc_jobs + arc_status MySQL tables for async job queue
- api/endpoints/arc.php: PHP bridge to daemon (status, job_create, job_get, jobs, purge)
- api.php: added arc route
- index.html: ARC REACTOR status indicator in bottom bar with live polling
- admin/index.php: ARC REACTOR nav section + full job management panel
- Built-in job handlers: ping, echo, shell (whitelist-gated)
- Foundation for Phase 2 (Intel Protocol) and beyond
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace tiny dot nodes with frosted-glass bubbles with ambient glow and float animation
- Add 6th ring for netscan-discovered network devices (cap 28)
- Split named/DB devices and discovered devices into separate rings
- Push rFrac to 0.82 to fill the overlay window
- Increase all ring caps and node radii
- Add FortiGate NAT IP to providers ACL
- Fix TCP SIP drop issue via transport=udp
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause 1: Notification.requestPermission() on startup (3s delay) opened
a browser permission dialog while JARVIS was still speaking the welcome greeting.
This aborted the SpeechRecognition session. Because isSpeaking=true at that
moment, onend did not reschedule a restart — mic went permanently silent.
Fix: removed the startup requestPermission() call entirely.
Root cause 2: Same requestPermission() inside _focusWindow() called on every
enterVoiceMode() — could abort the recognition session on each wake.
Fix: only create notification when permission already granted, never request.
Root cause 3: SLEEP_CMDS matched bare words like offline and sleep that appear
in normal commands (check if server is offline, put device to sleep, etc.)
Fix: tightened to require explicit phrasing — go offline, sleep mode,
shut down jarvis, good night jarvis, etc.
Sleep mode:
- Commands: good night / go to sleep / shut down / standby / offline / signing off
- Works via voice or text
- UI dims to 8% brightness, slow-spinning standby reactor overlay appears
- Refresh loop pauses (light 2min heartbeat keeps session alive)
- Mic stays fully active — only responds to master wake phrases
- Idle-reload disabled while sleeping (prevents unwanted reloads overnight)
Wake from sleep (master wake phrase):
- Detects wake phrase while isAsleep=true, routes to wakeFromSleep()
- Full HUD boot sequence animation (panels slide in)
- refreshAll() fires immediately to reload all data
- JARVIS greets: All systems back online
Window focus on any wake:
- window.focus() called on every enterVoiceMode
- document.title flashes 8x between JARVIS ONLINE and default
- Web Notifications API: system popup fires when window is minimized/backgrounded
- Notification permission requested 3s after login
- Works regardless of sleep/voice mode
Reverted to c8e0020 (all 10 effects working) then added net map cleanly:
- Used var/for instead of const/let/arrow-functions to avoid any closure/scope issues
- Orbital ring layout: JARVIS hub center, 4 concentric rings (proxmox/services/agents/devices)
- Rings rotate at different speeds/directions independently
- Spoke lines hub-to-each-node with cyan inbound and orange outbound particles
- Node labels point outward from center, never overlap
- Tiny green/red status dot on every non-hub node
- Hover shows node info card (name/IP/status/ring)
- Open: say/type show network map / network topology / show connections
- Close: say/type close map / close network / dismiss map
- All other features (mic, voice, text, panels) unaffected
- Overlay shrunk to min(860px, 86vw) x min(570px, 76vh) — fits any screen
- Solar system layout: JARVIS hub at center, 4 concentric orbital rings
- Ring 1 (green, innermost): Proxmox nodes, rotates clockwise
- Ring 2 (gold): Services (HA, AI, PBX, Homebridge), counter-clockwise
- Ring 3 (cyan): Linux/Windows agents, slow clockwise
- Ring 4 (dim blue, outermost): Network scan devices, slow counter-clockwise
- Rings rotate at different speeds/directions (persistent offsets across frames)
- Each ring draws dashed track + tick marks every 30 deg + label + online/total count
- Nodes evenly spaced on their ring, rotate with it
- Spoke lines from each node to hub (straight, low opacity)
- Particle flow on spokes: cyan in (data), orange out (commands)
- Node positions computed per-frame from angle+ring radius+rotation
- Overlay canvas sized exactly to container minus header+legend height
- Quadrant layout: Proxmox (top-left), Services (top-right), Agents (bottom-left), Devices (bottom-right)
- Dashed divider lines + subtle per-zone color gradient fill separates sections visually
- Zone watermark labels (PROXMOX CLUSTER, SERVICES, AGENTS, NETWORK DEVICES) with online/total count
- Nodes arranged in tidy grid within each zone — no more single crowded ring
- Labels positioned OUTWARD from hub center (atan2 to calculate angle) so they never overlap nodes
- Bezier lines bow outward away from hub center (control point pushed along hub→midpoint vector)
so lines spread out and each is individually traceable
- IP shown only on hub and hovered nodes — reduces label clutter
- Overflow indicator: shows +N MORE when zone has too many nodes (max per zone: 6/6/8/10)
- Intra-zone cross-links for Proxmox cluster (green) and Services cluster (gold)
- RGB color system replaces old r/g/b object — cleaner rgba() template strings
- Voice: say show network map / network topology / show connections to open
- Voice: say close map / dismiss / close network to close
- Same commands work in chat text input
- Explode animation: overlay expands from top-left reactor position with clip-path wipe
- Collapse animation: folds back to reactor on close
- Visualization: live node graph with bezier curved edges, hub (JARVIS) at center
- Inner ring: all registered agents (agents color-coded by type: proxmox=green, HA=gold, etc)
- Outer ring: netscan-discovered devices
- Rotating orbit rings on hub and agent nodes
- Pulsing radial glow per node keyed to online status
- Hub cross-hair targeting lines
- Directional particle flow:
- CYAN particles: data/heartbeats flowing FROM agents TO JARVIS hub
- ORANGE particles: commands flowing FROM JARVIS hub TO agents
- All particles travel curved bezier paths, fade at endpoints, glow with shadows
- Mouse hover: node info card shows name/IP/status/type
- Stats bar: total nodes, online count, agent count
- Background: faint hex grid overlay for sci-fi depth
① HUD corner rings: animated scanning arcs in all 4 screen corners with tick marks, edge lines, moving dot
② Data stream columns: 22 subtle falling hex/glyph columns behind everything (Matrix-adjacent, very low opacity)
③ Network topology canvas: live node constellation above the network list with pulsing travel dots on connections
④ HUD boot sequence: topbar/panels slide in from edges with staggered timing on every login
⑤ Breathing vignette: screen edges slowly pulse + shifts to red when alerts are active
⑥ EKG heartbeat: scrolling ECG waveform in bottom bar (P-QRS-T complex, green glow)
⑦ Audio waveform ring: animated bar ring around the arc reactor during mic/TTS activity
⑧ Typewriter: JARVIS chat responses type out character by character with adaptive speed + cursor blink
⑨ Static noise burst: random panel gets 280ms noise overlay every 75-130 seconds
⑩ Ambient color cycle: --cyan slowly drifts between blue-cyan and green-cyan over 70s loop
- Remove isSpeaking outer guard — detection loop now runs always so lastFaceSeen stays current
- While isSpeaking + no face detected: refresh lastFaceSeen to prevent exit timer ticking during TTS
- Raise no-face exit threshold from 3s to 12s — sporadic missed frames no longer kill the session
- Add noCommandMs guard: camera never exits voice mode within 12s of last spoken command
- Voice auto-trigger still respects isSpeaking (wont reactivate mid-response)
- Smooth lerp animation loop (rAF at 60fps) drives .tb-logo translateX/Y toward face center
- Face X flipped to match mirror (move right = reactor slides right toward you)
- Scan crosshair overlay appears on screen at detected face position with spinning ring
- Reactor glows brighter (drop-shadow) while face tracking is active
- Graceful: coasts back to center when face lost, snaps off cleanly on camera disable
- Video frame is 320x240 mapped to viewport coords for overlay positioning
- Mouse parallax: panels tilt in 3D toward cursor + columns shift depth (perspective:1200px on layout)
- Sparklines: mini 25-point line charts under CPU/mem/disk bars (cyan/green/orange per metric)
- Panel flash: system panel border pulses bright cyan on each data refresh
- Glitch: JARVIS title text does chromatic aberration glitch every 35-60s (random interval)
- Alert pulse: red radial overlay slowly breathes when there are unresolved alerts
- Hover rise: panels lift extra 4px + brighter border on mouse hover
- Bonus: metric bar shimmer (animated light sweep through filled bars)
- Ambient particle canvas: 65 nodes with dynamic connection lines (GPU-accelerated)
- Floating panels: translateY oscillation with staggered phases per panel (pure CSS)
- HUD corner brackets on every panel (4-corner L-brackets via CSS ::after gradients)
- Animated grid drift: background-position keyframes give moving-through-space effect
- Scanline sweep: bright horizontal band that slowly scans the full viewport
- Mini arc reactor in top bar: always-on spinning rings + pulsing core
- Parallel API fetches in refreshAll(): Promise.all cuts refresh latency ~3x
- Animated number counters: CPU/mem/disk roll smoothly to new values (ease-out cubic)