Commit Graph
171 Commits
Author SHA1 Message Date
Gmer4Lfe e58f0352a7 Stop General Chat inventing answers about Varaverk internals
Asked what mover_stop.sh does, it invented a description and dressed it in
real memory facts so it read as authoritative — the exact failure the profile
split exists to prevent. A polite instruction in a system prompt is not a
guard. The rule now leads and is absolute, and a deterministic check repeats
it immediately before the message whenever the question names a shell script,
a SCREAMING_CASE conf key, or Varaverk itself. Detection can only make the
model more cautious, so a false positive costs a redirect, not an answer.
2026-08-03 17:38:43 -04:00
Gmer4Lfe 8d393a1e1c Add three chat profiles: Varaverk Assistant, General Chat, Code Sketcher
Explicit buttons rather than an automatic router. Misclassifying a Varaverk
question as chat produces a confident invention about the user's system, which
is exactly what retrieval exists to prevent — with buttons there is no hidden
heuristic to be wrong and the strict profile is the default you land on.

Only Varaverk Assistant retrieves; the other two would be carrying passages
that cannot help write a folder-copy script. Memory goes to all three, since
that is what lets chat know the setup without claiming authority over it.
History depth is per profile and set server-side: retrieval costs ~2500 of
16384, so the profiles that skip it can hold a real conversation. Code
Sketcher is told to flag flags it is unsure of, after it invented
rsync --no-overwrite.
2026-08-03 17:36:24 -04:00
Gmer4Lfe d0b3588f6c Give the assistant a standing memory file
A small operator-written file handed to the model at the start of every
conversation — who you are, how this install is set up, what has already been
decided. Injected ahead of the retrieved passages and marked operator-authored
so it outranks anything they contradict, and never cited as a source.

Deliberately not indexed and deliberately under DATA_DIR: it changes
constantly, vector similarity is the wrong way to retrieve things you were
told to remember, and gitignoring it keeps personal notes out of a pushed
repository. The character cap is a context budget — this text costs its share
of 16k on every single turn.
2026-08-03 17:11:27 -04:00
Gmer4Lfe 7625e923e5 Accept the global RSYNC_ENABLED flag, not only prefixed tiers
The pattern required a tier prefix, so the master gate the rsync page renders
alongside the tier toggles was rejected as an invalid flag name and sprang
back to off. There was no way to enable syncing from the UI. Masked until now
because every POST to this endpoint was being swallowed as multipart.
2026-08-02 18:49:00 -04:00
Gmer4Lfe 76ad744581 Convert every POST off multipart — 21 call sites across 7 tabs
A multipart POST to the plugin API hangs and never completes on this host: no
status code, and no server-side trace of any kind. The correlation was exact —
every page using URLSearchParams worked, every page using FormData hung, which
is why scheduler and partnership appeared fine while docker, rsync, settings,
auth, arrs, fallback and monitor did not. URLSearchParams has the same append
API and fetch sets the urlencoded content type for it, so each site is a
one-token change with the payload logic untouched.
2026-08-02 18:27:25 -04:00
Gmer4Lfe 47110730e6 Send AI POSTs urlencoded instead of multipart
A multipart POST to this endpoint hangs: no status code is ever returned, and
the request never reaches PHP — no CSRF termination, no fatal, no entry log —
despite leaving the browser with a valid token and a correct body. Every POST
on this host that demonstrably works, including Unraid's own, is
x-www-form-urlencoded. Same fields and same $_POST server-side.
2026-08-02 18:20:57 -04:00
Gmer4Lfe 7f01b3040d Log entry into the AI endpoint before any dependency loads
A POST the browser demonstrably sent — correct token, correct body — left no
trace: no CSRF termination, no fatal, and no action log. Rejected-before-PHP
and died-inside-the-include are indistinguishable from outside, so the first
statement now records that execution arrived.
2026-08-02 18:16:58 -04:00
Gmer4Lfe f30f3263bd Fix nested php open tag in the AI page build stamp
The build-stamp edit replaced the header block's closing tag instead of
keeping it, opening a second php block inside the first. Deployed broken
because the lint in that commit printed OK unconditionally rather than
gating on php -l.
2026-08-02 18:06:52 -04:00
Gmer4Lfe ca678b1784 Stamp the AI page build and tear down stale copies of its script
The tab bar uses Unraid's localURL, which swaps content by AJAX without
tearing down the previous page's JavaScript, so old copies keep their timers
and their state. That makes "is the browser running what I deployed"
unanswerable from the server, and explains banner polls arriving far faster
than the 30s timer. The page now stamps its build, says plainly when its own
script is not the one running, and stops the previous copy's timers.
2026-08-02 18:06:10 -04:00
Gmer4Lfe ae7555a423 Stop a stuck in-flight flag from silently swallowing every later question
A turn that ended without finish() left busy=true, so send() returned at line
one for every subsequent click — no fetch, no error, and the original
"starting…" still on screen. That is a hang which produces no request and so
no server-side trace of any kind. It now says what happened, and the pending
indicator carries an elapsed counter so stalled and merely slow look different.
2026-08-02 18:03:21 -04:00
Gmer4Lfe e0925b9d38 Make a failed AI send visible instead of hanging
GET reaches the endpoint and POST does not, with nothing in the request log,
no CSRF termination and no PHP error — so it fails in the browser before the
request goes out, and the only symptom was the pending indicator sitting
there. Reads the response as text before parsing so an empty body reports as
rejected-before-execution rather than a JSON error, wraps the synchronous
path, and surfaces script errors into the transcript.
2026-08-02 18:00:53 -04:00
Gmer4Lfe 563ea0eb78 Log AI requests, and stop hiding a failed job-file write
There is no nginx access log on this host and the CSRF prepend exits with an
empty body, so a request that never arrived and one that arrived and failed
were indistinguishable — the page just sat at "starting…". The job-file write
was also suppressed with @, which would produce exactly that hang: a token
returned for a job that can never report.
2026-08-02 17:57:22 -04:00
Gmer4Lfe 198532e280 Send all health checks as live state, not only the failing ones
Asked what was wrong, it answered "AI_ENABLED=false" — read from the conf
template, which records the shipped default, while the live value was true.
Passing checks are what tell the model the current value of a setting;
without them a documented default fills the silence. The prompt now states
explicitly that live state overrides any documented default.
2026-08-02 17:45:41 -04:00
Gmer4Lfe 69ffb5e1dc Fix two false alarms in the AI health checks
vv_meta uses columns k/v, so the embedder-match check read nothing and
reported "unrecorded" — a silent pass on the one mismatch that returns
confident nonsense instead of an error. And Ollama reports tags fully
qualified while conf carries the bare name, so an installed embedding model
was reported missing. A health panel that cries wolf is worse than none.
2026-08-02 17:42:35 -04:00
Gmer4Lfe 237156c46f Add config-vs-reality health checks, loaded models, and log evidence
The failures this subsystem actually has are configuration drift, so each
check names the setting to change rather than reporting that retrieval
failed. Notably it catches a conf model tag that is no longer installed, and
an index built by a different embedder than the one configured — vectors
from two models are not comparable, and that failure returns confident
nonsense rather than erroring. Diagnostic questions also get recent log
warnings, attached only then because they cost budget the passages need.
2026-08-02 17:40:43 -04:00
Gmer4Lfe 264ba57cbb Add the AI tab — grounded chat over the documentation index
Token and poll rather than SSE, so the api layer keeps one response
convention and reuses the pattern manual_sync already proved. History is
capped at three turns because the model is only fully offloaded at 16384
context and unbounded history would cross that silently. The tab exists
only while AI_ENABLED is true, rejected server-side and not merely hidden.
2026-08-02 17:32:17 -04:00
Gmer4Lfe e02dc1be15 Keep the monitor page header inside its PHP block
Its first line closed PHP before the header comment started, so the whole
block rendered as text at the top of the tab.
2026-08-02 10:37:34 -04:00
Gmer4Lfe c34224effa Carry the CSRF token on fetch requests and put mutations behind POST
Unraid already enforces CSRF on every POST via auto_prepend, but its
injector is jQuery-only — the plugin's native fetch() calls carried no
token and were being terminated before the endpoint ran, silently,
because csrf_terminate exits with an empty body that r.json() swallows.
2026-08-02 10:28:53 -04:00
Gmer4Lfe 987313e7dc Document the PHP api layer and fix what documenting it exposed
Writing down what each endpoint actually guarantees made the places it
didn't obvious — shell arguments reaching a crontab or a bash -c
unescaped, master.conf written without tmp+rename, and conf edits that
could be saved without ever being parsed.
2026-08-02 10:11:39 -04:00
Gmer4Lfe b00688bad1 Add RAG retrieval core, and correct six stale default values in headers
Chunker splits on the header sections the audit standardised, then sub-splits
named-paragraph safeguards — without that a specific question about one of
rsync.sh's fourteen safeguards scored below unrelated chunks, because the other
thirteen dominated the vector. Index is SQLite with raw float32 blobs and is
incremental on mtime; a no-op re-index takes 66ms.

The stale defaults were found by asking the system a question and checking its
answer: it correctly reported what mover_stop.sh's header claimed, and the
header was wrong.
2026-08-02 01:13:01 -04:00
Gmer4Lfe ccc6c742ee Add structured headers to the PHP pages layer
Documents each tab's purpose, what it renders, and which endpoints it polls.
Pages that start with markup get the header in a <?php ?> block so it never
reaches the browser.

Also corrects the layer diagram in README-unraid.md: eight of eleven pages hold
no PHP logic and poll api/ for everything — only auth, monitor and scheduler
require an include/ file directly.
2026-08-02 00:51:41 -04:00
Gmer4Lfe 43b5443b30 Add structured headers to the PHP include layer, fix monitor state paths
All 16 include/ files now carry PURPOSE / DESIGN PRINCIPLES / OPERATIONAL
SAFEGUARDS / EXPORTS / CONFIGURATION, keeping the first three section names
identical to the bash headers so retrieval can route across both languages.

monitor.php read six watchdog state files from /tmp while the watchdogs write
to STATE_DIR, so every strike set came back empty and the summary reported
healthy unconditionally. docs.php gained path containment before it is wired
to a page.
2026-08-02 00:38:22 -04:00
Gmer4Lfe 76c4ca5ccf Correct api_key_renew schedule in System_Essentials README
It is listed in WATCHDOG_ORCHESTRATOR_SCRIPTS as well as ARRAY_START_SCRIPTS,
so the claim that nothing in this folder runs on a timer was wrong.
2026-08-02 00:17:41 -04:00
Gmer4Lfe e2e76560a2 Fix Authelia config path and stale schedule comments in conf templates
The Authelia config default pointed at /mnt/user/appdata/Authelia, which does
not exist — the auth stack lives in the Critical-Data share so it gets synced.
Because conf_populate only fills empty fields, that wrong non-empty default
blocked auto-detection permanently and left the auth page's rules panel dead.

Also corrects three schedule comments that no longer matched varaverk.cron and
two references to scripts that have since been renamed or split.
2026-08-02 00:13:53 -04:00
Gmer4Lfe 1ed6b92118 Document the Unraid platform layer
The folder that translates the OS into Varaverk's vocabulary had no docs of its own, so the
adapter contract and the three-layer web UI were only discoverable by reading the code.
2026-08-01 23:20:52 -04:00
Gmer4Lfe c377ddfcca Complete the header template across Partnership, Kernel, Deployment and Plugin
Finishes the pass: every script now documents its safeguards, and the deliberate absences
in the sourced libraries are recorded so they are not "corrected" later.
2026-08-01 22:44:23 -04:00
Gmer4Lfe cdce877601 Add a second GPU card to the monitor page
The 3080 was invisible because the stats parser only ever described GPU 0.
2026-08-01 20:37:58 -04:00
Gmer4Lfe ce580d9935 Remove dead rc.emhttp mapping from adapter.sh
No such rc.d service exists on Unraid (emhttpd isn't managed via a
standalone rc.emhttp script) and nothing in the codebase calls
platform_restart_service/platform_stop_service with 'emhttp' — confirmed
during a post-7.3.2-upgrade audit of all platform-specific paths.
2026-08-01 11:49:05 -04:00
Gmer4Lfe 3ae24939cc Fix array-stop event hook folder name (disks_unmounting -> unmounting_disks)
Unraid's real event name is unmounting_disks, not disks_unmounting — the
mismatch meant emhttp_event never found this hook, so array_stopping.sh
never ran on real array stop.
2026-08-01 11:41:39 -04:00
Gmer4Lfe 7162f16c1a Correct docs that placed lidarr_missing_art in the 4-hour tier when it runs daily 2026-07-28 18:51:13 -04:00
Gmer4Lfe de12c1fada Widen unraid-api key lookup timeout to stop false "renewed" alarms
Measured live: the apikey --name lookup takes 2.2-2.7s baseline with
the system idle, against a 5s timeout that left almost no margin.
Load spikes (confirmed correlated with resource_watchdog pressure
events in the same log window) pushed it over 5s, and the script
couldn't distinguish "timed out" from "genuinely missing" — it fell
through to the create path and logged a false renewal every time,
even though the on-disk key file's timestamp never actually changed.
Bumped to 15s for real headroom.
2026-07-19 17:20:09 -04:00
Gmer4Lfe 7fa0adbda4 Fix external-link warning on the Partnership tab's web terminal link
Same root cause as the tab-navigation fix (a6fe820): the "Open Terminal"
link builds its href from window.location.hostname (the same server the
plugin is already running on) but Unraid's global external-link guard
still flags it, since it's a fully-qualified URL the guard hasn't seen
allowed before. Added class="localURL", the same escape hatch used for
the tab bar and dynamix's own pages.
2026-07-05 00:00:16 -04:00
Gmer4Lfe 084220692f Add unambiguous prefix-match fallback for NetBIOS-truncated hostnames
Unraid truncates the Server Name to 15 chars. Depending on which form
ends up in master.conf's HOST* value (the truncated OS hostname, or a
longer name matching what Tailscale independently registered for that
peer), either host-identity detection or Tailscale IP resolution could
fail — hit live on HOST2 in both directions this session.

- common.sh detect_hosts(): was case-sensitive exact match only, with no
  fallback and an exit 1 on failure — meaning every orchestrator/watchdog/
  rsync script would hard-fail on a truncated-hostname host, not just the
  web UI. Now case-insensitive, with a prefix-match fallback when the
  local hostname is exactly 15 chars.
- common.sh resolve_tailscale_ip(): already did a bare regex prefix match
  with zero ambiguity handling (pre-existing risk: e.g. server1/server10
  could collide). Replaced with an explicit unambiguous-only check.
- config.php vv_detect_host() / vv_resolve_tailscale_ip(): same treatment,
  kept as close a mirror of the bash logic as PHP allows.

All fallbacks require an EXACT prefix match (never fuzzy/percentage
similarity — considered and rejected, since names like server1/server2/
server3 would be dangerously similar under any generic similarity metric)
and require exactly one candidate to qualify; ambiguous matches are
treated as no match rather than guessed. Verified live against HOST1/
HOST2 in both master.conf configurations (short and long HOST2 value).
2026-07-04 23:49:44 -04:00
Gmer4Lfe abfbaa7f47 Fix host identity detection for NetBIOS-truncated hostnames
Unraid truncates the Server Name to 15 chars (NetBIOS limit). HOST2's
real hostname is "unRAID-Jayred36" but master.conf's HOST2 (matching
what Tailscale shows for this peer, since resolve_tailscale_ip() keys
off the same value) is the untruncated "unRAID-Jayred365" — confirmed
live, Tailscale's own Self.HostName on that machine is truncated too.

vv_detect_host() did a strict case-insensitive match against the bare
`hostname -s` output with no tolerance for this, so it always returned
'unknown' on HOST2. That silently broke the first-run wizard (Varaverk.page
explicitly excludes 'unknown' from the "needs setup" check) even though
host2.conf never existed, plus vv_partner_state() and vv_fallback_active()
in monitor.php which independently reimplemented the same hostname
comparison instead of calling vv_detect_host().

Fix: vv_detect_host() falls back to a prefix match when the local hostname
is exactly 15 chars; vv_partner_state()/vv_fallback_active() now call
vv_detect_host() instead of duplicating the comparison. Verified live on
HOST2 — vv_detect_host() now returns 'host2', partner state correctly
flags HOST2 as is_me, and the wizard-trigger condition now evaluates true.
2026-07-04 23:28:54 -04:00
Gmer4Lfe 3d7b15d6bb Fix vv_push_master_conf() — remote command was expanding locally, not on the remote host
The readiness probe wrapped the remote command in raw double quotes with
manually backslash-escaped inner quotes. shell_exec() runs its command
through an extra local `sh -c` layer beyond the ssh invocation itself, and
because the remote command was double-quoted (not single-quoted/opaque),
that extra local layer expanded the $(...)/${...} substitutions using
HOST1's own environment before ssh ever sent anything to the remote host.
Confirmed live: the exact same command run directly (one shell layer)
returned the correct remote SCRIPTS_DIR; run through an extra sh -c layer
(matching shell_exec's real behavior) it silently evaluated everything
against HOST1's local varaverk.cfg instead, producing an empty probe result
every time — so every push silently reported "plugin not installed" even
though HOST2 was fully installed and reachable.

Fix: build the remote command as a plain string and escapeshellarg() it as
a whole, same pattern vv_pt_ssh() already used safely elsewhere. Verified
live — probe now returns HOST2's real SCRIPTS_DIR and the master.conf push
lands with a matching checksum on both hosts.
2026-07-04 23:19:42 -04:00
Gmer4Lfe a6fe820a61 Fix external-link warning on tab navigation
Tab links use relative query-string hrefs (?tab=scheduler), which fail
every check in Unraid's global external-link click-guard (BodyInlineJS.php):
not a valid absolute URL, doesn't start with "/", doesn't match a
registered plugin page basename. Confirmed live — the guard's dom.hostname
ends up undefined for these, matching the reported "Always Allow undefined"
dialog text exactly.

Fix: add class="localURL", the same escape hatch dynamix's own pages
(ManagementAccess.page) use for this exact situation. Applied to the main
tab bar and the setup wizard's checklist action links (?tab=partnership).
2026-07-04 23:05:47 -04:00
Gmer4Lfe 7e4db7b504 Fix stale plugin docs and dead links
- unraid_api.php comment still told you to run Deployment/deploy.sh,
  deleted a while back
- VaraverkSettings.page linked to a CHANGELOG.md that doesn't exist
  anywhere in the repo
- Manual-Plugin.md / README-Plugin.md described manually heredoc-ing the
  .plg locally and a .txz-based install that isn't wired up — rewritten
  to describe the actual install flow (raw .plg URL via Plugins ->
  Install Plugin), with plugin_setup.sh's dev-symlink role called out
  separately from that install path
2026-07-04 23:00:57 -04:00
Gmer4Lfe f7fa75fdfb Fix dead/incorrect vars in Plugin/ found during full codebase audit
- WEBGUI_PHP_WAIT was referenced by webgui_watchdog.sh but never defined
  in master.conf, always silently falling back to a hardcoded default
- arrs.php/confform.php still pointed at Media/ for arr cleanup/discovery
  scripts moved to Arrs_Stack/ in b4bc926 — broke the Arrs page's stats
  and the per-script settings editor for those scripts
- docker_folders.php read directly from the optional folder.view3 plugin's
  file instead of Varaverk's own docker_folders.json (the primary store
  since the Docker tab got its own config) — left the Monitor page's
  Docker Folders widget empty on any host without folder.view3 installed
- vv_wd_remote_data() read remote watchdog state files from hardcoded
  /tmp or /boot/config paths instead of the remote's actual STATE_DIR
  (which resolves dynamically and can differ under flash mode) — remote
  node's Watchdog panel was always empty; same wrong path also used for
  two local reads (system_watchdog_oom.db, watchdog_appdata_growth.db)
- rsync.php referenced a {HOST}_MONTHLY_SYNC_SHARES conf var that never
  existed (monthly_maintenance.sh has no rsync section) — nulled out to
  match the existing pattern used for the fallback window
- vv_arr_node_names() did a pointless identity array_map
- vv_dk_webui() had its own duplicate local-IP resolution instead of
  using vv_local_ip(), despite config.php's comment claiming that exact
  duplication was already consolidated
2026-07-04 23:00:26 -04:00
Gmer4Lfe 6623d1e776 Fix dead/incorrect vars and consolidate duplicated logic into common.sh
Codebase-wide audit pass: fixed real bugs (SSH hangs missing BatchMode,
local-outside-function no-ops, variable name collisions, a truncated
ratio calc, wrong state-dir path, DARK vs NO_INTERNET drift, and more),
then pulled logic that was duplicated across multiple scripts — arr
cleanup safety gates, docker restart ordering, container maintenance
stop/restart, watchdog state-file helpers, partnership role resolution,
cert expiry checks, remote node discovery, and TMDB discovery scoring —
into common.sh so each now has a single implementation.
2026-07-03 23:52:33 -04:00
Gmer4Lfe 69189bbf18 Fix dead-variable and exit-code bugs found in codebase-wide audit
Same audit as the orchestrator standardization pass (2a062e5), extended to
every remaining script. Found the same class of bug independently recurring:
ramdisk_stop.sh checked $LOG (nothing assigns it, should be $ENABLE_LOGGING),
partnership_onboard.sh checked $LOG_MODE (same issue), emby_session_report.sh
checked $TRANSCODE_PCT which was never computed so the high-transcode alert
could never fire, and storage_migrate.sh never called detect_hosts() so
$MY_ID was empty, silently breaking the post-migration host*.conf update.
partnership_manager.sh used `local` at top-level script scope (invalid outside
a function) and had two master.conf path references missing "Configurations/".

Along the way: several scripts (share_setup.sh, conf_sync.sh,
downloaders_reset.sh, transcode_cleanup.sh, transcode_manager.sh,
remote_arr_cache_writer.sh, upgrade_webhook_handler.sh) had no explicit
trailing exit code, so they always reported success regardless of real
failures. play_state_sync.sh was missing the partnership gate its own header
documented, so remote play-state sync ran even with PARTNERSHIP_ENABLED=false;
it also always exited 0 on sync errors. arr_profile_enforcer.sh and
webhook_setup.sh hand-rolled their own flag parsing instead of common.sh's
parse_args, so --log silently did nothing on either.

system_watchdog.sh was itself an un-standardized mini-orchestrator — converted
to the shared run_orch_child()/JOB_PASS/JOB_FAIL pattern, added the missing
failure notification, and fixed dry-run to pass --dry-run down to children
instead of skipping them outright. Also fixed a stale webgui_watchdog.sh path
in master.conf.template that would break system_watchdog.sh on any fresh
install.

Closed a sibling-drift gap: radarr_cleanup.sh and sonarr_cleanup.sh were
missing lidarr_cleanup.sh's tracked-count percentage-drop safety gate and its
"not configured on this host, skip cleanly" guard — both now match Lidarr's
7-gate model.
2026-07-03 17:35:30 -04:00
Gmer4Lfe 6fd22ae4ee Move Custom Scripts out of the repo and add an Import Script picker
Custom Scripts (the Scheduler page's inline editor) used to save into the
git-tracked Custom/ folder, so anything saved there would end up on GitHub.
They now live in /boot/config/plugins/user.scripts/Varaverk/Scripts, same
folder family as Unraid's own User Scripts plugin. Import Script lets you
browse the whole server and move an existing script in instead of only
creating new ones inline — always a move, never a copy, so no stray
duplicate is left where it came from.
2026-07-03 10:57:35 -04:00
Gmer4Lfe 5d32f58f5d fix boot device detection failing on ZFS /boot
findmnt returns 'flash/boot' for a ZFS dataset, not a /dev/* path.
lsblk -no pkname then fails, leaving transport as 'unknown'. Resolve
ZFS pools to a backing device via zpool before checking transport.
2026-06-27 23:18:36 -04:00
Gmer4Lfe b314aa4aff fix monitor disk used space underreported for spun-down disks
Unraid API returns fsUsed=0 when a disk's filesystem is unmounted (spun
down). disks.ini keeps the last-known value in KB even after spindown —
use it as fallback when isSpinning=false and fsUsed=0. Also remove the
mounted-only guard in the ini fallback path (vv_disk_entry) for the same
reason. Stale comments in user_script_plug-in.sh and partnership_manager.sh
also cleaned up.
2026-06-27 23:08:51 -04:00
Gmer4Lfe b4bc9267e9 Move arr stack scripts from Media/ to Arrs_Stack/
Media/ now holds only media-level scripts (cleaner, permissions, play_state_sync).
All arr management scripts (cleanup, discovery, sync, webhooks, release fixer) live in Arrs_Stack/.
2026-06-27 18:39:33 -04:00
Gmer4Lfe c9a0ad187b Fix editor horizontal click offset — force inline fontFamily to override Unraid SPA clear-sans 2026-06-27 13:20:03 -04:00
Gmer4Lfe 0aa5851549 Fix editor line-height mismatch caused by Unraid SPA CSS override
Unraid 7's React CSS overrides line-height: 1.5 on textareas to normal.
vvRestoreEditorPrefs() only called vvFontSize() for non-default sizes, so
the inline style that overrides Unraid's CSS was never set for the default
12px case — leaving Firefox to render at ~14px while our code calculated
positions at 18px, putting the cursor 2-3 lines above where clicked.
Now always calls vvFontSize() so the inline lineHeight is always forced.
2026-06-27 13:05:31 -04:00
Gmer4Lfe ef7bc127b6 Fix platform_is_service_enabled to match Unraid's actual cfg format
Unraid quotes values (DOCKER_ENABLED="yes") and uses SERVICE="enable" for
libvirt — the old patterns matched nothing, so docker_watchdog always skipped.
2026-06-27 12:34:12 -04:00
Gmer4Lfe ccaf19cfe4 Fix editor click alignment in Firefox and enable arr cleanup scripts in daily maintenance 2026-06-26 22:35:47 -04:00
Gmer4Lfe f92ee4064b Add full banner headers to all scripts across the codebase
Every script now has the established header format: PURPOSE with ─────── separator,
OPERATIONAL MODEL, DESIGN PRINCIPLES, OPERATIONAL SAFEGUARDS, CONFIGURATION, and
RUNTIME MODES — structured with full ====== banner sections throughout.

Orchestrators converted from compact ── inline format to full banners. Stale
emby-fallback and dirty sync references removed from Plugin/user_script_plug-in.sh.
2026-06-26 18:50:05 -04:00
Gmer4Lfe 638aba20c0 Rename Lldap-Gmer4Lfe to Lldap and guard local containers in cleanup 2026-06-26 17:56:20 -04:00