From b00ee3008ddf38a1473b760b92b6c0fa768d80d8 Mon Sep 17 00:00:00 2001 From: Timothy Wayne Gregg Date: Mon, 19 Oct 2026 20:16:37 -0400 Subject: [PATCH] Explain the Activity setup notice and open the dashboard through Discord The Agent setup notice read like an error in every Discord Activity, because Discord's iframe never delegates the WebMCP tools permission. Say plainly that the planner below is the way to set up, and that agents need the browser dashboard. In the Activity, open the dashboard with openExternalLink (a plain target=_blank link does nothing there) and preselect the server. Co-Authored-By: Claude Opus 5.5 --- SHA256SUMS | 6 +++--- activity/src/main.ts | 3 ++- activity/src/onboarding.ts | 8 +++++--- scripts/onboarding-browser.py | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/SHA256SUMS b/SHA256SUMS index 7706121..11ba42f 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -21,8 +21,8 @@ ecd8294e24a1cd55cc1aa0b3c5d6cde68c956524cfb1d7707766b4f6287b5e3e activity/index 6c8b74d4d57bff38a393ab038418c8f410627dc66721bc416905289110f151ac activity/legal/privacy.html 297c926eb462285e52e196af2d23f2ac70cb280324bfd30aeff74836e02f159c activity/legal/terms.html ac5a46a57d2c4ba90ed861c840b7240c9367359bbb21c8167890a7a61211f783 activity/src/connection.ts -df6b8511d942c38a498fc3a74b404d92556736be37e519021bb613871c1c2984 activity/src/main.ts -8010da4164c86394863cb645eaf4567f066822114c40edf1d2762c1a5da3806a activity/src/onboarding.ts +2e6808727e3230b32d41b1c37a3c50c1029d8a48edda6d43eddd20ad4cebeed1 activity/src/main.ts +4ebc81c7b8afd960ee6249ee60086606082e88240c1d7fbc05c30e125b75d307 activity/src/onboarding.ts 66988416b7ab216ad9d3947ed528bfe9f2e45f74943971d506a686ff0b044508 activity/style.css 3fb468ea85cd082f252d85b34bb3da8b62a10ae4aa984b48ef93f0ecacc7017f data/scams/README.md 2b1733d3ba70cd80dc5e91720f0deacf0fced2145e9af5d0e5f4029c50001694 data/scams/SHA256SUMS @@ -360,7 +360,7 @@ c29b2921019f406d52ea97f99b24f5fb1b3d7d188bd5be54bf40a2b3ca60de58 scripts/kaggle d3454c1ef2f5bd1b871358485104dfb5b849c53f13d8b9b892cc0e2cdfbe2570 scripts/migration-receipt.mjs fbe41f990d155b158571ba0b8db5c5138f5cbbeb20ce6b84059aecb7d9f9b00a scripts/migration-receipt.test.mjs b2d7f56ef5420637227298102779b2b2e07d3c56b7dbbdc32ff1bb1c99107acb scripts/onboarding-browser-server.mjs -34c33ad5a8f9ecf69cb74c5b2971faaa18c50764146f658216a7eef5d10a8a6d scripts/onboarding-browser.py +5699a82961b50dfbb0eabc02833b378a7447160c753af8e306aa749bca212d1d scripts/onboarding-browser.py 2c2432b67c1739d50bd339ba9d6504ace9a9f2bf20afa8deef67daef7110ed50 scripts/onboarding-live.mjs a9ba710e3953aebf3557647bda6447a807dca2e023f3dd588955ae6faf65edea scripts/pack-browser-workflow.js 071b1afae64f798864ce9cefcb95d4642a2b17e97d3f06efb1df235653a9c32a scripts/pack-browser.py diff --git a/activity/src/main.ts b/activity/src/main.ts index 6240c22..6757580 100644 --- a/activity/src/main.ts +++ b/activity/src/main.ts @@ -175,6 +175,7 @@ let session = '', guild = '', authority: Authority | null = null, sdk: SDK | nul let status: HTMLDivElement; let browserDashboardUrl='/setup'; let agentSetup: ReturnType | undefined; +function dashboardFor(guildId: string) { const url=new URL(browserDashboardUrl,location.href); if(guildId)url.searchParams.set('guild',guildId); return url.href; } function clearAgentSetup() { agentSetup?.stop(); agentSetup = undefined; } function initializeAgentSetup() { clearAgentSetup(); @@ -186,7 +187,7 @@ function initializeAgentSetup() { if(args[0]==='onboarding/apply'&&result.receipt) settings={value:result.after,revision:result.receipt.settingsRevision}; if(args[0]==='pause'){settings=await api('settings');void render().catch(fail);} return result; - },()=>{page='Agent setup';void render().catch(fail);},browserDashboardUrl); + },()=>{page='Agent setup';void render().catch(fail);},dashboardFor(expectedGuild),sdk?url=>sdk!.commands.openExternalLink({url}):undefined); } window.addEventListener('pagehide',clearAgentSetup); const can = (cap: Capability) => authority?.capabilities.includes(cap) ?? false; diff --git a/activity/src/onboarding.ts b/activity/src/onboarding.ts index 2ccd003..ff78457 100644 --- a/activity/src/onboarding.ts +++ b/activity/src/onboarding.ts @@ -42,7 +42,8 @@ export async function registerTools(context: ModelContext | undefined, api: Api, return true; } function el(tag: string, text = '', cls = '') { const e=document.createElement(tag); e.textContent=text; e.className=cls; return e; } -export function setupPanel(api: Api, onPlan?: ()=>void, dashboardUrl = '/setup') { +// Inside Discord, openExternal opens the dashboard through the SDK; a plain link does nothing in the Activity iframe. +export function setupPanel(api: Api, onPlan?: ()=>void, dashboardUrl = '/setup', openExternal?: (url: string)=>unknown) { let target: HTMLElement | undefined, plan: any, supported = false, active = true; const controller = new AbortController(); const stop = () => { active=false; controller.abort(); clearTimeout(expiry); clearInterval(poll); supported=false; if(target)target.prepend(el('p','Session ended or authority changed. Reconnect to continue.','notice error')); }; @@ -54,8 +55,9 @@ export function setupPanel(api: Api, onPlan?: ()=>void, dashboardUrl = '/setup') const pretty=(v: unknown)=>JSON.stringify(v,null,2); function draw() { if(!target)return;target.replaceChildren(); - target.append(el('p',supported?'Browser tools registered. Discovery by your agent still depends on browser support and iframe policy.':'WebMCP unavailable or blocked. Use the manual planner below; in Discord, try the standalone dashboard with its own login.','notice')); - const external=el('a','Open browser dashboard','button quiet') as HTMLAnchorElement;external.href=dashboardUrl;external.target='_blank';external.rel='noopener noreferrer';target.append(external); + target.append(el('p',supported?'Browser tools registered. Discovery by your agent still depends on browser support and iframe policy.':openExternal?'Set up TypeCheck with the planner below. To let an AI browser agent help instead, open the browser dashboard and sign in there; Discord does not let agents use tools inside Activities.':'Set up TypeCheck with the planner below. AI browser agent tools (WebMCP) are not available in this browser.','notice')); + if(openExternal)target.append(actions('Open browser dashboard',async()=>{await openExternal(dashboardUrl);})); + else{const external=el('a','Open browser dashboard','button quiet') as HTMLAnchorElement;external.href=dashboardUrl;external.target='_blank';external.rel='noopener noreferrer';target.append(external);} target.append(el('p',ONBOARDING_NOTICE,'muted')); const form=el('div','','panel form-stack'), chosen: HTMLInputElement[]=[]; for(const preset of ONBOARDING_PRESETS){const label=el('label','','check'), box=document.createElement('input');box.type='checkbox';box.value=preset.id;chosen.push(box);const copy=el('span',preset.name);copy.append(el('small',preset.purpose+' Components: '+preset.components.join(', ')));label.append(box,copy);form.append(label);} diff --git a/scripts/onboarding-browser.py b/scripts/onboarding-browser.py index ef349a7..36c99b1 100644 --- a/scripts/onboarding-browser.py +++ b/scripts/onboarding-browser.py @@ -27,7 +27,7 @@ async def main(): # Permanent visible labeling: screenshots never imply real Discord/provider acceptance. await page.evaluate("""() => {const b=document.createElement('p');b.textContent='OFFLINE SYNTHETIC DEMO — fake Discord/Jev; not live acceptance';b.style='background:#ffedb3;color:#191919;padding:14px;font-weight:bold';document.body.prepend(b)}""") native=await page.evaluate("({documentAPI:typeof document.modelContext?.registerTool,navigatorAPI:typeof navigator.modelContext?.registerTool})") - await page.get_by_text('WebMCP unavailable or blocked.',exact=False).wait_for() + await page.get_by_text('AI browser agent tools (WebMCP) are not available',exact=False).wait_for() await page.screenshot(path=str(root/'evidence'/f'issue44-fallback-{label}.png'),full_page=True) await page.get_by_label('Scam and phishing review',exact=False).check() await page.get_by_label('Add monitored channel IDs',exact=False).fill('100000000000000021')