diff --git a/samy.js b/samy.js
new file mode 100644
index 0000000..461b473
--- /dev/null
+++ b/samy.js
@@ -0,0 +1,408 @@
+// Use globals provided by the PowerShell-generated HTML bridge
+const tasks = (window.SAMY_TASKS || []);
+const defaultPage = (window.SAMY_DEFAULT_PAGE || "onboard");
+
+let completedTasks = 0;
+let totalTasks = 0;
+
+// Progress / title handling
+function setTotalTaskCount(count) {
+ totalTasks = count;
+ completedTasks = 0;
+ updateTitle();
+}
+
+function logProgress(label, isSuccess) {
+ const statusBox = document.getElementById("status-box");
+ completedTasks++;
+ updateTitle();
+
+ const msg = isSuccess
+ ? ` ${completedTasks}/${totalTasks} done: ${label}`
+ : ` ${completedTasks}/${totalTasks} failed: ${label}`;
+
+ const div = document.createElement("div");
+ div.style.color = isSuccess ? "lime" : "red";
+ div.textContent = msg;
+ statusBox?.appendChild(div);
+
+ if (completedTasks === totalTasks) {
+ const finalMsg = document.createElement("div");
+ finalMsg.style.marginTop = "10px";
+ finalMsg.innerHTML = ` All tasks complete (${completedTasks}/${totalTasks})`;
+ statusBox?.appendChild(finalMsg);
+
+ document.title = ` ScriptMonkey - Complete (${completedTasks}/${totalTasks})`;
+
+ const sound = new Audio(
+ "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAESsAACJWAAACABAAZGF0YQAAAAA="
+ );
+ sound.play().catch(() => {});
+ flashTitle(document.title);
+ }
+}
+
+function updateTitle() {
+ document.title = `ScriptMonkey - ${completedTasks}/${totalTasks} Done`;
+}
+
+function flashTitle(finalTitle) {
+ let flashes = 0;
+ const interval = setInterval(() => {
+ document.title = document.title === "" ? finalTitle : "";
+ flashes++;
+ if (flashes >= 10) {
+ clearInterval(interval);
+ document.title = finalTitle;
+ }
+ }, 800);
+}
+
+// =======================================================================
+// Tab Navigation
+// =======================================================================
+document.addEventListener("DOMContentLoaded", () => {
+ const tabButtons = document.querySelectorAll(".tab-button");
+ const tabContents = document.querySelectorAll(".tab-content");
+
+ if (!tabButtons?.length || !tabContents?.length) {
+ console.error("ScriptMonkey: no tab buttons or tab contents found.");
+ return;
+ }
+
+ tabButtons.forEach((btn) => {
+ btn.addEventListener("click", () => {
+ tabButtons.forEach((b) => b.classList.remove("active"));
+ tabContents.forEach((c) => c.classList.remove("active"));
+
+ btn.classList.add("active");
+ const targetId = btn.dataset.tab;
+ const target = document.getElementById(targetId);
+ if (target) target.classList.add("active");
+ });
+ });
+
+ // Default tab from PS (onboard/offboard/tweaks/SVSApps)
+ const defaultTabId = `${defaultPage}Tab`;
+ const defaultBtn = document.querySelector(`.tab-button[data-tab='${defaultTabId}']`);
+ const defaultTab = document.getElementById(defaultTabId);
+ if (defaultBtn) defaultBtn.classList.add("active");
+ if (defaultTab) defaultTab.classList.add("active");
+});
+
+// =======================================================================
+// Onboarding: Select-all left/right columns
+// =======================================================================
+function toggleColumn(col) {
+ const master = document.getElementById(
+ `selectAll${col[0].toUpperCase() + col.slice(1)}Checkbox`
+ );
+ const children = document.querySelectorAll(
+ `#onboardTab input[type=checkbox][data-column=${col}]`
+ );
+
+ children.forEach((cb) => {
+ cb.checked = master.checked;
+ });
+
+ setTimeout(() => {
+ children.forEach((cb) => {
+ cb.dispatchEvent(new Event("change"));
+ });
+ }, 0);
+}
+
+function updateSelectAll(col) {
+ const master = document.getElementById(
+ `selectAll${col[0].toUpperCase() + col.slice(1)}Checkbox`
+ );
+ const children = document.querySelectorAll(
+ `#onboardTab input[type=checkbox][data-column=${col}]`
+ );
+
+ master.checked = Array.from(children).every((cb) => cb.checked);
+}
+
+document.addEventListener("DOMContentLoaded", () => {
+ ["left", "right"].forEach((col) => {
+ document
+ .querySelectorAll(`#onboardTab input[type=checkbox][data-column=${col}]`)
+ .forEach((cb) =>
+ cb.addEventListener("change", () => updateSelectAll(col))
+ );
+ });
+});
+
+// =======================================================================
+// Off-boarding Select All
+// =======================================================================
+function toggleOffboardAll() {
+ const master = document.getElementById("offboardSelectAll");
+ const children = document.querySelectorAll(
+ "#offboardTab input[type=checkbox]:not(#offboardSelectAll)"
+ );
+
+ children.forEach((cb) => {
+ cb.checked = master.checked;
+ });
+}
+
+function updateOffboardSelectAll() {
+ const master = document.getElementById("offboardSelectAll");
+ if (!master) return;
+
+ const children = document.querySelectorAll(
+ "#offboardTab input[type=checkbox]:not(#offboardSelectAll)"
+ );
+ if (!children.length) {
+ master.checked = false;
+ return;
+ }
+
+ master.checked = Array.from(children).every((cb) => cb.checked);
+}
+
+document.addEventListener("DOMContentLoaded", () => {
+ const offChildren = document.querySelectorAll(
+ "#offboardTab input[type=checkbox]:not(#offboardSelectAll)"
+ );
+
+ if (!offChildren?.length) return;
+
+ offChildren.forEach((cb) =>
+ cb.addEventListener("change", updateOffboardSelectAll)
+ );
+ updateOffboardSelectAll();
+});
+
+// =======================================================================
+// DattoRMM options + Enter key handling
+// =======================================================================
+function toggleDattoRMMOptions() {
+ const master = document.getElementById("installDattoRMM");
+ const container = document.getElementById("installDattoRMMOptionsContainer");
+ if (!container) return;
+ const checked = master?.checked;
+ container.style.display = checked ? "block" : "none";
+ container
+ .querySelectorAll('input[type="checkbox"]')
+ .forEach((cb) => (cb.checked = checked));
+}
+
+document.addEventListener("DOMContentLoaded", () => {
+ const master = document.getElementById("installDattoRMM");
+ if (master) {
+ master.addEventListener("change", toggleDattoRMMOptions);
+ }
+
+ const passwordField = document.getElementById("Password");
+ const goButton = document.querySelector("button[onclick='fetchSites()']");
+
+ if (passwordField && goButton) {
+ passwordField.addEventListener("keydown", (e) => {
+ if (e.key === "Enter") {
+ goButton.click();
+ }
+ });
+ }
+
+ const siteDropdown = document.getElementById("dattoDropdown");
+ const runButton = document.querySelector(".run-button");
+
+ if (siteDropdown && runButton) {
+ siteDropdown.addEventListener("keydown", (e) => {
+ if (e.key === "Enter" && siteDropdown.value) {
+ runButton.click();
+ }
+ });
+ }
+});
+
+// =======================================================================
+// Fetch Sites handler (calls /getpw)
+// =======================================================================
+async function fetchSites() {
+ const pwdInput = document.getElementById("Password");
+ const pwd = pwdInput?.value;
+ if (!pwd) {
+ alert("Please enter the password.");
+ return;
+ }
+
+ const dropdown = document.getElementById("dattoDropdown");
+ dropdown.innerHTML = '';
+
+ try {
+ const resp = await fetch("/getpw", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ password: pwd }),
+ });
+
+ if (!resp.ok) throw "HTTP " + resp.status;
+
+ const sites = await resp.json();
+ dropdown.innerHTML = "";
+
+ sites.forEach((site) => {
+ const option = document.createElement("option");
+ option.value = site.UID;
+ option.textContent = site.Name;
+ dropdown.appendChild(option);
+ });
+
+ document.getElementById("dattoRmmContainer").style.display = "block";
+ } catch (e) {
+ console.error(e);
+ dropdown.innerHTML =
+ '';
+ alert("Failed to fetch sites. Check password and try again.");
+ }
+}
+
+// =======================================================================
+// Run Selected (main trigger)
+// =======================================================================
+async function triggerInstall() {
+ const runBtn = document.querySelector(".run-button");
+ if (!runBtn) return;
+
+ runBtn.disabled = true;
+
+ const statusBox = document.getElementById("status-box");
+ if (statusBox) statusBox.innerHTML = "";
+
+ try {
+ const checkedTasks = tasks.filter((t) => {
+ const cb = document.getElementById(t.id);
+ return cb && cb.checked;
+ });
+ setTotalTaskCount(checkedTasks.length);
+
+ // 1. DattoRMM first
+ const dattoCB = document.getElementById("installDattoRMM");
+ if (dattoCB && dattoCB.checked) {
+ try {
+ const sub = Array.from(
+ document.querySelectorAll(".sub-option-installDattoRMM:checked")
+ ).map((x) => x.value);
+ const dropdown = document.getElementById("dattoDropdown");
+ const uid = dropdown?.value;
+ const name = dropdown?.selectedOptions?.[0]?.text || "Datto";
+
+ await fetch("/installDattoRMM", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ checkedValues: sub, UID: uid, Name: name }),
+ });
+ logProgress("Install DattoRMM", true);
+ } catch (e) {
+ logProgress("Install DattoRMM", false);
+ console.error(e);
+ }
+ }
+
+ // 2. SVSMSP module second
+ const svsCB = document.getElementById("installSVSMSPModule");
+ if (svsCB && svsCB.checked) {
+ try {
+ await fetch("/installSVSMSPModule", { method: "GET" });
+ logProgress("Install SVSMSP Module", true);
+ } catch (e) {
+ logProgress("Install SVSMSP Module", false);
+ console.error(e);
+ }
+ }
+
+ // 3. Remaining tasks
+ for (const t of tasks) {
+ if (["installDattoRMM", "installSVSMSPModule"].includes(t.id)) continue;
+
+ const cb = document.getElementById(t.id);
+ if (!cb || !cb.checked) continue;
+
+ try {
+ await fetch(t.handler, { method: "GET" });
+ logProgress(t.label || t.id, true);
+ } catch (e) {
+ logProgress(t.label || t.id, false);
+ console.error(`Error running ${t.id}:`, e);
+ }
+ }
+ } catch (e) {
+ console.error("triggerInstall fatal error:", e);
+ } finally {
+ runBtn.disabled = false;
+ }
+}
+
+// =======================================================================
+// Shutdown handler (Exit button & window close)
+// =======================================================================
+function endSession() {
+ fetch("/quit", { method: "GET" }).finally(() => window.close());
+}
+
+// Sub-options auto-toggle, tagline rotation, and beforeunload hook
+document.addEventListener("DOMContentLoaded", () => {
+ // Sub-option containers
+ const tasksWithSubOptions = document.querySelectorAll(
+ '[id$="OptionsContainer"]'
+ );
+
+ tasksWithSubOptions.forEach((container) => {
+ const taskId = container.id.replace("OptionsContainer", "");
+ const masterCheckbox = document.getElementById(taskId);
+ if (!masterCheckbox) return;
+
+ function updateVisibility() {
+ const checked = masterCheckbox.checked;
+ container.style.display = checked ? "block" : "none";
+ container
+ .querySelectorAll('input[type="checkbox"]')
+ .forEach((cb) => (cb.checked = checked));
+
+ if (taskId === "installDattoRMM") {
+ const pwdBox = document.getElementById("PasswordContainer");
+ const rmmBox = document.getElementById("dattoRmmContainer");
+ if (pwdBox) pwdBox.style.display = checked ? "block" : "none";
+ if (rmmBox) rmmBox.style.display = checked ? "block" : "none";
+ }
+ }
+
+ masterCheckbox.addEventListener("change", updateVisibility);
+ updateVisibility();
+ });
+
+ // Tagline rotation
+ const taglines = [
+ "Fast deployments, no monkey business.",
+ "Bananas for better builds.",
+ "Deploy without flinging code.",
+ "Tame your stack. Unleash the monkey.",
+ "Monkey see, monkey deploy.",
+ "Deploy smarter -- with a monkey on your team.",
+ "Don't pass the monkey -- let it deploy.",
+ "No more monkeying around. Stack handled.",
+ "Own your stack. But let the monkey do the work.",
+ "Why throw code when the monkey's got it?",
+ "Deployments so easy, a monkey could do it. Ours does.",
+ "Monkey in the stack, not on your back.",
+ ];
+
+ const el = document.getElementById("tagline");
+ if (el) {
+ let idx = Math.floor(Math.random() * taglines.length);
+ el.textContent = taglines[idx];
+
+ setInterval(() => {
+ idx = (idx + 1) % taglines.length;
+ el.textContent = taglines[idx];
+ }, 10_000);
+ }
+});
+
+// notify server on window close
+window.addEventListener("beforeunload", () => {
+ fetch("/quit", { method: "GET", keepalive: true });
+});