diff --git a/frontend/packages/agent/src/Root.tsx b/frontend/packages/agent/src/Root.tsx index 5b2dbeb4..cc3bb991 100644 --- a/frontend/packages/agent/src/Root.tsx +++ b/frontend/packages/agent/src/Root.tsx @@ -202,7 +202,9 @@ export function Root() { costLabel={cost !== null ? fmtTokens(cost) : undefined} paused={state.paused} onTogglePause={() => { - submitPauseResume(resolveDashboardBase(state.dashboard_port), state.label, state.paused ? 'resume' : 'pause'); + submitPauseResume(resolveDashboardBase(state.dashboard_port), state.label, state.paused ? 'resume' : 'pause').then( + () => refresh(), + ); }} /> diff --git a/frontend/packages/agent/src/lib/pauseAction.ts b/frontend/packages/agent/src/lib/pauseAction.ts index 060358fd..fee3d9e0 100644 --- a/frontend/packages/agent/src/lib/pauseAction.ts +++ b/frontend/packages/agent/src/lib/pauseAction.ts @@ -1,16 +1,23 @@ // Pause/resume POST to the *dashboard's* origin (hive-c0re, not this -// agent's own `/api/*`) — see dashboardBase.ts. A real `
` submit -// rather than `fetch`, kept unchanged from app.js: accessed directly -// (not through the gateway proxy), the dashboard is a different origin/ -// port, and a cross-origin `fetch` POST needs the response readable -// under CORS to report success/failure — a full navigation form submit -// sidesteps that (the browser reloads to whatever the endpoint -// returns) without needing hive-c0re to grow CORS headers for what's -// otherwise a same-origin action behind the gateway. -export function submitPauseResume(dashboardBase: string, label: string, verb: 'pause' | 'resume'): void { - const form = document.createElement('form'); - form.method = 'POST'; - form.action = `${dashboardBase}api/${verb}/${label}`; - document.body.appendChild(form); - form.submit(); +// agent's own `/api/*`) — see dashboardBase.ts. `fetch` with +// `mode: 'no-cors'` rather than a normal request: the POST is cross- +// origin (behind the gateway this page and the dashboard share an +// origin, but accessed directly they're different ports) and this way +// hive-c0re doesn't need to grow CORS headers for it — the tradeoff is +// an opaque, unreadable response, which is fine here since the caller +// doesn't need to read it, only trigger a state refresh afterward (same +// shape as `postModel`/`postEffort` in modelEffort.ts). `credentials: +// 'include'` matches the cookie-sending behavior of the plain +// submit this replaces. +// +// mara flagged: the previous version was a real `` submit, which +// navigates the whole page to whatever hive-c0re's endpoint returns — +// here, the literal text "ok". Fire-and-forget `fetch` keeps the click +// on the agent page. +export async function submitPauseResume(dashboardBase: string, label: string, verb: 'pause' | 'resume'): Promise { + await fetch(`${dashboardBase}api/${verb}/${label}`, { + method: 'POST', + mode: 'no-cors', + credentials: 'include', + }).catch(() => {}); }