267 Commits

Author SHA1 Message Date
myron ee0e116963 Add copyright notice 2026-07-26 23:53:37 -05:00
myron adbd1a7a24 Stop flagging parkerslingshotrentals as DOWN: it's intentionally behind a Basic Auth Coming Soon gate during rebuild, so 401 is expected there, not a failure
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 00:51:54 -05:00
myron 73aac8ab01 Fix weather widget location label stuck on Fort Worth: the span was a static HTML placeholder never wired to the API response. Wire loadWeather() to update it from d.location, and correct the fallback text to Weatherford, TX
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 00:45:04 -05:00
myron 646da21b86 Update weather section location to Weatherford, TX 76088 (from Fort Worth)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 19:55:05 -05:00
myron d97a345672 Fix network map duplicate-device bug: drop nmap --send-ip (was causing MAC misattribution/stale ARP entries) and dedupe network_devices by MAC on every scan push so IP changes don't leave orphaned rows
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 19:53:17 -05:00
Claude 141191bcdd Fix jarvis-health.sh: watchdog-restart alerts never deduped or auto-resolved
source_key was minute-stamped (health:wd_restart:YYYYMMDDHHMM), so the same restart event seen across two 5-min cron runs within the logs 6-min lookback window got two different keys -> two alert rows + two emails, and the key never matched a clear_cond call so these rows stayed resolved=0 forever, accumulating in the active-alerts view.

Fixed to a stable key (health:wd_restart), matching the pattern used by the other three checks in this script: raise() now dedups via the existing COUNT..resolved=0 check, and clear_cond() runs when no recent restart line is found.

Verified live: injected a fake watchdog restart log line, ran the script twice -> exactly 1 alert row + 1 email (not 2). Removed the line -> alert auto-resolved (resolved=1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 07:43:20 -05:00
Claude 8399048252 Backup: capture Phase 1/2 env files, systemd drop-ins, and ops scripts
jarvis-backup.sh now also archives /etc/jarvis-arc (reactor.env), /etc/jarvis (db.env), the jarvis-arc.service.d systemd drop-ins, and /usr/local/bin/jarvis-*.sh. Previously a restore would have come back with no API keys or DB password since those moved outside /var/www/jarvis + /opt/jarvis-arc during the secrets sweep.

Verified: ran a real backup (45M) and confirmed all new paths are present in the archive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 23:48:04 -05:00
Claude 652e44f7b3 Add JARVIS health self-check (Phase 2 reliability monitoring)
deploy/jarvis-health.sh (cron */5): detects silent failures the service watchdog cannot — stalled crons (cron.log >10min stale = 2+ missed runs), Arc jobs stuck running >30min, disk >85%, and watchdog service restarts. Writes auto-resolving rows to the alerts table (shown in admin panel) and emails myronblair@gmail.com on any NEW finding via the reactor Gmail SMTP creds.

Verified live end-to-end: injected a fake stuck job -> alert raised + email sent; cleared it -> alert auto-resolved. Installed in root crontab.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:43:37 -05:00
Claude 43be3e1105 Stop tracking INFRASTRUCTURE-REFERENCE.md (full credentials doc)
Untracked from git and added to .gitignore. The file stays on disk at public_html/admin/downloads/ (served behind admin auth) and in the jarvis-private + VM110 copies — it is no longer pushed to GitHub going forward.

NOTE: prior revisions remain in GitHub history; a git filter-repo purge + force-push is still pending user sign-off, as are rotations of the secrets that were in it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:35:41 -05:00
Claude 3d16061709 Auth hardening: login rate-limiting + session fixation defenses
- login.php: Redis-backed per-IP rate limit (10 fails / 15 min lockout), keyed off CF-Connecting-IP/X-Forwarded-For so it sees the real client behind NPM; fails open if Redis is down

- login.php: session_regenerate_id(true) on successful auth (prevents session fixation)

- php.ini: session.use_strict_mode = 1 (reject unknown/attacker-supplied session IDs)

- netscan.php: constant-time hash_equals for the registration-key check (matches agent.php)

Cookie flags already HttpOnly + SameSite=Lax (verified live). Agent auth verified: missing/bad X-Agent-Key -> 401 on every machine action.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:31:57 -05:00
Claude 80588efa7a Secrets sweep: move hardcoded credentials out of tracked files into env files
Removed live secret literals from git-tracked code (all were on GitHub):

- deploy/reactor.py: Claude/Groq API keys, DB pass, Gmail/iCloud app passwords now from os.environ (loaded via systemd EnvironmentFile=/etc/jarvis-arc/reactor.env, root:www-data 0640)

- public_html/login.php: used a private hardcoded PDO connection; now uses config.php DB_* constants

- deploy/jarvis-backup.sh (runs via cron), jarvis-deploy.sh, jarvis-watchdog.sh: DB pass now sourced from /etc/jarvis/db.env (root:root 0600)

- removed dead agent/jarvis-arc-reactor.py (unreferenced old duplicate leaking an old Groq key + stale Ollama IP)

- added deploy/reactor.env.example and deploy/db.env.example templates

Verified live: reactor restarted with all 21 handlers + DB poller (job round-trip OK), login works, mysqldump auth via env OK.

NOTE: these keys remain in GitHub history and should be rotated (Claude/Groq/Gmail/iCloud/DB). Separate decision needed on INFRASTRUCTURE-REFERENCE.md (full cred doc still tracked) + history purge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:28:42 -05:00
Claude f7309a15fc Rotate agent registration key; remove key literals from public scripts/UI
- install.sh, install-agent.sh: require JARVIS_REG_KEY env var or interactive prompt instead of baked-in key (matches install-mac.sh/install-windows.ps1 behavior)

- netscan.php: reuse AGENT_REGISTRATION_KEY constant instead of a duplicate literal

- agent.php + api.php: add session-authed "regkey" action so the admin install modal fetches the current key at runtime

- jarvis-agents.js: fetch reg key via /api/agent/regkey instead of hardcoding it; pass JARVIS_REG_KEY in the Linux install one-liner

- INFRASTRUCTURE-REFERENCE.md: scrub old key literal (rotated; real value lives only in api/config.php on VM211)

Key rotated on the box + rolled out to all 11 agents (verified all re-register online). New value is in the gitignored api/config.php only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:22:00 -05:00
Claude 18783dc137 Fix errors unmasked by re-enabling error_reporting(E_ALL)
- config.example.php: error_reporting(0) -> E_ALL (live config.php matches); add JELLYFIN_URL/JELLYFIN_API_KEY placeholders

- history.php, jellyfin.php: drop require of nonexistent includes/auth.php + AuthMiddleware call (router enforces auth centrally) — both endpoints were fataling on every request

- remove stale kb_intent_generator .bak files from deployed tree

DB (not in repo): kb_facts.fact_value TEXT -> MEDIUMTEXT; ha/entity_map had failed every write since Jul 2 at >64KB

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:43:37 -05:00
root 8f6be645ed Fix auto-detect agent install button: commands shown for Windows/Linux no longer use flags the scripts dont actually support (install-windows.ps1 has no -JarvisUrl/-Key params, install.sh has no --jarvis-url/--key flags), download links use the current page origin instead of a hardcoded URL thats unreachable from outside the LAN, Windows command reflects the new no-Python exe install, fixed the top-level install-agent.sh which still pointed at the pre-migration DO server IP (165.22.1.228) and would have failed outright 2026-07-07 12:43:54 -05:00
root 185d2c889f Fix AGENT button showing the wrong machine: same-subnet fallback matched whichever agent happened to be first in the list, not the actual browsing machine — happens whenever a LAN client hits the dashboard via hairpin NAT/external hostname and the server sees the same reflected IP for every visitor. Exact-match only now; falls through to not-detected instead of misreporting another real machine as yours. 2026-07-07 12:41:53 -05:00
root b5c47d898b Windows agent v3.2: build standalone PyInstaller exe (no Python/pywin32 install needed on target machines), add frozen-mode self-update (rename-swap since a running exe cant be overwritten in place), simplify installer accordingly, fix default install URL (jarvis.orbishosting.com default port is unreachable from outside the LAN - use :1972), fix stale windows=3.0 in the admin panel version-check map 2026-07-07 12:20:22 -05:00
root ffc01c3d4a Update infra doc: WAN IP change + full FortiGate VIP list, JARVIS auto-deploy pipeline restoration, admin panel fixes (Works/Site Health/Email Intelligence), backup systems audit + fixes across all 4 systems, Blair HQ Backup Downloads feature 2026-07-07 11:29:45 -05:00
root 156b210184 jarvis-backup.sh: was DB-only, now also backs up /var/www/jarvis, /opt/jarvis-arc, nginx site config, systemd unit, and root crontab — a DB dump alone was useless without the app code and daemon needed to actually restore JARVIS. Also fixed a typo (SIYE->SIZE) that silently broke the backup-size log line. 2026-07-07 10:54:24 -05:00
root 09f73edb0b Fix silent compose failures: poll actual job status in the compose modal instead of a fire-and-forget dispatch toast; add Groq 429 retry-with-backoff using its own rate-limit-reset header (12k tokens/min tier gets exhausted by gmail_triage alone) 2026-07-07 10:49:08 -05:00
root a4336ebdd6 Fix Email Intelligence inbox 404: was proxying to the old DO-hosted JARVIS (165.22.1.228/api/email), a dead endpoint since the move to VM211. Now reads email_triage directly, matching the pattern email_action_items already used. 2026-07-07 10:06:48 -05:00
root e7f555fff1 reactor.py: fix Ollama silent-empty-return bug (no error checking on API response), bump Ollama timeout 30s->90s (cold model loads took 15s+ alone), add exception type to fallback log lines 2026-07-07 09:25:25 -05:00
root 8034fc67e9 Fix field-name mismatches between PHP dispatcher and Python reactor: compose_email (recipient/subject/auto_send -> to_email/subject_hint/send) and send_reply (content -> body) were silently dropping the actual recipient, subject, and user-edited content on every dispatch 2026-07-07 09:01:47 -05:00
root 48b2a8523a reactor.py: fix llm_call() silently skipping fallback for explicit provider requests, add /comms/sent/{id}/send endpoint for approving queued drafts 2026-07-07 08:58:36 -05:00
root 5ff4f3e311 Outbox: add SEND button for queued drafts (compose previously had no way to actually send), fix VIEW showing body via list endpoint that omits it 2026-07-07 08:58:20 -05:00
root 24b96e809c Site Health tab: fix parkerslingshotrentals.com label + widen cards for full domain names; fix sites freshness-check interval mismatch (300s vs 180s cron) causing checks to feel far apart 2026-07-07 08:41:52 -05:00
root 8567018cc3 Test: verify auto-deploy pipeline end-to-end 2026-07-07 08:25:12 -05:00
root f8a095f783 Fix Works-tab last-run detection bugs, add generic live-log popup for Facts/Stats/Calendar workers, fix webhook branch check (master not main) and log path 2026-07-07 07:58:55 -05:00
root e060ff0c63 Merge origin/master history (ours: live production content is authoritative, origin was stale) 2026-07-07 07:55:58 -05:00
root 588cfe3f10 Adopt live production state as git baseline 2026-07-07 07:55:47 -05:00
root 3db329e925 Correct Pioneer VSX-822: wired through a 4th WiFi extender, not dual-NIC 2026-07-06 23:41:34 -05:00
root c01805316a Correct Pioneer VSX-822 attribution: confirmed at .100, note dual-MAC discrepancy 2026-07-06 23:38:34 -05:00
root 20b510186a Add network equipment and client device inventory (Section 14) from live ARP scan + manual confirmation 2026-07-06 23:34:31 -05:00
root 9b5e16660a Jellyfin: regenerate stale admin API token, document real admin username 2026-07-06 14:29:43 -05:00
root 7020d445b3 Update infra doc: MediaStack/Jellyfin verified detail, NordVPN LAN Discovery + wg0 lockout fix, VMID corrections 2026-07-06 13:09:02 -05:00
myron 80b0dfc583 Document code review + fixes across all 4 DO-hosted business sites (2026-07-06) 2026-07-06 02:58:28 -05:00
myron 30e2bc093c Document WEB HOST agent install and timezone freshness-check fix 2026-07-05 21:56:23 -05:00
myron a29670e93d Fix WEB HOST stats never populating (DO server had no monitoring agent installed) and a timezone bug in freshness checks (America/Chicago default timezone + strtotime() on naive UTC MySQL timestamps caused sites/proxmox/ollama facts to never refresh, and could have suppressed the KB intent generator's scheduled runs) 2026-07-05 21:30:53 -05:00
myron 10350cbcd8 Update infrastructure reference: document 2026-07-06 security review and fixes 2026-07-05 20:13:21 -05:00
myron 24bc876c1d Fix code review findings: unauthenticated infra doc + backup file exposure, onclick-attribute XSS breakouts (admin panel and front-end), plaintext calendar passwords, k()->j() typo, wildcard CORS, session cookie hardening (HttpOnly/SameSite) 2026-07-05 20:09:52 -05:00
myron cfb5b2a3f9 Document ChuckCo Time Keeper code review fixes and admin login rate limiting 2026-07-05 19:17:14 -05:00
myron 0b1a19d9de Update infrastructure reference: fix stale JARVIS port, rotate GitHub PAT reference, add ChuckCo Time Keeper site, FortiGate DNS change, git/repo management section 2026-07-05 18:58:56 -05:00
myron 66a5443f22 Document Homebridge backup switch from MSP360 to Proxmox vzdump 2026-07-04 12:21:53 -05:00
myron e5536b077c Document MSP360 backup status dashboard integration 2026-07-03 08:03:54 -05:00
myron a292411d52 Stop hardcoding a generic watch_services list on every agent install
The installer wrote the same service list (ollama, homeassistant, mysql,
mariadb, nginx, apache2, docker) onto every host regardless of what it
actually runs, causing false "Service Down" alerts on hosts that never
installed those services. Default is now empty; watch_services should be
set per-host to match what's actually running there.
2026-07-02 20:28:42 -05:00
myron 26b501b600 fix: address 8 code-review findings in KB topic manager
- Fix 1 (ORDER BY): use table alias t.id to force integer PK ordering;
  topic_id alias was causing alphabetical sort, breaking rotation offsets
- Fix 2 (PDOException): wrap INSERT/UPDATE in try/catch in kb_topic_save;
  duplicate topic_id now returns clean JSON error instead of HTTP 500
- Fix 3 (XSS/onclick): DEL button passes only t.id; tmDelete looks up
  name from _topicsData, removing JSON.stringify from onclick attribute
- Fix 4 (validation): topic_id must contain at least one [a-z0-9] after
  sanitization; "@@@" to "___" no longer passes required-field check
- Fix 5 (stale logs): guard comment and log messages updated from 20h to
  4h to match the actual 14400s threshold
- Fix 6 (dedup): tmEsc() replaced with existing esc() throughout; removed
  duplicate function definition
- Fix 7 (toggle rollback): tmToggle uses inline fetch to revert el.checked
  on API failure instead of leaving the UI in wrong state
- Fix 8 (confirm): tmDelete uses openModal confirmation instead of
  confirm() dialog, consistent with project live-popup convention

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014p87VFec84hNaf2WpvmLrW
2026-07-02 10:26:47 -05:00
myron 7327104612 feat: DB-driven KB topic manager — admin UI + migration
- Create kb_generator_topics table (140 topics migrated from hardcoded array)
- kb_intent_generator.php now loads active topics from DB instead of $BATCHES array
- Admin panel: MANAGE TOPICS button opens full topic manager modal
  - Browse all 140 topics with search, category, and active/disabled filters
  - Inline active toggle per topic (checkbox)
  - Add new topic form (topic_id, category, name, description)
  - Edit existing topics (all fields)
  - Delete topics with confirmation
  - Run count display
- Backend API cases: kb_topics, kb_topic_save, kb_topic_delete, kb_topic_toggle
- Topics can now be added/managed without any code changes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014p87VFec84hNaf2WpvmLrW
2026-07-02 07:04:20 -05:00
myron a13f750846 feat(kb-intent): expand to 140 topics, 109 KB topic library
Rich topic library across mathematics (12), sciences (13), history (10),
government/economics, literature, life skills (13), technology (5),
Texas/local (4), national US (3), world affairs (5), human sexuality (2),
astronomy (3), space (2), culture/arts (8), sports (8), food/drink (4),
home/DIY (3), wellness (4), tech continued (3), national continued (2),
world continued (2), medicine (3), math continued (2), communication (2).

Each topic has detailed multi-subtopic descriptions (~200 chars each)
vs prior 8-word descriptions — significantly richer Groq prompts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014p87VFec84hNaf2WpvmLrW
2026-07-02 06:50:12 -05:00
myron 3c8dd8e206 feat(kb-intent): 122-topic rotation engine, every-6h cron
- Expanded $BATCHES from 25 to 122 topics across: life skills, personal
  finance, Texas/local, US national, world geopolitics, human sexuality
  (educational), deep astronomy (15 topics), and space exploration (15 topics)
- Rotation engine: 25 topics per run cycling through all 122 in order;
  wraps to topic 1 on cycle complete (~30h full cycle at 6h interval)
- batch_offset tracked in kb_facts for cross-run persistence
- Cron changed from 0 3 * * * to 0 */6 * * * (every 6 hours)
- 20h skip guard reduced to 4h so 6h cron isn't blocked
- max_tokens bumped 3500 → 5000 to prevent JSON truncation errors
- JSON extraction: partial recovery + raw snippet logged on failure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014p87VFec84hNaf2WpvmLrW
2026-07-01 22:53:57 -05:00
myron 554488aefa fix(kb-intent): reduce batch size 40→20 intents, raise max_tokens to 5000
Token budget was too low for 40 intents — responses were truncated mid-JSON,
causing "No JSON array found" on ~88% of batches. Fixes 880 errors/run.
Also adds partial-JSON truncation recovery and raw response debug logging.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014p87VFec84hNaf2WpvmLrW
2026-07-01 22:44:22 -05:00
myron e99c3aa171 feat(admin): KB intent generator — force run, background on close, history panel
- Always runs when triggered from admin (JARVIS_FORCE_RUN=1 bypasses 20h guard)
- Closing popup stops UI polling but server job continues; toast confirms background run
- History panel at top of popup shows last success time/count + failures from last 7 days
- New intent_gen_history backend case parses cron.log for status summary

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014p87VFec84hNaf2WpvmLrW
2026-07-01 22:39:41 -05:00