diff --git a/static/adwright.js b/static/adwright.js
index 61c7bbb..c724132 100644
--- a/static/adwright.js
+++ b/static/adwright.js
@@ -44,7 +44,11 @@
// ── Active-profile detection (PRD §3 visibility gating) ────────────────
// hermes-webui exposes S.activeProfile (see static/ui.js line 1). We probe
// it defensively — the panel always renders, but enables only for CMO.
+ // Cache from a real /api/profile/active fetch since window.S may not be
+ // populated yet on /session/* pages before boot.js runs.
+ NS.state._fetchedProfile = null;
function _activeProfile() {
+ if (NS.state._fetchedProfile) return NS.state._fetchedProfile;
try {
return (window.S && window.S.activeProfile) || "default";
} catch (_) { return "default"; }
@@ -90,6 +94,24 @@
_wireConnections(panel);
_refreshDisabledState();
_renderTab(NS.state.activeTab);
+ // Authoritative profile fetch (window.S may be empty on /session/* paths
+ // before boot.js finishes). Update banner state once it arrives.
+ _fetchActiveProfile().then((name) => {
+ if (name) {
+ NS.state._fetchedProfile = name;
+ _refreshDisabledState();
+ }
+ });
+ // Re-poll every 5s so a profile switch from the upstream Profiles panel
+ // also lifts the banner without requiring a hard reload.
+ setInterval(() => {
+ _fetchActiveProfile().then((name) => {
+ if (name && name !== NS.state._fetchedProfile) {
+ NS.state._fetchedProfile = name;
+ _refreshDisabledState();
+ }
+ });
+ }, 5000);
NS.state.mounted = true;
return true;
@@ -116,7 +138,8 @@
'' +
'
' +
'
' +
- 'Adwright is read-only — switch to the cmo profile to run actions.' +
+ 'Adwright needs the cmo-planb profile active. ' +
+ '' +
'
' +
tabs +
'
' +
@@ -136,6 +159,38 @@
if (bteBtn) bteBtn.addEventListener("click", () => {
if (window.SvrntyBTE && window.SvrntyBTE.open) window.SvrntyBTE.open();
});
+ // One-click profile switch to cmo-planb.
+ const switchBtn = panel.querySelector("#svrntyAwSwitchCmo");
+ if (switchBtn) switchBtn.addEventListener("click", async () => {
+ switchBtn.disabled = true;
+ switchBtn.textContent = "Switching…";
+ try {
+ const res = await fetch("/api/profile/switch", {
+ method: "POST",
+ credentials: "same-origin",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ name: "cmo-planb" }),
+ });
+ if (!res.ok) throw new Error("HTTP " + res.status);
+ // Reload to pick up new profile state across the whole webui.
+ location.reload();
+ } catch (e) {
+ switchBtn.disabled = false;
+ switchBtn.textContent = "Switch failed — retry";
+ console.error("[svrnty-aw] profile switch failed", e);
+ }
+ });
+ }
+
+ // Pull live active profile from server (don't rely on window.S which may
+ // not be populated yet on /session/* pages before boot.js runs).
+ async function _fetchActiveProfile() {
+ try {
+ const r = await fetch("/api/profile/active", { credentials: "same-origin" });
+ if (!r.ok) return null;
+ const d = await r.json();
+ return (d && (d.name || d.profile)) || null;
+ } catch (_) { return null; }
}
function _activateTab(id) {