// Automations live inside the firm whose site they drive. The dashboard renders // a tab per firm and a button per automation within it; the Python runner claims // a queued run, resolves each selector through the extension, and drives the real // mouse. // // Adding a button means adding an entry to that firm's `automations` — nothing in // the page, the API or the runner changes. // // Adding a NEW FIRM also needs its host added to extension/manifest.json // host_permissions, and the extension reloaded. Without that the extension is not // permitted to read that site and every step fails to locate. export type AutomationStep = // `skipIfNotFound` skips the step when the element isn't on the page, instead of // failing the run — for things that only sometimes appear, like a cookie // banner or a confirmation modal. Only absence is tolerated: an element that // is present but covered or off-screen still fails. // `frame` targets an element inside a cross-origin