feat(box): add invite code handler, Settings RPA, and agent onboarding pipeline
- Support invite code discovery in main chat and redemption in settings menu - Add Settings RPA primitives with Radix UI mouse dispatch and retry polling for async DOM - Attribute 'has_redeemed' binary from the Additional tokens ticker / entrypoint visibility - Unblock agent @646 by repairing warp-def/dev tunnels and redeeming REDCJ7 via dev (+1B tokens) - Implement 'box onboard' pipeline to provision infra, authenticate, and auto-redeem queued codes - Add 'box onboard feed-matrix' ranking all agents by work done over time, job count, and role - Register 'InputType.SALVAGE' in loop modulation (CRITICAL priority, 600s timeout, 3 nudges to opm) - Ingest recurring balance audits into canonical HEARTBEAT.md and TOOLS.md
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
"""Generic control primitives (ws-level, no tab knowledge).
|
||||
|
||||
Radio/switch list + set with verify-then-fallback: synthetic click,
|
||||
verify state flipped, else trusted real click, verify again. Tab
|
||||
modules build their flows on these; toggles.py adds addressing.
|
||||
"""
|
||||
import time
|
||||
|
||||
from approvals import cdp_evaluate
|
||||
from hatch_menu.mouse import real_click
|
||||
|
||||
JS_LIST_RADIOS = """(() => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return null;
|
||||
return Array.from(d.querySelectorAll('input[type="radio"]')).map(r => {
|
||||
let head = '', el = r.parentElement, depth = 0;
|
||||
while (el && el !== d && depth < 6) {
|
||||
const h = el.querySelector('h1,h2,h3,h4');
|
||||
if (h && (h.innerText || '').trim()) {
|
||||
head = h.innerText.trim().slice(0, 60);
|
||||
break;
|
||||
}
|
||||
el = el.parentElement;
|
||||
depth += 1;
|
||||
}
|
||||
const lab = r.closest('label');
|
||||
return {value: r.value, checked: !!r.checked, heading: head,
|
||||
aria: r.getAttribute('aria-label') || '',
|
||||
label: lab ? (lab.innerText || '').trim().slice(0, 80) : ''};
|
||||
});
|
||||
})()"""
|
||||
|
||||
JS_CLICK_RADIO = """((heading, value) => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return 'NO_DIALOG';
|
||||
const radios = Array.from(d.querySelectorAll('input[type="radio"]'));
|
||||
const headOf = (r) => {
|
||||
let el = r.parentElement, depth = 0;
|
||||
while (el && el !== d && depth < 6) {
|
||||
const h = el.querySelector('h1,h2,h3,h4');
|
||||
if (h && (h.innerText || '').trim())
|
||||
return h.innerText.trim().toLowerCase();
|
||||
el = el.parentElement;
|
||||
depth += 1;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const t = radios.find(r => headOf(r) === heading.toLowerCase()
|
||||
&& r.value === value);
|
||||
if (!t) return 'NO_MATCH';
|
||||
t.click();
|
||||
return 'CLICKED';
|
||||
})('%s', '%s')"""
|
||||
|
||||
JS_RADIO_RECT = """((heading, value) => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return null;
|
||||
const radios = Array.from(d.querySelectorAll('input[type="radio"]'));
|
||||
const headOf = (r) => {
|
||||
let el = r.parentElement, depth = 0;
|
||||
while (el && el !== d && depth < 6) {
|
||||
const h = el.querySelector('h1,h2,h3,h4');
|
||||
if (h && (h.innerText || '').trim())
|
||||
return h.innerText.trim().toLowerCase();
|
||||
el = el.parentElement;
|
||||
depth += 1;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const t = radios.find(r => headOf(r) === heading.toLowerCase()
|
||||
&& r.value === value);
|
||||
if (!t) return null;
|
||||
const r = t.getBoundingClientRect();
|
||||
return {x: r.x + r.width / 2, y: r.y + r.height / 2};
|
||||
})('%s', '%s')"""
|
||||
|
||||
JS_CLICK_RADIO_ARIA = """((name) => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return 'NO_DIALOG';
|
||||
const n = name.toLowerCase();
|
||||
const t = Array.from(d.querySelectorAll('input[type="radio"]'))
|
||||
.find(r => (r.getAttribute('aria-label') || '').toLowerCase() === n
|
||||
|| (r.value || '').toLowerCase() === n);
|
||||
if (!t) return 'NO_MATCH';
|
||||
t.click();
|
||||
return 'CLICKED';
|
||||
})('%s')"""
|
||||
|
||||
JS_RADIO_ARIA_RECT = """((name) => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return null;
|
||||
const n = name.toLowerCase();
|
||||
const t = Array.from(d.querySelectorAll('input[type="radio"]'))
|
||||
.find(r => (r.getAttribute('aria-label') || '').toLowerCase() === n
|
||||
|| (r.value || '').toLowerCase() === n);
|
||||
if (!t) return null;
|
||||
const r = t.getBoundingClientRect();
|
||||
return {x: r.x + r.width / 2, y: r.y + r.height / 2};
|
||||
})('%s')"""
|
||||
|
||||
JS_LIST_SWITCHES = """(() => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return null;
|
||||
return Array.from(d.querySelectorAll('[role="switch"]')).map(s => {
|
||||
let el = s.parentElement, label = '', depth = 0;
|
||||
while (el && el !== d && depth < 6) {
|
||||
const t = (el.innerText || '').trim().replace(/\\s+/g, ' ');
|
||||
if (t && t.length < 250) { label = t; break; }
|
||||
el = el.parentElement;
|
||||
depth += 1;
|
||||
}
|
||||
return {label: label.slice(0, 200),
|
||||
aria: s.getAttribute('aria-label') || '',
|
||||
checked: s.getAttribute('aria-checked') === 'true'};
|
||||
});
|
||||
})()"""
|
||||
|
||||
JS_CLICK_SWITCH = """((label) => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return 'NO_DIALOG';
|
||||
const rowOf = (s) => {
|
||||
let el = s.parentElement, depth = 0;
|
||||
while (el && el !== d && depth < 6) {
|
||||
const t = (el.innerText || '').trim();
|
||||
if (t && t.length < 250) return t.toLowerCase();
|
||||
el = el.parentElement;
|
||||
depth += 1;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const hits = Array.from(d.querySelectorAll('[role="switch"]'))
|
||||
.filter(s => rowOf(s).includes(label.toLowerCase())
|
||||
|| (s.getAttribute('aria-label') || '').toLowerCase()
|
||||
.includes(label.toLowerCase()));
|
||||
if (!hits.length) return 'NO_MATCH';
|
||||
if (hits.length > 1) return 'AMBIGUOUS';
|
||||
hits[0].click();
|
||||
return 'CLICKED';
|
||||
})('%s')"""
|
||||
|
||||
JS_SWITCH_RECT = """((label) => {
|
||||
const d = document.querySelector('[role="dialog"]');
|
||||
if (!d) return null;
|
||||
const rowOf = (s) => {
|
||||
let el = s.parentElement, depth = 0;
|
||||
while (el && el !== d && depth < 6) {
|
||||
const t = (el.innerText || '').trim();
|
||||
if (t && t.length < 250) return t.toLowerCase();
|
||||
el = el.parentElement;
|
||||
depth += 1;
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const hits = Array.from(d.querySelectorAll('[role="switch"]'))
|
||||
.filter(s => rowOf(s).includes(label.toLowerCase())
|
||||
|| (s.getAttribute('aria-label') || '').toLowerCase()
|
||||
.includes(label.toLowerCase()));
|
||||
if (hits.length !== 1) return null;
|
||||
const r = hits[0].getBoundingClientRect();
|
||||
return {x: r.x + r.width / 2, y: r.y + r.height / 2};
|
||||
})('%s')"""
|
||||
|
||||
|
||||
def _eval(ws, js, timeout=8.0):
|
||||
try:
|
||||
return cdp_evaluate(ws, js, timeout=timeout)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def list_radios(ws):
|
||||
"""All dialog radios with heading/label/value/checked (or [])."""
|
||||
return _eval(ws, JS_LIST_RADIOS) or []
|
||||
|
||||
|
||||
def list_switches(ws):
|
||||
"""All dialog switches with row label + checked (or [])."""
|
||||
return _eval(ws, JS_LIST_SWITCHES) or []
|
||||
|
||||
|
||||
def radio_state(ws, heading, value):
|
||||
"""Checked state of one heading-grouped radio, None if absent."""
|
||||
for r in list_radios(ws):
|
||||
if (r.get("heading") or "").lower() == heading.lower() \
|
||||
and r.get("value") == value:
|
||||
return bool(r.get("checked"))
|
||||
return None
|
||||
|
||||
|
||||
def set_radio_by_heading(ws, heading, value):
|
||||
"""Set a heading-grouped radio; verify, else trusted click, verify."""
|
||||
if _eval(ws, JS_CLICK_RADIO % (heading, value)) == "CLICKED" \
|
||||
and radio_state(ws, heading, value) is True:
|
||||
return True
|
||||
rect = _eval(ws, JS_RADIO_RECT % (heading, value))
|
||||
if not rect or "x" not in rect:
|
||||
return False
|
||||
try:
|
||||
real_click(ws, rect["x"], rect["y"])
|
||||
except Exception:
|
||||
return False
|
||||
time.sleep(0.6)
|
||||
return radio_state(ws, heading, value) is True
|
||||
|
||||
|
||||
def radio_aria_state(ws, name):
|
||||
"""Checked state of one aria-labeled radio, None if absent."""
|
||||
n = name.lower()
|
||||
for r in list_radios(ws):
|
||||
if (r.get("aria") or "").lower() == n \
|
||||
or (r.get("value") or "").lower() == n:
|
||||
return bool(r.get("checked"))
|
||||
return None
|
||||
|
||||
|
||||
def set_radio_by_aria(ws, name):
|
||||
"""Set an aria-labeled radio; verify, else trusted click, verify."""
|
||||
if _eval(ws, JS_CLICK_RADIO_ARIA % name) == "CLICKED" \
|
||||
and radio_aria_state(ws, name) is True:
|
||||
return True
|
||||
rect = _eval(ws, JS_RADIO_ARIA_RECT % name)
|
||||
if not rect or "x" not in rect:
|
||||
return False
|
||||
try:
|
||||
real_click(ws, rect["x"], rect["y"])
|
||||
except Exception:
|
||||
return False
|
||||
time.sleep(0.6)
|
||||
return radio_aria_state(ws, name) is True
|
||||
|
||||
|
||||
def switch_state(ws, label):
|
||||
"""Checked state of one label-matched switch, None if not unique."""
|
||||
matches = [s for s in list_switches(ws)
|
||||
if label.lower() in (s.get("label") or "").lower()
|
||||
or label.lower() in (s.get("aria") or "").lower()]
|
||||
if len(matches) != 1:
|
||||
return None
|
||||
return bool(matches[0].get("checked"))
|
||||
|
||||
|
||||
def set_switch(ws, label, on):
|
||||
"""Set a switch by row-label/aria match; no-op when already there."""
|
||||
state = switch_state(ws, label)
|
||||
if state is None:
|
||||
return False
|
||||
if state == bool(on):
|
||||
return True
|
||||
if _eval(ws, JS_CLICK_SWITCH % label) == "CLICKED" \
|
||||
and switch_state(ws, label) is bool(on):
|
||||
return True
|
||||
rect = _eval(ws, JS_SWITCH_RECT % label)
|
||||
if not rect or "x" not in rect:
|
||||
return False
|
||||
try:
|
||||
real_click(ws, rect["x"], rect["y"])
|
||||
except Exception:
|
||||
return False
|
||||
time.sleep(0.6)
|
||||
return switch_state(ws, label) is bool(on)
|
||||
Reference in New Issue
Block a user