v0.7.2
v0.7.2 — mode wiring + audit hardening
Three groups of fixes, all surgical (no refactors, no new features).
1 · Mode chrome flags wired end-to-end (originally tagged v0.7.1)
handleLaunchChrome/check-cdp/focus-debug/ agent preflight /mcpConfigall consumeeffectiveLaunchExtras()— security mode now actually launches Chrome on 9333 with--proxy-server+ SPKI pin in real user flow. v0.7.0 storedmodeChromeProxybut nobody read it; smokes hid the bug becausee2e-smokecalledlaunchDebugChromedirectly.systemPromptAdditionswalks every loaded plugin (not just active-mode plugin). Plugin contributing an always-on prompt without a mode now works.switchModerolls backcurrentModeId/modeChromeProxy/mcpEnvOverrides+ rebroadcasts modes on activate-hook failure. v0.7.0 left state half-applied.replayFlowrefuses cross-origin replay by default. Opt-in viaallowCrossOrigin: trueon the MCP tool. Prevents agent accidentally probing third-party APIs the dev server calls (Stripe / Sentry / analytics).replayFlowgets a 30s default timeout (AbortSignal.timeout). Hung target no longer blocks the MCP tool indefinitely.
2 · Audit hardening — round 1
- widget WS reconnect —
detachWs()unbinds the previous socket's handlers before swap;scheduleReconnect()guarded against double-scheduling so a paired error+close can't queue two reconnects. - widget save-menu race — deferred
addEventListeneris tracked inattachTimer; acloseMenu()inside the same tick cancels it, so listeners can never attach after close and leak. - widget pagehide — new
releaseVoiceResources()stops the mic interval, callsrecognizer.stop(), and cancels the speaker queue on tab close / HMR reload. - core
sendIfOpenhelper — new utility inservice/types.ts. The deferredagentsbroadcast on connect now guardsreadyStateand.catches agetAvailabilityrejection (was an unhandled promise). raiseWindow—runCapture/runDetachedtrack asettledflag — a child that errors and then closes can no longer resolve / reject twice.saveHandlers— anonSavedfailure (e.g.listSkills) no longer overwrites the artifact's success message with a fake "save failed" error; logged as a warning instead.- webpack-plugin — hard floor
if (mode !== 'development') return;regardless of customenabledcallback. Prod HTML never gets widget injection.
3 · Audit hardening — round 2
- duplicate
session_endon cancel — a user-initiatedcancel()already sent a syntheticsession_end{cancelled:true}; the subsequentAbortErrorsurfacing in the for-await catch used to send a secondsession_end{isError:true}. Catch is now gated on!cancelledand also skips preflight invalidation (CDP isn't suspect — the user just stopped). defaultDisallowedToolson descriptor — the 18-item hard-sandbox deny list moves ontoclaudeAgent;service.tspullsinvokedDescriptor.defaultDisallowedToolsinstead of hard-coding the list at the call site. Future agents own their own deny list.- error path — switched to
sendIfOpenfor parity with the cancel-path catch.
Verified
pnpm typecheckclean across all 9 publishable packagespnpm test— 177 vitest tests across core / widget-bootstrap / vite-plugin- Playwright e2e (
basic-app/__vibe_tests__/login-and-counter.spec.ts) passes - All 5 security smokes pass
Packages on npm
@hover-dev/core · @hover-dev/widget-bootstrap · @hover-dev/astro · @hover-dev/nuxt · @hover-dev/next · @hover-dev/cli · @hover-dev/security · vite-plugin-hover · webpack-plugin-hover — all at 0.7.2.
Full Changelog: v0.7.0...v0.7.2