@botbuddy/react
v0.9.13
Published
BotBuddy test coordination widgets for React — draggable, translucent overlays for human-in-the-loop QA
Downloads
2,424
Maintainers
Readme
@botbuddy/react
Draggable, translucent test coordination widgets for React. Drop into any app for human-in-the-loop QA powered by BotBuddy.
Install
npm install @botbuddy/reactQuick Start
import { TestRunWidget } from "@botbuddy/react";
function App() {
return (
<>
{/* Your app */}
<TestRunWidget
config={{
serverUrl: "https://api.bot-buddy.ai/functions/v1/mcp-server",
anonKey: "your-supabase-anon-key",
supabaseUrl: "https://api.bot-buddy.ai", // enables realtime updates
}}
appSlug="my-app"
environment="staging"
ticketId="PROJ-123"
targetUrl={window.location.origin}
onNavigate={(path) => (window.location.href = path)}
/>
</>
);
}Widget Modes
| Mode | Shows | |------|-------| | Mini | Pill with pass/total count + clickable PR & ticket links | | Expanded | Title, environment badge, stats, description, links | | Max | Full test case list with verdict buttons + fail reason input |
Click the pill to cycle through modes. Drag to reposition anywhere on screen.
Props
| Prop | Type | Description |
|------|------|-------------|
| config | BotBuddyConfig | Server URL and anon key (required) |
| appSlug | string | App identifier (required) |
| environment | string | local, preview, staging, production, custom (required) |
| testRunToken | string | Widget access token (public_xxx) — highest priority resolution |
| testRunId | string | Direct test run ID lookup |
| targetUrl | string | Match by deployed URL (e.g. window.location.origin) |
| version | string | Match by version |
| commitSha | string | Match by commit SHA |
| branchName | string | Match by branch name |
| onNavigate | (path: string) => void | Called when user clicks a test case URL |
| displayName | string | Attribution name for verdicts (default: "human") |
| defaultMode | WidgetMode | Initial mode: "mini" (default), "expanded", or "max" |
| defaultPosition | { x: number; y: number } | Initial pixel position |
Resolution Waterfall
The widget finds the active test run using a strict priority waterfall. Within each step, active runs beat draft beat completed; among equal status, the most recent wins.
| Priority | Params | Strategy |
|----------|--------|----------|
| 0 | testRunToken | Widget access token (public_xxx) — zero-ambiguity |
| 1 | testRunId | Direct UUID |
| 2 | targetUrl (+ appSlug, environment) | Origin match (scheme+host+port), scoped to app+env |
| 3 | appSlug + environment + version | Semantic version |
| 4 | appSlug + environment + commitSha | Exact SHA |
| 5 | appSlug + prNumber | PR-scoped |
| 6 | appSlug + environment=local + branchName | Branch (local only) |
| 7 | appSlug + environment | Broadest match |
| 8 | commitSha (7+ chars) | SHA prefix (cross-app last resort) |
Token Resolution Cascade
When no explicit testRunToken prop is passed, the widget automatically discovers the token:
- Explicit prop —
testRunToken="public_xxx" - Agent-injected file —
fetch('/.botbuddy-token')reads a file the agent writes topublic/.botbuddy-token - Build-time env var —
VITE_BOTBUDDY_TEST_RUN_TOKEN(set in CI/preview environments)
When a ticket_id is provided during create_test_run, the token is upserted on ticket_id + environment, so multiple agents or worktrees working on the same ticket share the same resolution context.
Local 2FA Secrets (no API key required)
When environment === "local", the widget can compute TOTP codes
client-side from a developer-owned file at public/.botbuddy-totp.json:
{
"[email protected]": "JBSWY3DPEHPK3PXP",
"[email protected]": "JBSWY3DPEHPK3PXQ"
}If a key in this file matches the case's seed_user slug, the widget
generates the code in-browser (RFC 6238, SHA-1, 30s, 6 digits) and skips
the server /widget/totp-code round-trip. This means local development
does not need BOTBUDDY_API_KEY or a register_totp_seed MCP call.
- Honored only when
environment === "local". Preview, staging, and production always go through the server endpoint so the secret never leaves the developer's machine. - File must be gitignored — it contains the raw TOTP secret. Add
public/.botbuddy-totp.jsonto your repo's.gitignore. - If a slug is missing from the file, the widget falls back to the server endpoint as before — so the file is purely additive.
- The file is resolved against your app's
<base href>if one is set (Vite emits this automatically whenbaseis configured), otherwise it's fetched from the domain root. If you deploy to a subpath, make sure your build emits<base href>so the lookup hits the right URL.
Origin-Based Matching
When targetUrl is provided, the server matches by origin (e.g. http://localhost:5173), not the full URL. Redirects, query params, and hash fragments won't break resolution. Pass window.location.origin for best results.
Matches are scoped to appSlug + environment to prevent cross-app collisions. If two runs exist on the same origin with different paths, the exact-path match takes priority.
Hooks
Use the hooks directly for custom UIs:
import { useTestRun, useDraggable } from "@botbuddy/react";
const { run, widgetState, setVerdict, markComplete } = useTestRun({
config: { serverUrl: "...", anonKey: "..." },
appSlug: "my-app",
environment: "staging",
});
const { pos, onPointerDown, onPointerMove, onPointerUp } = useDraggable(16, 600);Zero Dependencies
The widget uses inline styles and inline SVG icons — no Tailwind, no icon library, no CSS imports needed. Just React.
License
MIT
