From 18a0d6fe29b76d709cdc72ea1ef46a881dfb9cb4 Mon Sep 17 00:00:00 2001 From: Joshua Date: Wed, 18 Feb 2026 20:54:39 -0800 Subject: [PATCH] Add visible human/auto mode controls to launcher --- README.md | 1 + app/app.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ app/index.html | 6 ++++++ app/style.css | 6 ++++++ 4 files changed, 62 insertions(+) diff --git a/README.md b/README.md index d456cbf..8166e19 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Top-level control surface: 5. Wallet/session/membership/designation/last-sync overview cards 6. Pull-first updates feed + support ticket action 7. Identity assurance visibility (`none` / `crypto_direct_unattested` / `sponsored_unattested` / `onramp_attested`) +8. Explicit operator-visible mode toggles (`Human mode` / `Auto mode`) synced to governance `operation_mode` Advanced integration controls (collapsible): diff --git a/app/app.js b/app/app.js index af50b10..2fc745e 100644 --- a/app/app.js +++ b/app/app.js @@ -217,6 +217,7 @@ function refreshOverview(statusPayload) { const currentWallet = wallet(); setSummary("summaryWallet", currentWallet || "not connected"); setSummary("summarySession", sessionSummary()); + refreshModeUI(); if (statusPayload && typeof statusPayload === "object") { setSummary("summaryMembership", statusPayload.status || "unknown"); setSummary("summaryDesignation", statusPayload.designation_code || "-"); @@ -316,6 +317,34 @@ function operationMode() { return $("operationMode").value.trim() || "human_manual"; } +function normalizeOperationMode(value) { + return String(value || "").trim().toLowerCase() === "worker_auto" ? "worker_auto" : "human_manual"; +} + +function refreshModeUI() { + const mode = normalizeOperationMode(operationMode()); + setSummary("summaryMode", mode); + const humanBtn = $("btnModeHuman"); + const autoBtn = $("btnModeAuto"); + if (humanBtn) { + humanBtn.classList.toggle("mode-active", mode === "human_manual"); + } + if (autoBtn) { + autoBtn.classList.toggle("mode-active", mode === "worker_auto"); + } +} + +function setOperationMode(mode, source = "ui") { + const normalized = normalizeOperationMode(mode); + const select = $("operationMode"); + if (select) { + select.value = normalized; + } + refreshModeUI(); + logLine("operation mode set", { mode: normalized, source }); + return normalized; +} + function renderEvents(events) { const list = $("eventList"); list.innerHTML = ""; @@ -1062,6 +1091,16 @@ async function onOfflineRenew() { logLine("offline renew", out); } +async function onModeHuman() { + setOperationMode("human_manual", "quick_toggle"); + setFlowStatus("mode set: human_manual"); +} + +async function onModeAuto() { + setOperationMode("worker_auto", "quick_toggle"); + setFlowStatus("mode set: worker_auto"); +} + function bind(id, handler) { const el = $(id); if (!el) { @@ -1080,6 +1119,8 @@ bind("btnQuickConnect", onQuickConnect); bind("btnQuickActivate", onQuickActivate); bind("btnQuickRefresh", onQuickRefresh); bind("btnQuickInstallStatus", onQuickInstallStatus); +bind("btnModeHuman", onModeHuman); +bind("btnModeAuto", onModeAuto); bind("btnConnectWallet", onConnectWallet); bind("btnRunMembershipFlow", onRunMembershipFlow); bind("btnIntent", onIntent); @@ -1108,6 +1149,14 @@ bind("btnCheckoutConfirm", onCheckoutConfirm); bind("btnRunCheckoutFlow", onRunCheckoutFlow); bind("btnListEntitlements", onListEntitlements); +const operationModeSelect = $("operationMode"); +if (operationModeSelect) { + operationModeSelect.addEventListener("change", () => { + setOperationMode(operationModeSelect.value, "advanced_select"); + }); +} + +refreshModeUI(); logLine("launcher shell ready", { api_base: baseURL(), chain_id: chainID(), diff --git a/app/index.html b/app/index.html index b0ac1a3..f5a1474 100644 --- a/app/index.html +++ b/app/index.html @@ -20,6 +20,8 @@ + +

ready

@@ -35,6 +37,10 @@

Membership

unknown

+
+

Mode

+

human_manual

+

Designation

-

diff --git a/app/style.css b/app/style.css index dd58061..6b4ed5f 100644 --- a/app/style.css +++ b/app/style.css @@ -149,6 +149,12 @@ button:hover { filter: brightness(1.08); } +button.mode-active { + border-color: #4ed380; + background: #1f4a33; + color: #e0ffe9; +} + button:active { transform: translateY(1px); }