Changelog

What's new in TraceBug

Every release, straight from the repo. New capture features, agent-workflow improvements, and the bugs we caught in the bug-catcher.

v1.10.1
2026-07-29

Store-readiness release: fixes from a Chrome Web Store-style review — permission minimization, a hardened page↔extension bridge, and four real extension-lifecycle bugs the happy path had been hiding.

Fixed
  • Removed the unused tabs permission
    the extension never needed it (every chrome.tabs.* call rides activeTab or host permissions), and it added a "Read your browsing history" install warning for nothing.
  • Page→extension bridge is now allowlisted
    page scripts can only relay the six tb:rec:* recording verbs; previously a page could relay arbitrary message types (including CAPTURE_SCREENSHOT, reading the tab's pixels back without a consent prompt).
  • tb:rec:started now actually reaches the page
    it was broadcast via runtime.sendMessage, which never delivers to content scripts, so the HUD-mount fallback, the mic-missing toast, and the slow-picker recovery (2-min cap + DOM replay re-arm) were dead code end-to-end. Background now fans it out per-tab like the auto-stop broadcast.
  • Service-worker hydration race
    a mutating event that *woke* the worker (tab close, toolbar ✕, auto-stop) could persist blank state over every tab's saved state, and the in-flight hydration read could then resurrect the stale snapshot. All mutating paths now await hydration, and a dirty flag makes fresh writes win.
  • Firefox recorder-window id survives event-page restarts
    previously a restart mid-recording meant closing the popup never ended the recording on-page, passive probes reported "not recording", and the next start opened a second window.
  • The recorder host is closed after every recording on both browsers
    Chrome's offscreen document (exempt from auto-teardown) used to hold the full base64 recording in memory until browser close; recovery is served from chrome.storage.local instead.
  • minimum_chrome_version: 116
    declared — Chrome ≤108 used to install the extension and silently fail to record.
v1.10.0
2026-07-29

The Firefox release: the extension now ships for Firefox 128+ from the same source as Chrome, with honest handling of every platform difference (gesture-gated screen picker, opt-in site access, no tab audio). Also makes locally saved tickets eviction-proof with storage insights, and hardens both flows with fixes from a full multi-agent review — including a cross-browser Sentry-mode bug where 📸 captures could attach a stale video.

Added
  • Firefox extension
    (tracebug-extension/build/build-ext.mjs, background.js, offscreen.*) — the extension now builds and packages for Firefox (115+) from the same source as Chrome. Firefox has no offscreen API, so the recorder page runs in a small popup window instead; because Firefox's getDisplayMedia requires a user gesture *in that document*, the popup shows a Share screen button that opens the native picker (Chrome's invisible flow is unchanged). Closing the recorder popup mid-recording tears the on-page HUD down cleanly. npm run zip:ext now also produces the AMO upload zip (tracebug-firefox-v<version>.zip), and the Firefox manifest declares data_collection_permissions: none — TraceBug collects nothing.
  • Saved tickets are eviction-proof
    (src/storage.ts, src/ui/quick-bug.ts, src/compact-toolbar.ts) — tickets saved with Save Ticket now live until explicitly deleted: storage-pressure eviction and session rotation only ever touch unsaved sessions, saves are verified before "Saved" is shown (with a screenshot-dropping fallback that's committed only on success and marked on the ticket card), and a warning fires at ~90% storage usage — before saves start degrading, not after. The Saved Tickets list is un-capped (scrollable) and gains per-ticket sizes, a storage meter with a room-for-≈N-more estimate, one-click Export (.html replay), and a two-click delete confirm. Storage-pressure incidents are counted locally (TraceBug.getStorageStats(), never transmitted) as the decision gate for the future IndexedDB migration.
Fixed
  • Sentry-mode 📸 Capture could attach a stale or missing video
    (cross-browser) — the capture reply told the page to fetch the clip from storage, but the capture was never persisted there; each rolling capture now persists before replying (tracebug-extension/offscreen.js).
  • Firefox parity hardening
    Xray-safe content-script→page events (cloneInto), one-time host-permission request at the first capture (Firefox treats site access as opt-in), injection failures surface in the popup instead of a false success, screenshots capture the requester's window (not whichever window has focus), recordings persist via direct chrome.storage.local when available (no multi-MB IPC round-trip), the recorder popup never opens for passive probes and closes itself after stop/cancel, clipboard writes no longer throw unhandled activation errors after async exports, and a recording recovered via broadcast (slow picker) re-arms the 2-minute cap and DOM replay.
  • Saved-ticket storage engine
    a refused write (storage full of saved tickets) is now side-effect-free (no in-memory event loss), re-saving an already-saved ticket can't un-save it, deleteSession preserves un-flushed data when freeing space, storage warnings are throttled (one per incident, not one per second), and failed flushes back off instead of re-serializing every second.
v1.9.0
2026-07-22

The fix-loop release: the report stops being evidence an agent *reads* and becomes something it *iterates against* — run the generated failing test, patch, re-run until green. Also ships inspect mode (design-QA style evidence), pre-recording blur, an extension redaction UI, and a full production-audit hardening pass (bounded recording memory, capped console capture, modal focus trap, faster source-map resolution, e2e in CI).

Added
  • Generated failing Playwright test
    (src/exporters/playwright-test.ts) — every export now embeds a runnable spec that replays the captured session (locator preference: data-testid → id → aria-label → role+name → captured CSS selector) and asserts the captured failure is gone: failed requests are collected and the specific endpoint must stop failing; console errors must stop being thrown. Red while the bug exists, green after the fix. Redacted input values become TODO placeholders with a comment. Available three ways: Download failing test (.spec.ts) in the Quick Bug More menu, embedded in the .html export payload, and via the MCP get_playwright_test tool. New SDK exports: generatePlaywrightTest, playwrightTestFilename. Input/select events now also capture a stable CSS selector (clicks already did).
  • Source-map stack resolution
    (cli/source-map.ts, MCP resolve_stack) — maps the report's minified stack frames (assets/index-ab12.js:1:43210) to original source files/lines using .map files discovered in the repo the MCP server runs from. Dependency-free V3 decoder (base64 VLQ, ~150 lines) keeps the published CLI at zero runtime dependencies. searchDir targets a custom build-output folder.
  • MCP tool get_fix_context
    one-call fix starter: the failing request with response snippet, the user action that triggered it, the first error with source-map-resolved top frames, and whether a generated failing test is available. The investigation guide now routes agents to the new tools; the server exposes nine tools total.
  • Extension UI for redaction rules
    (tracebug-extension/popup.*, content-script.js, tracebug-init.js) — the popup gains a collapsible 🛡 Redaction rules section (field names + regex patterns, validated on save) so extension users get the 1.8.0 redact config without writing code. Rules sync via chrome.storage.sync and reach the page-world SDK through <html data-tb-redact> (the same bridge as the CSP-proof player URL); a MutationObserver pushes edits into an already-running SDK live via setRedactRules.
  • Blur is element-level now — click to blur/unblur
    (src/ui/blur-tool.ts) — rebuilt from drag-rectangles to Traeco-style element picking: hover highlights, click applies filter: blur(12px) to the element itself, click again unblurs, Undo on the arming bar removes the last. Because the blur is part of the element's own rendering it moves in the same paint as the content — it physically cannot lag behind scrolling (the old viewport-fixed boxes exposed the text during fast scrolls, and even frame-tracked overlays trail by a frame). Blurred elements also get tb-mask, so the rrweb DOM replay masks their text, not just the video pixels. Blurs persist through the recording and are restored (original inline filters preserved) when it stops. HUD blur icon changed from an ambiguous cloud to the standard droplet.
  • Pre-recording options — blur first, then roll
    (src/ui/pre-record.ts, TraceBug.prepareRecording(), extension popup) — the popup gains a ⚙ Record options panel (persisted): capture surface (current tab / desktop picker), start delay (3s/5s with an on-page 3-2-1 countdown overlay), and Blur before recording — activates the existing blur tool *before* capture starts, with a floating "● Start recording / Cancel" bar, so sensitive areas are redacted with real backdrop blur from the very first frame (cancel clears the boxes). Options flow popup → background → content script → prepareRecording({ blurFirst, delaySec, surfaceMode, withMicrophone }), which is also public SDK API. The in-recording HUD already had pause/mic/screenshot/draw/blur — this closes the pre-roll gap.
  • Inspect mode — style evidence for design-QA bugs
    (src/inspect-mode.ts, src/style-evidence.ts) — "the button looks wrong" now ships with the receipts. A DevTools-style inspect mode (extension popup → Inspect element, or TraceBug.activateInspectMode()): hover paints the box-model highlight (margin/padding/content tint) plus a tooltip with the computed-style summary; click attaches the element to the report as an inspect annotation carrying a curated ~20-property style snapshot — typography, colors as hex, box model, layout — plus a WCAG text-contrast verdict (ratio + AA pass/fail, large-text aware). Existing annotate-mode annotations capture the same evidence. Surfaced everywhere: expandable "Styles" block on modal annotation cards, an Element Evidence section in generated GitHub issues, the export's Description panel, and structured elementAnnotations in the payload so MCP agents get it from get_bug_report (the investigation guide points visual bugs at it — diff captured styles against the design tokens in the repo). Deliberately *not* a site-explorer (palette/assets/responsive is VisBug's job) — this exists so visual bugs are fixable from evidence. New exports: captureStyleEvidence, formatStyleSummary, contrastRatio, cssColorToHex, activateInspectMode/deactivateInspectMode/isInspectModeActive.
v1.8.0
2026-07-21

The launch-feedback release — every feature here traces to a Product Hunt comment. Visible, configurable redaction (a masked-values summary in the export flow, app-specific redact rules for PII the token patterns can't know), console.info capture with warn/info rendered properly in the repro timeline, a .zip export because GitHub issues accept .zip but reject .html, and issue actions inside the exported report so the file's recipient can file the ticket, not just read the evidence.

Added
  • Redaction summary — the pipeline is finally visible
    (src/redaction-summary.ts, src/ui/quick-bug.ts, src/exporters/html-replay.ts) — the export modal footer and the exported report's Info tab now show exactly what the sanitizers masked, e.g. 🛡 3 sensitive values auto-masked (1 token, 2 URL params), counted by category (tokens, URL params, form fields, storage values) by scanning the built report for the [REDACTED] markers. Omitted at zero — pattern matching can't promise a clean bill of health. New SDK exports: summarizeRedactions, formatRedactionSummary.
  • Configurable redaction rules
    (src/sanitize/custom-redaction.ts, redact in TraceBugConfig) — declare app-specific PII the built-in token shapes can't know about: redact.fields (name-based, case-insensitive substring — covers form/input names, storage keys, URL query params, and JSON/urlencoded keys inside console output and response snippets) and redact.patterns (custom regexes masked anywhere in captured text). Applied at capture time on top of the built-in masking; counted in the auto-masked summary; invalid patterns are skipped so a typo can't break capture. New exports: setRedactRules, RedactRules.
  • console.info capture + warn/info in the repro timeline
    (src/collectors.ts, src/timeline-builder.ts) — info was previously not captured at any level; it now rides the "warnings" tier (error + warn + info). Warn/info/log events render as their message in the timeline ( / prefixes) instead of a raw JSON dump. Each non-error level is capped at the first 50 calls per session, and TraceBug's own [TraceBug] diagnostics are never captured.
  • Download .zip (attach to GitHub)
    (src/exporters/zip-export.ts, More menu) — the same offline replay wrapped in a .zip, because GitHub issues accept .zip attachments by drag-and-drop but reject bare .html. Zero-dependency ZIP writer (~150 lines): CompressionStream("deflate-raw") when available, STORE fallback, CRC-32, UTF-8 names. Generated GitHub issues now end with a Full Repro Replay section telling the reporter to drag the .zip in. New exports: exportSessionAsZip, buildZipBlob.
  • Issue actions in the exported report
    (src/exporters/html-template.ts, src/exporters/html-replay.ts) — the file's recipient is usually the person who files the ticket, but the viewer was read-only. The header now has Open GitHub issue (prefilled github.com/…/issues/new URL, shown when the exporter configured githubRepo) and Copy issue markdown (fully offline, pastes into any tracker). Both are precomputed at export time — zero issue-builder code ships in the viewer, and the markdown derives from the already-redacted report. Token-based integrations deliberately stay out of the shareable file. HtmlReplayOptions.githubRepo added.
  • Official MCP Registry metadata
    (packages/tracebug/server.json, mcpName in the CLI package) — the tracebug npm package now carries the registry's verification marker and a server.json for mcp-publisher publish under io.github.prashantsinghmangat/tracebug.
  • Marketing screenshot pipeline
    (e2e/marketing-screenshots.mjs) — Playwright script that drives the live sandbox (record → trigger bugs → Quick Bug modal → region screenshot → export) and screenshots the exported viewer, producing current-build product shots on demand.
Changed
  • Severity is labeled as machine-classified
    the modal Info tab, exported Info rows, and the viewer's header badge tooltip now say "Severity (auto)"; the modal's Priority dropdown placeholder shows the severity-derived suggestion (Priority (auto: Medium)) with a tooltip clarifying it isn't exported unless explicitly picked. Auto severity kept being mistaken for a tester's triage call.
  • Docs match the shipped captureConsole default
    (docs/api-reference.md, docs/configuration.md, docs/bug-reporting.md) — the default has been "all" since 1.7.0 but the docs still claimed "errors"; the tier table now includes console.info and the per-level caps, and the privacy section gained a full "what gets redacted" table with honest limitations.
Fixed
  • Unbounded rrweb buffer during long recordings (OOM risk)
    (src/rrweb-recorder.ts) — the DOM-replay event array had no cap, so a multi-hour "record all day" session could accumulate hundreds of MB and crash the tab before export. rrweb now emits a fresh full snapshot every ~2 minutes (checkoutEveryNms), and the buffer is trimmed back to the most recent full snapshot past a soft cap (with a hard ceiling as a floor guarantee) — the retained tail always stays replayable. wasDomBufferTrimmed() reports when a session was windowed. Pure trimEventBuffer() is unit-tested.
  • Console/error messages could bloat the report (and drop on circular refs)
    (src/collectors.ts) — captured console arguments and error messages/stacks are now capped at 10 000 chars (…[truncated]), so a single console.error("x", hugeObject) can't retain a multi-MB string in the event buffer and localStorage. The new formatConsoleArgs is also circular-safe: a logged circular object degrades to [unserializable] instead of throwing and silently dropping the whole event.
  • Quick Bug modal now traps focus
    (src/ui/quick-bug.ts) — Tab / Shift+Tab cycle within the dialog instead of escaping to the inert page behind it (WCAG 2.4.3 / 2.1.2). Escape-to-close and focus-restore-on-close were already present; this completes the modal's keyboard semantics. trapModalTab / getFocusableElements are unit-tested.
  • CI now runs the browser e2e suite
    (.github/workflows/ci.yml) — an e2e job builds the real SDK bundle and runs the headless Playwright checks (blur tracking, pre-record flow, inspect mode) so regressions in the most complex recorded flows are caught automatically. The e2e scripts are now path-portable (were hardcoded to a local absolute path).
  • Unified sensitive-query-param detection
    (src/url-hygiene.ts isSensitiveParamName) — the capture-time URL redactor and the upload sanitizer kept two separate key lists that had drifted (one caught sig/signature, the other session/sid/csrf/pwd; each under-redacted what the other caught). Both now share one matcher that is a strict superset of both — neither path ever redacts less than before.
  • Faster source-map resolution
    (cli/source-map.ts) — a map's mappings are now decoded once and cached (per map object), and the map-file path cache is module-scoped across calls. Previously every stack frame re-decoded every mapping line up to its target and re-walked the repo for the bundle — seconds on a large map with a deep repo; now one decode + an O(segments-in-line) lookup. clearSourceMapCache() added for long-lived servers.
  • Light-mode muted text meets WCAG AA
    (src/theme.ts) — --tb-text-muted was #82828C (3.8:1 on white, fails AA for normal text); now #75757E (4.56:1).
  • Long standard recordings warn past 1 GB
    (tracebug-extension/offscreen.js) — a multi-hour non-rolling recording accumulates all chunks in the offscreen document; it now logs a one-time warning past 1 GB advising rolling mode (the default), rather than silently growing. No hard cap — truncating the video could lose the bug.
  • Unified "is this our UI element?" check for the mode tools
    (src/dom-helpers.ts) — annotate, blur, and inspect each carried a near-identical ancestor walk with drifted prefix sets; they now share one isTraceBugUiElement. Deliberately matches only widget prefixes (tracebug-/bt- ids, tracebug-/tb-qb/tb-hud/tb-rs classes, data-tracebug) and not bare tb-, because tb-mask/tb-block are redaction markers applied to host-page content — a broad match would treat a blurred element as our own UI and break second-click-to-unblur (caught by e2e, locked in by a test). The capture-path check in collectors is intentionally left separate — broadening it could drop host events.
  • init() split into named phases
    (src/index.ts) — the ~250-line init() was extracted into six private phase methods (_validateConfig, _applyThemeFromConfig, _wireQuickBugConfig, _buildEmit, _startCollectors, _mountDashboardIfEnabled, _restoreVideoSessionOnInit) with the orchestrator now ~80 lines. Pure internal refactor — no public-API or behavior change (verified: 303 unit tests + all e2e green). The TraceBugSDK facade split flagged in the audit stays deferred to a major version.
  • Tokens logged to the console reached the offline export unmasked
    (src/collectors.ts) — the token-shape scrub ran at capture only for network response snippets; console messages and error stacks were scrubbed only on the cloud-upload path, which the offline .html export never runs. sanitizeTokenShapes now applies at capture to console error/warn/info/log messages and to window.onerror / unhandled-rejection messages and stacks — a logged Bearer/JWT can no longer enter the report object at all.
  • console_warn/console_log rendered as truncated JSON in the timeline
    (src/timeline-builder.ts) — they fell into the default JSON.stringify case instead of showing the message.
v1.7.0
2026-07-17

The launch-polish release. A full Slate Indigo rebrand across every surface (widget, exports, extension, website — with "Trace", the pixel-sprite mascot), the exported replay slims down ~3–4× via gzip, issue-tracker exports file real GitHub/Linear/Slack items with your own token, and the website gains a live sandbox running the actual SDK plus a 15-second real-capture demo video. Zero lint warnings, dead code removed, adoption friction audited and fixed.

Added
  • Slate Indigo brand + "Trace" the pixel mascot
    (src/theme.ts, website/, tracebug-extension/) — one palette across all five token surfaces (widget, replay export, AI export, extension popup, website): slate-tinted near-black neutrals, a single refined indigo accent (#6366F1), green reserved strictly for success. New 8-bit mascot appears in the website flow diagram, 404, footer, hero headline (as the blinking caret), and the extension's "can't run here" state — crisp at every size because it *is* pixels. All icons (favicon, extension, apple-touch) regenerated.
  • Live sandbox — the real widget on the website
    (website/public/try.html) — a checkout page with two intentional bugs (a TypeError and a failing POST) running the actual IIFE SDK bundle. Visitors trigger a bug, capture it with the real toolbar, and export a genuine self-contained report. Linked from the demo section; the extension opens it as the first-install welcome tab.
  • Real demo video
    (website/public/tracebug-demo.webm) — a 15-second captioned screen recording of TraceBug catching a live crash on the sandbox (recorded by scripting the real product with Playwright, so re-cuts are a script run). Embedded in the website demo section with lazy mount, reduced-motion handling, and a poster fallback; replaces the scripted walkthrough iframe and the stale README GIF.
  • MCP tool picker on the hand-off card
    (src/ui/quick-bug.ts) — the post-export card now shows the one-time setup command for Claude Code / Cursor / VS Code with per-tool copy, instead of assuming Claude Code.
  • First-install welcome
    (tracebug-extension/background.js) — installing the extension opens the live sandbox with a tailored "try your first capture" banner instead of nothing.
  • npm run zip:ext
    reproducible Chrome Web Store upload zip, versioned from package.json into releases/.
  • Website: flow diagram, changelog page, and motion polish
    a Userback-style "everything connects" section with measured SVG beams; a /changelog page rendered from this file at build time; a self-assembling hero report card (events stream in, skeletons hand off to the root-cause box); cursor-spotlight cards; OS-level dark-mode auto-detect; a DevTools console easter egg.
  • html2canvas fallback for script-tag consumers
    (src/screenshot.ts) — when the lazy import("html2canvas") can't resolve (no bundler — e.g. the IIFE bundle on a plain page), the SDK now picks up a page-provided window.html2canvas UMD global, so screenshots work outside bundled apps and the extension.
  • Real issue-tracker integrations (BYO-token)
    (src/integrations/tracker-client.ts) — the GitHub / Linear / Slack export buttons now create a real issue/message via the provider's API using the user's own token, instead of only prefilling a URL or copying markdown. The call goes directly from the browser to the provider — token in localStorage, no OAuth, no TraceBug backend — the same privacy pattern as the BYO-key AI Debugger. GitHub uses a PAT (POST /repos/{owner}/{repo}/issues), which also lifts the ~6–8 KB URL-prefill truncation cap (the full report body travels in the request body); Linear uses a personal API key (GraphQL issueCreate, returns the issue URL + identifier); Slack uses an incoming webhook (fire-and-forget). A 🔗 Configure integrations modal (More menu) stores per-provider tokens; when a provider is configured its export button files for real, otherwise it falls back to the existing URL/copy flow. Jira Cloud is intentionally excluded (CORS-blocked for browser XHR) and stays copy-markup. New SDK exports: createTrackerIssue, createGitHubIssue, createLinearIssue, sendSlackMessage, getIntegrationsConfig/setIntegrationsConfig/clearIntegrationsConfig, hasIntegration. (src/ui/quick-bug.ts, tests/tracker-client.test.ts — 11 tests)
  • Self-contained DOM replay export (rrweb)
    (src/rrweb-recorder.ts, src/exporters/html-replay.ts, src/exporters/html-template.ts) — Export .html now embeds an interactive DOM replay instead of the multi-MB base64 video. rrweb records a full DOM snapshot plus incremental mutation events (KB, not MB); the exported .html inlines rrweb's Replayer runtime and reconstructs the page in a sandboxed <iframe>, scaled-to-fit, with a play/seek control bar and click-to-seek from the Console/Network/Events rows. Inputs are masked and .tb-block/.tb-mask respected; inlineImages embeds images so the replay is genuinely offline (no requests back to the original site). The Replayer runtime is regenerated by npm run gen:rrweb (a prebuild hook, gitignored). Falls back to the screenshot gallery if the Replayer or DecompressionStream is unavailable.
  • Compressed replay stream
    (gzipToBase64 in html-replay.ts; inflateRrweb in html-template.ts) — the rrweb event stream is gzip-compressed via the browser-native CompressionStream and base64-embedded (rrwebEventsGz), then inflated at load with DecompressionStream. Repetitive DOM JSON compresses ~8–12×, cutting a typical replay file ~3–4× (measured 2.96 MB → 0.87 MB) with a byte-exact round-trip. No bundled compression library. The Export .html button's size estimate reflects the compressed size.
  • Export for AI (.html)
    (More menu; generateAiHtml/exportReportAsAiHtml in src/exporters/ai-prompt.ts) — a tiny (~5 KB) text-only HTML report for users who want to paste/upload a report into a chat (Claude/ChatGPT) without MCP. Renders the same capped/deduped structured content as the .md export — no rrweb runtime, no DOM blob, no base64 media — so it fits well under a chat's context limit. HTML-escaped throughout.
Changed
  • npx tracebug init is now honest and actually useful
    (cli/bin.ts) — it no longer claims to "set up" the project or print "Done! ready" when it only echoes a snippet. It now states plainly that it prints (doesn't install/edit), and — the real value — leads with the framework gotcha developers actually trip on: the Next.js App-Router "use client" + useEffect requirement, Nuxt's .client.ts SSR rule, and Svelte's onMount. All snippets now include the dev-only enabled: "auto" flag with an explainer. Website "CLI setup" tab updated to match.
  • shadcn (new-york) UI re-skin
    the injected widget (src/theme.ts), the exported replay viewer (src/exporters/html-template.ts), the AI export (src/exporters/ai-prompt.ts), and the extension popup (tracebug-extension/styles.css) all now share the website's brand palette (now the Slate Indigo palette — indigo-500 primary, slate near-black dark, hairline borders, 10/12/16 radii). Buttons match new-york variants (glow primary, active press, focus-visible rings via --tb-ring); the Quick Bug modal is a rounded-2xl card. Hardcoded off-palette colors in the draw/annotate tools were tokenized.
  • prebuild hook regenerates the rrweb runtime
    src/exporters/rrweb-runtime.generated.ts is gitignored and rebuilt by a prebuild step wired into all build* scripts, so a fresh clone builds cleanly.
  • Zero lint warnings
    cleared all 177 (no-explicit-any ×116, no-unused-vars ×61) with real types, not suppressions: proper axe-core/DOM/Web-Speech typings, small interfaces for provider API responses, unknown + narrowing for genuinely dynamic values. No eslint-disable, no as any. DrawRegion now officially includes the pen shape it always stored.
  • Dead code removed
    the cut v1 onboarding tour machinery (the surviving logo pulse now actually injects its keyframe — it silently never animated before), six dead toolbar functions and write-only state, orphaned website components, stale release zip, and the pre-rebrand docs/demo.gif.
  • Adoption audit fixes
    npx tracebug help pointed at a dead domain; the README's Chrome Web Store badge was a broken URL; docs led with --dir while the homepage taught the zero-config MCP form; the popup now surfaces the Ctrl+Shift+B shortcut and explains the mic toggle; example-app/ gained a README; the website sandbox SDK copy is auto-synced by every build.
Fixed
  • The exported replay no longer shows TraceBug's own UI
    (src/rrweb-recorder.ts) — rrweb was recording the injected widget (#tracebug-root, the compact toolbar) and the blank draw canvas into the DOM stream, so they rendered on top of the user's page in the exported .html replay (an empty box + the floating toolbar). A blockSelector now excludes TraceBug's own overlay UI from the capture while keeping the draw SVG overlay, so the replay shows only the user's page + the annotations.
  • Pen drawing is smooth, not laggy
    (src/draw-mode.ts) — freehand strokes re-stroked the *entire* growing path on every pointer move (O(n²), so it got laggier the longer you drew) and were raw polylines. Now each move draws only the newest segment (O(1)) and all strokes are quadratic-smoothed (canvas, the committed render, and the SVG replay path).
  • Pen/draw annotations now appear in the exported replay
    (src/draw-mode.ts) — during a recording, freehand pen strokes and shapes are drawn on a <canvas>, which rrweb's DOM replay can't capture (recordCanvas is off), so they showed in the modal's video preview but vanished from the exported .html DOM replay. Each committed shape is now mirrored as an SVG element in the page DOM with the same appear→fade lifecycle, so rrweb records it as ordinary DOM mutations and the annotations replay at the exact moment they were drawn — no file-size cost, no recordCanvas.
  • Event capture no longer stops on full-page navigation
    (src/index.ts, src/storage.ts, src/compact-toolbar.ts) — the Track session (events-only) capture now survives clicking a link to another page. A persisted capture mode (tracebug_active_capture_mode) lets the SDK resume an event-only session on the next page (keeping one session id across the whole flow) while still finalizing a *video* session whose tab-share Chrome ended. Also: durable flush on pagehide/visibilitychange:hidden (bfcache-safe), no duplicate session:start per navigation, and the toolbar's tracking state is restored after the load.
  • MCP server finds reports with zero setup
    (cli/mcp-server.ts, cli/bin.ts) — get_bug_report (and the other get_* tools) now resolve a report by bare filename or fragment from the user's Downloads/Desktop folders — where browser exports land — in addition to --dir. Previously the copy-pasted hand-off prompt failed unless the server was pointed at the download folder. Shared folders are shallow-scanned and name-prefiltered (tracebug-*) to stay fast. list_bug_reports widens to those folders only when the server started without an explicit --dir (an explicit --dir stays scoped to that folder). The generated hand-off prompt (generateMcpPrompt) drops the --dir requirement. (src/exporters/ai-prompt.ts, tests/mcp-server.test.ts)
v1.6.0
2026-07-09

The agent-workflow release. Three ways to get a bug in front of an AI — and none of them phone home: failed Playwright tests become the same agent-ready .html reports (upload as a CI artifact), BYO-key LLM analysis runs browser-direct against Anthropic/OpenAI/Ollama with your key never leaving the page, and HAR export hands you your network capture as a standard file you own. Built on the v1.5 local MCP foundation.

Added
  • HAR export
    (src/exporters/har-export.ts) — a new 🌐 Export HAR button in the Quick Bug modal writes the captured network activity as a standard HAR 1.2 (HTTP Archive) file that opens in Chrome/Firefox DevTools, Charles, Fiddler, and Postman. Reshapes the request/response data TraceBug already captures (method, url, status, timing, query string parsed into name/value pairs, failed-response bodies with a guessed mime type) into the spec — no new capture, no dependency. Spec-optional fields we don't capture (headers, cookies) are emitted as empty arrays / -1 sentinels per the HAR schema, so the output validates. New SDK exports buildHar (pure) and exportSessionAsHar (build + download). Jam markets "everything a HAR offers" but ships no HAR export — this owns that axis. Docs: docs/har-export.md. (src/ui/quick-bug.ts, tests/har-export.test.ts — 8 tests)
  • AI Debugger — BYO-key LLM analysis
    (src/ai/llm-client.ts) — the AI tab can now run real LLM root-cause analysis using the user's own API key (Anthropic / OpenAI / local Ollama). The call goes directly from the browser to the provider — no TraceBug backend — and the key is stored only in localStorage. The prompt (the same structured one the "copy prompt" flow builds) is scrubbed of secret token shapes via the existing sanitizer before it leaves the page; screenshots/video are never sent. The model returns markdown (Root cause / Evidence / Where to look / Suggested fix / Edge cases), rendered inline. Replaces the "coming soon" stub with a real provider+key+model config modal (migrates the legacy tracebug_ai_key bare-key storage). New SDK exports: runLLMAnalysis, buildAnalysisPrompt, getAIConfig/setAIConfig/clearAIConfig/hasAIKey, DEFAULT_MODELS, ANTHROPIC_MODEL_CHOICES, PROVIDER_LABELS. Completes the "private AI debugging" story (local heuristic + local MCP + BYO-key LLM). Docs: docs/ai-debugger.md. (src/ui/quick-bug.ts, tests/llm-client.test.ts — 11 tests)
  • Playwright reporter
    (tracebug-sdk/playwright) — every failed test writes a self-contained TraceBug .html report to outputDir (default bug-reports/): assertion error + Playwright code snippet, test.step()/pw:api timeline as repro steps and timeline events, failure screenshots from attachments, project metadata, and a local root-cause hint (5xx → high, 4xx/page error → medium, assertion-only → low). Optional traceBugPage fixture adds page console, uncaught errors, network requests with failed-response bodies, and navigations (attached only on failure, 500-entry caps). Reports are written only for the final retry; the reporter can never fail the run; output is verified readable by the MCP server (fuzzy title lookup + investigation guide). Zero runtime deps — the module imports nothing from @playwright/test (structural types), so it builds and tests without Playwright installed. New ./playwright subpath export, Node-side tsup entry, and tsconfig.node.json for typechecking Node code (cli/, src/reporters/). Docs: docs/playwright.md. (src/reporters/playwright.ts, tests/playwright-reporter.test.ts — 5 tests)
v1.5.0
2026-07-08

The MCP release: TraceBug exports become agent-ready. npx -y tracebug mcp gives Claude Code / Cursor / VS Code read access to every exported bug report — fully local, zero network connections.

Added
  • Standalone tracebug npm package
    new ~24 KB, zero-dependency CLI package (packages/tracebug) publishing just bin.mjs (MCP server + init), so a developer who only *receives* bug reports runs npx -y tracebug mcp without pulling the full SDK. tracebug-sdk still bundles the same CLI; npm run build:cli generates the package's bin from dist/bin.mjs. (packages/tracebug/, cli/bin.ts version lookup now supports both layouts)
  • MCP server
    npx -y tracebug mcp [--dir <path>] starts a local Model Context Protocol server so AI coding agents (Claude Code, Cursor, Windsurf, VS Code) can read exported bug reports and debug from them. Six tools: list_bug_reports, get_bug_report, get_console_errors, get_network_activity, get_repro_steps, get_screenshot (returns real image content). Reads the self-contained .html exports directly (the embedded tb-data payload) — fully local, stdio-only, zero network connections, zero new dependencies (the JSON-RPC loop is hand-rolled). Includes a demo report (demo-bug-reports/sample-report.html) and a pre-configured .mcp.json so a fresh clone works with Claude Code out of the box. Docs: docs/mcp.md. (cli/mcp-server.ts, cli/bin.ts, tests/mcp-server.test.ts)
  • Investigation guide
    get_bug_report now returns a prioritized "what to fetch next" list computed from what the report actually contains (e.g. [HIGH] get_network_activity — 2 failed requests captured…), so agents spend their tool calls on the data that matters for that specific bug. Network leads when the root-cause hint blames a request; console leads otherwise; screenshots are promoted to a primary source when no errors were captured. (cli/mcp-server.ts)
  • Forgiving report resolution
    every MCP tool's file argument now accepts a path, a bare filename found anywhere under the scan dir, or a case-insensitive fragment of the filename or report title; unresolvable names error with the list of available reports. (cli/mcp-server.ts)
  • debug_bug_report MCP prompt
    the server now advertises the prompts capability with one prompt (optional file argument): the standard hand-off ("load the report, follow its investigation guide, cross-reference the codebase, propose a fix"). In Claude Code: /tracebug:debug_bug_report. (cli/mcp-server.ts)
  • Agent hand-off prompt in the extension
    after every Export .html, the Quick Bug modal shows the paste-into-Claude-Code/Cursor prompt for that export (auto-copied to the clipboard) with a link to the MCP setup guide. New generateMcpPrompt() exported from the SDK. (src/ui/quick-bug.ts, src/exporters/ai-prompt.ts)
  • Agent hand-off prompt in the export itself
    the exported .html viewer's AI tab now carries a "Debug with a coding agent (MCP)" card with the same prompt and a copy button, so whoever receives the file learns how to feed it to their agent. The filename is recovered from the file:// URL at view time, so the prompt survives renames. The shipped demo report (demo-bug-reports/sample-report.html) was regenerated as a full viewer export, so it demos both the interactive replay and the agent card. (src/exporters/html-template.ts)
  • Website: /docs/mcp page
    docs/mcp.md is now on the website as a full docs page (workflow, hand-off prompt, Claude Code/Cursor/VS Code setup, tools reference, privacy, troubleshooting), linked from the docs TOC, a promo card on /docs, the footer Resources column, and the sitemap. (website/app/docs/mcp/page.tsx)
v1.4.0
2026-07-06

The hardening pass that made Phase 1 (fully offline) production-ready.

Production hardening & bug-fix pass (July 2026)
  • Removed committed Supabase credentials
    website/.env.local untracked from git; .gitignore now covers .env.local / .env.*.local. Keys must be rotated (they remain in git history).
  • cloudEndpoint validation
    new src/cloud-endpoint.ts with resolveCloudEndpoint(): HTTPS enforced (plain HTTP only for localhost), javascript:/data:/malformed URLs rejected with fallback to the production endpoint. Applied in the auth bridge constructor, all SDK call sites, share-link exporter, and the Quick Bug modal. Unit-tested.
  • Chrome extension manifest: explicit content_security_policy for extension pages.
  • Stale video bundled into unrelated exports / fresh video missing from the modal.
    The global last-recording had no session binding and the ownership check existed only in the modal. New shared getSessionVideo() gate in report-builder.ts (recording must start after the session was created, 10 s transport grace) used by both buildReport() and the modal; the toolbar record flow now arms the session *before* capture starts; historical tickets strip the video explicitly. (src/report-builder.ts, src/compact-toolbar.ts, src/ui/quick-bug.ts)
  • Modal video played only a few seconds of long recordings.
    Chrome MediaRecorder WebM lacks a duration header; the player now forces Chrome to compute the real duration (seek-past-end workaround) when the reported duration is Infinity/short. (src/ui/quick-bug.ts)
  • iframe-bridge.ready() could hang forever and leak a message listener
    when the bridge iframe never loaded — added a 20 s timeout that unmounts, cleans up, and allows retry. (src/auth/iframe-bridge.ts)
  • deleteSession() silently dropped up to 1 s of pending events
    from surviving sessions — pending flush now runs before the read. (src/storage.ts)
  • Uncaught (in promise) Error: No tab with id
    spam from the extension service worker — badge API promises are now awaited inside the try/catch. (tracebug-extension/background.js)
  • Clipboard copy failures now show "✗ Copy failed" instead of failing silently (src/dashboard.ts); "Fix with AI" button no longer renders white-on-white on hover in light theme; six ESLint errors fixed (emoji regex u flags, stray expression, extra semicolon); pushScreenshot() side-path now respects the 50-screenshot memory cap.
  • Exports now carry the user's edited title and description
    ; the description renders below the Replay (matching the ticket modal) instead of hiding in a tab. Notes and Description tabs removed from the export viewer (tabs: Info / Console / Network / Actions / AI / Events).
  • Tester-assigned priority is surfaced everywhere
    🚩 priority chip in the export header next to the auto-severity badge; priority flows user → session → report → all exports.
  • Cookies captured
    (non-HttpOnly only) alongside localStorage/sessionStorage with the same redaction rules; shown in the modal Info tab and export, scrubbed again by the cloud sanitizer.
  • Info tab cleanup: TraceBug's own tracebug_* storage keys filtered at capture, empty env rows dropped, per-row storage icons removed, explicit "Web storage — empty on this page" state.
  • Ticket modal: description editor open by default; Notes tab renders only when the session has annotations.
  • CI now runs ESLint and the test suite on every push/PR; package.json declares engines: node >=18.
Cloud sharing portal (Phase 6)
  • TraceBug.shareReport()
    uploads the bug report to TraceBug's cloud and returns a public URL like https://tracebug.dev/share/<id>. Recipient opens it in a browser without installing anything. (src/exporters/share-link.ts)
  • Sign-in via Supabase magic link
    TraceBug.signIn() / TraceBug.signOut() / TraceBug.getCurrentUser(). Auth happens in a hidden iframe pointed at tracebug.dev/sdk-bridge, so the customer's site never sees the auth token. (src/auth/iframe-bridge.ts, website/app/sdk-bridge/page.tsx)
  • 🔗 Share link button
    in the Bug Ticket modal next to "📦 Export .html". Shows inline spinner during upload; opens the public viewer in a new tab on success. (src/ui/quick-bug.ts)
  • Per-user quotas
    5 active video shares + 10 active screenshot shares, max 5 screenshots per share, 50 MB upload cap. Enforced both client- and server-side. (website/lib/quotas.ts)
  • Screenshot trim picker
    when a report has more than 5 screenshots, a modal lets the user choose which 5 to upload (numbered selection, max-cap, grid view). Cancel preserves local report unchanged. (src/ui/screenshot-trim-modal.ts)
  • 2-min video duration cap for cloud uploads
    with warnings at 1:30 and 1:55, auto-stop at 2:00. Local recording stays uncapped if shareReport() is never called. (src/video-recorder.ts)
  • Pre-upload sanitization
    strips Authorization headers, password fields, and common token shapes (JWT, OpenAI sk-, Stripe, GitHub PAT, AWS keys, Slack tokens, Google API keys) from network logs, console output, and URLs before anything leaves the browser. Local download path keeps the unsanitized original. (src/sanitize/cloud-upload.ts)
  • Dashboard at /dashboard
    Jam.dev-style sidebar + grid layout with quota bars, real thumbnail previews (320×180 JPEG generated from the first screenshot or video frame at upload time), Copy / Extend +14d / Delete actions, video / screenshot filters, search. (website/app/dashboard/*)
  • Public viewer at /share/[token]
    no login required. Server fetches via service-role client with 5-min signed download URLs; renders report in sandboxed <iframe srcdoc>. OG tags so links unfurl in Slack/Teams. (website/app/share/[token]/page.tsx)
  • 14-day default retention
    , user-extendable +14d per click. Nightly pg_cron soft-deletes expired rows; hourly Netlify cron purges Storage objects. (website/supabase/migrations/0001_initial.sql, website/app/api/cron/purge-expired/route.ts)
  • Chrome extension popup gets a cloud account block
    shows signed-in email + quota (🎥 X/5 · 📸 Y/10), Sign-in button when out, dashboard link, sign-out. Reads endpoint from chrome.storage.local.tracebug_cloud_endpoint (default: production). (tracebug-extension/popup.{html,js})
  • CORS middleware
    echoes Access-Control-Allow-Origin for chrome-extension:// and moz-extension:// origins on /api/*. (website/middleware.ts)
  • docs/SHARE-PORTAL-PLAN.md
    the full design spec for the cloud sharing portal (architecture, quotas, RLS, files-changed, deployment, security checklist).
  • docs/PROJECT-CONTEXT.md
    single-doc orientation for agents/contributors picking up the project cold.
  • New table public.sessions with RLS policies (sessions_select_own / _insert_own / _update_own / _delete_own).
  • New Storage RLS on storage.objects for the reports bucket — users can only PUT/GET/DELETE under their own <user_id>/ folder.
  • New pg_cron job tracebug-expire-shares runs daily at 03:00 UTC.
  • Refactored src/exporters/html-replay.ts to extract buildReplayPayload() so the local download and cloud upload paths share the same assembly logic — touching one updates both.
  • Fixed pre-existing bug in src/video-recorder.ts where in-page recordings were silently dropped: isUsableRecording() required a dataUrl that the in-page path never generated. Now FileReader-encodes the blob → base64 dataUrl before stashing.
  • Fixed pre-existing bug where browser-native "Stop sharing" didn't trigger the toolbar UI reset (only the SDK's own Stop button did). The in-page track.ended handler now fires _onAutoStop callback too.
  • Fixed pre-existing build break in src/exporters/html-template.ts where unescaped backticks inside a comment inside a template literal confused esbuild.
Phase 5 — Console tab → unified event feed
    Phase 5 — Console tab → unified event feed
    • Console tab is now a unified, chronological event feed
      (matches Jam.dev's mental model). One scrollable story per session: console logs of every level, page navigations, network errors, user clicks/inputs/selects/submits, and video start/stop markers — all merged and sorted by timestamp.
    • Six category-filter pills
      above the list — All / Console / Page navigations / Network errors / User activity / Video — with live counts. Pills hide categories that have zero entries. Existing search input + "Errors only" toggle still apply.
    • Per-row layout
      48 px elapsed-time gutter (m:ss) | 24 px SVG category icon | message text + optional collapsed stack trace. Replaces the old card-style log entries.
    • Category-aware coloring
      navigation rows tinted info-blue, network errors tinted error-red, console errors red text, console warnings amber, video markers in accent.
    • Mirrored in the HTML export
      ([src/exporters/html-template.ts](src/exporters/html-template.ts)) — viewers reviewing an exported .html see the same unified feed with the same six pills and same filter behavior.
    Phase 4 — Video recording stabilization
    • Empty video field in exports.
      Multi-MB recording dataUrls were silently truncated by chrome.runtime.sendMessage (it drops responses >10 MB or so). The exported HTML had everything except the video bytes. Now the offscreen writes the recording into chrome.storage.local via the background service worker (which always has storage access), the content-script reads it back, and re-attaches the dataUrl to the page-side response. IPC carries metadata only. (tracebug-extension/offscreen.js, background.js, content-script.js)
    • dataUrlToBlob rejected valid base64.
      Splitting on the first , was wrong because mime types can contain commas (e.g. video/webm;codecs=vp9,opus). Switched to splitting on the literal ;base64, marker. The atob failure was the actual root cause of every previous empty-video export and the NotSupportedError on play. (src/video-recorder.ts)
    • tb:rec:auto-stopped broadcast dead-coded.
      The generic tb:rec:* handler in background.js was registered before the dedicated auto-stop handler, so the latter never ran. Reordered so tb:rec:auto-stopped matches first. (tracebug-extension/background.js)
    • content-script.js re-injection crashed
      with SyntaxError: Identifier 'REC_DATA_KEY' has already been declared. Wrapped the whole script in a window.__TRACEBUG_CS_LOADED__ guard so re-injection is a no-op. (tracebug-extension/content-script.js)
    • Double share-picker.
      Two concurrent startVideoRecording calls both passed the isActive() check (recorder doesn't exist yet — getDisplayMedia is in flight) and showed the picker twice. Added _startInFlight coalescing on both SDK and offscreen sides. (src/video-recorder.ts, tracebug-extension/offscreen.js)
    • Recording lost on page reload.
      When the recording tab navigated and Chrome ended the share, the SDK's reinit cleared the stale sessionId flag but didn't recover the finalized recording. Added a recovery path that pulls _lastBuiltRecording from the offscreen on init. (src/index.ts)
    • Auto-stop finalize race.
      The video track's ended event and the MediaRecorder's stop event raced; the early bail on isActive() could miss the broadcast. Removed the bail and added _autoStopBroadcast dedup so finalize fires exactly once regardless of which signal arrives first. (tracebug-extension/offscreen.js)
    • In-modal play threw NotSupportedError.
      v.play() returns a Promise that rejects on no-supported-sources, and the surrounding sync try/catch couldn't catch it. Added a .catch() that falls back to event-only timeline playback. (src/ui/replay-scrubber.ts)
    • Switched from silent chrome.tabCapture to getDisplayMedia picker.
      Tab capture's silent-record path failed on many sites (cross-origin, sandboxed iframes, chrome:// URLs) and produced recordings the modal couldn't play back. The picker is more reliable, lets the user record any tab / window / screen, and the surfaceSwitching: "include" option keeps the recording alive through tab navigation. (tracebug-extension/offscreen.js)
    • Recording HUD now has a "Draw" button
      that toggles the existing draw-mode (rect / ellipse / redact, 5 colors) while recording continues. HUD slides down to top: 64px so it doesn't collide with the draw toolbar. (src/ui/recording-hud.ts)
    • hydrateRecording is non-throwing.
      Even if atob fails for any reason, the recording is still returned with the dataUrl preserved, so the export still embeds the video. (src/video-recorder.ts)
    • isUsableRecording gate.
      revokeAndStash no longer overwrites a real recording with an empty stub. The auto-stop broadcast and manual stop both go through this check before storing. (src/video-recorder.ts)
    • Manifest:
      added unlimitedStorage permission for large recordings. (tracebug-extension/manifest.json)
    Phase 3 — UI overhaul + parity work
    • Minimal popup
      with one hero CTA ("Capture Bug Now") plus secondary "Record session" / "View tickets" buttons. The old toggle + 6 quick-action grid + active-sites list are gone. Three actions, three clicks max from "I see a bug" to "report filed".
    • Lazy SDK injection
      the SDK no longer loads until the user clicks a popup action. No persistent allowlist, no auto-inject on page load. Tracking is fully opt-in per session. (tracebug-extension/background.js, popup.js)
    • Silent tab capture (later replaced — see Phase 4)
      initial implementation used chrome.tabCapture.getMediaStreamId to avoid the share picker. Phase 4 reverted this to getDisplayMedia for reliability.
    • Quick Bug modal tabbed layout
      two-pane (replay left, tab strip right) with Info | Console | Network | Actions | AI | Notes tabs. Each renders real data from the BugReport. Theme toggle (🌗) in header. (src/ui/quick-bug.ts)
    • Action chips
      Actions tab renders chips with verb + HTML element preview (<button class="play-btn" type="button"> +1 more) and theme-aware syntax coloring. New module src/action-chips.ts, new BugReport.actionChips field. Text exports (GitHub/Jira/markdown) still use plain sessionSteps[].
    • Full network capture
      Network tab shows ALL requests, not just failures. New NetworkRequestEntry type + BugReport.networkRequests field. Color-coded 2xx/3xx/4xx/5xx/err status badges. (src/types.ts, src/report-builder.ts)
    • Linear integration
      src/linear-issue.ts opens https://linear.app/new?title=...&description=... with prefilled markdown.
    • Slack export
      src/slack-export.ts returns Slack-flavored text (*bold*, code blocks, > quotes) for clipboard paste.
    • Redact (blur) tool
      third shape type in draw mode, solid hatched block, no comment prompt. (src/draw-mode.ts, src/types.ts)
    • HTML export tabbed layout + dual-theme
      standalone replay file mirrors the modal layout with Info | Console | Network | Actions | AI | Notes | Events | Description tabs. Both palettes embedded as CSS variables; auto-switches via prefers-color-scheme, manual override via in-header 🌗 toggle saved per file in localStorage. (src/exporters/html-template.ts, src/exporters/html-replay.ts)
    • Theme toggle in modal header
      cycles ☀ light → 🌙 dark → 🌗 auto. Per-origin preference saved in localStorage.tracebug_theme_pref, picked up on next SDK init. (src/ui/quick-bug.ts, src/index.ts)
    • Smarter dashboard search
      renderFilteredSessions() now also matches click text, input values, aria-labels, repro steps, request URLs — not just sessionId + errorMessage. (src/dashboard.ts)
    • Theme palette refresh
      softer zinc + violet ramps replacing navy + cyan. New syntax-highlighting tokens (--tb-code-tag, --tb-code-attr-name, --tb-code-attr-val, --tb-code-text, --tb-code-bg) so HTML element previews adapt to light/dark. Default mode changed from "dark" to "auto". (src/theme.ts, src/index.ts:254)
    • Modal CSS polish
      more generous padding, real hover backgrounds (button lifts instead of dimming opacity), pill badges (border-radius 999px), refined focus rings, custom theme-aware scrollbar, larger radii, -0.01em letter-spacing on titles. (src/ui/quick-bug.ts_injectStyles())
    • Popup enable flow no longer reloads
      the tab. SDK injects in-place via chrome.scripting.executeScript. User keeps current page state. (tracebug-extension/popup.js, background.jsINJECT_SDK_NOW handler)
    • Badge now reflects "SDK loaded on tab"
      rather than "site enabled". Clears automatically on tab reload (since injectedTabs is wiped). (tracebug-extension/background.js)
    • "Jam" references removed
      from all source comments. 17 mentions replaced with neutral wording.
    • Persistent enabled-sites allowlist (getEnabledSites / saveEnabledSites / isSiteEnabled / toggleSite and the TOGGLE_SITE / CHECK_SITE message handlers).
    • Auto-injection on page navigation.
    • Popup's 6 quick-action buttons (Annotate / Draw / Screenshot / PDF Report / GitHub Issue / Jira Ticket) — they duplicated the on-page toolbar.
    • Popup's Enable / Disable toggle row — replaced with informational hint.
    • console.error wrapper (in src/collectors.ts:collectErrors()) adds a frame at the top of every console.error stack trace once the SDK is loaded. Trace shows tracebug-sdk.js as the topmost frame; the actual caller is the line below. Fix candidates: install the wrapper only during active recording, add //# sourceURL= magic comment, or default captureConsole to "none".
    Added — Sentry Mode (Rolling Video Buffer)
    • New module: src/video-recorder.ts
      wraps getDisplayMedia + MediaRecorder. Supports two modes: - mode: "rolling" (default) — recording continues across captures; captureRollingBuffer() snapshots the in-progress recording into a finished VideoRecording while the screen-share keeps running. - mode: "standard" — classic record-then-stop flow.
    • New module: src/ui/recording-hud.ts
      floating pill with pulsing red dot, elapsed timer, "captures taken" counter, comment input (timestamped to recording time, Enter to save), 📸 Capture button (rolling mode only), and ⏹ Stop. Defensive CSS injected with !important to defeat host-page resets (Tailwind preflight, etc.).
    • Auto-capture on error
      when an unhandled error fires *and* a rolling session is armed, the existing error toast offers "Capture with video" instead of "Capture bug." One click captures the buffer + opens the ticket modal.
    • Smart Stop
      if the user already filed tickets via Capture, Stop ends silently with a toast. If no captures were taken, Stop opens the modal with the full recording (preserves the simple one-shot flow).
    • Public API:
      TraceBug.startVideoRecording({ mode?, withMicrophone?, onStatus? }) - TraceBug.stopVideoRecording(): Promise<VideoRecording | null> - TraceBug.captureRollingBuffer(): Promise<VideoRecording | null> - TraceBug.isVideoRecording() / isRollingMode() / getCaptureCount() - TraceBug.getLastVideoRecording() - downloadVideoRecording(rec, filename?) (named export)
    • Toolbar:
      new red Record button (between Region Screenshot and the right edge). Only enabled when the browser supports getDisplayMedia.
    • Exports updated:
      GitHub issue, Jira ticket, and PDF report now include a "Screen Recording" section listing the auto-downloaded .webm filename, duration, file size, and any timestamped comments. Every export action auto-downloads the .webm alongside screenshots.
    • Comments reset on capture
      each ticket gets its own set of timestamped comments. Comments accumulate during the recording; capturing snapshots them into the recording and clears the buffer for the next bug.
    Added — Auto-Scanner (Phase 2)
    • New runtime dep: axe-core@4.11.4
      ~1.4 MB, lazy-loaded via import("axe-core") so the base bundle stays light. Only loaded the first time scanPage() is called. Extension IIFE bundle grew from 770 KB → 2.17 MB.
    • New module: src/scanner/index.ts
      orchestrator. Runs all detectors in parallel via Promise.all + per-detector catch wrapper (one failure doesn't block the others). Concurrent scan() calls are coalesced. Issues live in memory only — each scan is a fresh run, results clear on reload.
    • New module: src/scanner/helpers.ts
      shared selector builder (id → data-testid → tag+nth-of-type chain), severity coercion, ID generator.
    • Detectors
      (one file each in src/scanner/detectors/): - a11y.ts — axe-core, restricted to WCAG 2.0/2.1 A+AA rules (skips noisy best-practice). Multi-element violations roll into one issue with a (+ N more) suffix. - broken-images.ts<img> where naturalWidth === 0 && complete === true. - mixed-content.tshttp:// resources on HTTPS pages. Covers img, script, iframe, link[rel=stylesheet|preload|prefetch|manifest|icon], audio, video, source, embed, object. - session-data.ts — three detectors that classify already-collected session data: console-error (deduped by message), failed-request (4xx/5xx/network-error with response snippets), slow-api (successful requests over 2s).
    • New module: src/ui/issues-panel.ts
      modal grouped by severity. Defensive CSS with !important rules. Locate scrolls into view + outlines the element with a 2.4s purple flash. File Ticket pre-fills the Quick Bug modal via the new prefilledTitle / prefilledDescription options on showQuickBugCapture().
    • New types in src/types.ts:
      Issue, IssueDetector ("axe-a11y" | "broken-image" | "mixed-content" | "console-error" | "slow-api" | "failed-request"), IssueSeverity ("critical" | "serious" | "moderate" | "minor").
    • Public API:
      TraceBug.scanPage(): Promise<ScanResult> - TraceBug.showIssuesPanel({ rescan? }) — runs a fresh scan first by default - TraceBug.getIssues({ includeDismissed? }) - TraceBug.dismissIssue(id) / undismissIssue(id) / clearIssues() - TraceBug.getIssue(id) / getIssueCounts() (severity-bucketed counts) - Named exports: scan, getIssues, dismissIssue, etc.
    Changed — UX Cleanup (v1.0 polish pass)
    • Toolbar reduced from 10 → 6 elements:
      Logo · ⚡ Quick Bug · 🔍 Scan · 📷 Screenshot · ⬚ Region · 🔴 Record. Removed: standalone recording-state dot, Annotate button, Draw button, Annotation List button + badge, Settings card button, Help button.
    • Quick Bug modal exports reduced from 5 → 3:
      Open in GitHub · Copy as GitHub · Copy as Jira. Removed: Copy as Plain Text (GitHub markdown is pasteable anywhere), Download Screenshots (every export already auto-downloads them).
    • First-run onboarding tour removed.
      Most users skipped it. Logo pulse retained as a subtle "we're here" hint; button tooltips are the only discovery aid.
    • Source files retained for all cut features.
      src/element-annotate.ts, src/draw-mode.ts, src/onboarding.ts, src/pdf-generator.ts still ship in the bundle and remain accessible programmatically — TraceBug.activateAnnotateMode(), TraceBug.activateDrawMode(), TraceBug.downloadPdf(), replayOnboarding(). Only the default UI surface changed.
    • shortcuts.annotate and shortcuts.draw config keys retained
      in the TraceBugConfig type for backwards compatibility. They're now no-ops since the corresponding toolbar buttons aren't mounted.
    • Build artifacts:
      Extension IIFE 2.17 MB (axe-core dominates). npm DTS 32 KB. All 74 tests pass.
    Added — Freemium Plan
    • New module: src/plan.ts
      getPlan(), isPremium(), setPlan(), hydratePlan(), FREE_LIMITS. Plan exposed on the SDK singleton and as named exports.
    • New module: src/ui/upgrade-modal.ts
      minimal centered modal with a placeholder "Upgrade — Coming Soon" CTA and a dev-only toggle for flipping the plan flag locally.
    • Gates:
      Screenshots — free users capped at 2 per ticket (FREE_LIMITS.screenshots). Both takeScreenshot() and takeRegionScreenshot() return null and show the upgrade modal at the cap. Toolbar buttons enforce the same. - PDF exportTraceBug.downloadPdf() opens upgrade modal; no PDF is generated. - Jira ticketTraceBug.getJiraTicket() returns null and opens upgrade modal. The Quick Bug modal renders the Jira button as 🔒 Jira Ticket (Premium) (muted) for free users; premium gets the blue 🎫 Copy as Jira Ticket. - Advanced metadataconsoleErrors and networkErrors arrays in the generated report are blanked out for free users. Capture still happens (cheap); only the export is redacted. - Custom branding — new companyName config option, ignored on free. On premium, every export is prefixed with > _Reported via TraceBug — {companyName}_.
    • UI surfaces:
      Toolbar settings card now shows a Free Plan / ✨ Premium badge next to the screenshot count (clickable; opens upgrade modal). Screenshot count line shows N / 2 cap on free. - Quick Bug modal footer shows the same badge alongside "Draft auto-saved".
    • Dev toggle
      the upgrade modal exposes a small Dev: enable Premium button so testers can flip the flag without redeploying. Persists across sessions.
    • Backwards compat:
      getJiraTicket() and downloadPdf() previously always succeeded for any caller; they now return null / open the modal for free users. Existing premium-equivalent flows (programmatic generateGitHubIssue, etc.) are unchanged.
    Changed — Ticket-First Capture Flow
    • Toolbar Screenshot button
      captures a full-viewport screenshot and stores it in the ticket. Toast: "Added to ticket · N screenshots". No file is written to disk.
    • Toolbar Region Screenshot button
      same flow: drag-to-crop, store in the ticket, no download.
    • TraceBug.stopRecording()
      pauses recording and auto-opens the ticket-review modal so the user sees every step + every screenshot before exporting.
    • Ticket-review modal
      (the renamed Quick Bug modal — title is now "Bug Ticket — Review & Export"): - Renders all screenshots in the active ticket as a numbered thumbnail strip below the primary preview. - Click any thumbnail to swap it into the primary preview. - Header shows screenshot count (e.g. "3 screenshots attached · download/copy includes all screenshots").
    • Bulk export
      every export action (Open in GitHub, Copy as GitHub Issue, Copy as Jira Ticket, Copy as Plain Text, Download Screenshots) downloads every screenshot in the ticket, staggered 120ms apart so the browser doesn't drop concurrent downloads.
    • Toast labels updated to reflect the count, e.g. "✓ Copied as Jira Ticket · downloading 3 screenshots".
    Added — Region Screenshot (Snipping Tool)
    • TraceBug.takeRegionScreenshot()
      drag-to-select-area screenshot. Shows a fullscreen overlay with a translucent dim layer; user drags a rectangle; the cropped PNG is pushed to getScreenshots(). Press Esc to cancel. - Reuses the existing captureScreenshot() pipeline, so it inherits chrome.tabs.captureVisibleTab in extension context and the html2canvas fallback in plain-SDK context — no new dependencies. - Crops via canvas with DPR-aware scaling (naturalWidth / window.innerWidth). - Returns null if the user presses Esc or selects a region smaller than 5×5 px. - New module: src/region-screenshot.ts - New export: captureRegionScreenshot
    • Toolbar button
      a corner-square icon next to the existing camera, tooltip "Region Screenshot — drag to select, added to ticket".
    • Overlay carries data-tracebug="region-overlay" so the existing isTraceBugElement filter ignores its own clicks.
    Added — Recording Aliases
    • TraceBug.startRecording()
      alias for resumeRecording(). Semantic only; behavior is unchanged.
    • TraceBug.stopRecording()
      calls pauseRecording() and auto-opens the ticket-review modal. The modal flow above is the only behavioral difference from pauseRecording().
    v1.3.0
    2026-04-13
    Added — Debugging Assistant
    • 🔍 Root Cause Hint Engine
      every report now leads with a one-line, confidence-tiered cause hint. Deterministic, no AI APIs. - HIGH — when a failed network request is present: "API POST /orders failed with 500 after clicking 'Place Order'" - MEDIUM — when only a runtime error is present: "TypeError suggests undefined/null data — the response or upstream value was likely missing" - LOW — click without downstream signal: "Click on 'Submit' did not trigger any observable effect" - Injected at the top of GitHub issues, Jira tickets, PDF reports, and the Quick Bug modal - New exports: generateRootCauseHint(report), formatRootCauseLine(rc) - New type: RootCauseHint { hint, confidence }
    • 🧠 Smart Bug Summary
      one-sentence TL;DR derived from network + error + click + page signals. Rendered as a blockquote on GitHub, a {panel} on Jira, and an indigo banner on PDF. - Example: "API POST /orders failed with 500 when clicking 'Place Order' button on /checkout" - New export: generateSmartSummary(report)
    • 🧩 Session Steps
      last ~10 user actions converted to plain-English strings ("Clicked 'Edit' button", "Navigated to /checkout"). FIFO queue. Injected as a numbered list in all exports. - New export: generateSessionSteps(events)
    • 🎯 Clicked Element snapshot
      structured { tag, text, selector, id, ariaLabel, testId, page } for the last click before the bug. Surfaced as a User clicked: line in exports. - New export: extractClickedElement(events) - New type: ClickedElementSummary
    Added — Network Failure Capture
    • Response body snippets
      first 200 chars of every failed fetch or XHR response, captured asynchronously after the response returns (never blocks the request). - Rendered as a collapsible <details> block in GitHub, h4. Response Snippets on Jira, monospace blocks in PDF - Fetch path clones the response and reads text on a microtask tick — the caller gets the response unchanged - XHR path reads responseText on loadend only for status >= 400 || status === 0
    • Last-10 failures ring buffer
      in-memory FIFO, ~2KB steady state, cleared on destroy() and on "Clear All Data" - New export: getNetworkFailures() and TraceBug.getNetworkFailures() - New types: NetworkFailure, NetworkErrorEntry (with optional response field)
    Fixed — Session & Data Integrity
    • Clear All Sessions was silently undone by the pending flush
      after clicking "Clear All Data", the next event re-wrote the stale in-memory cache back to localStorage. Now clearAllSessions() cancels any pending flush and drops the cache before wiping storage.
    • Deleted sessions could resurrect themselves
      deleteSession(id) now invalidates the cache; pending flushes can't re-save the deleted row.
    • Race between flush queue and mutator writes
      updateSessionError, addAnnotation, saveEnvironment previously read from localStorage, ignoring newer events in the pending cache; their writes then overwrote the cache on flush. All three now read through the cache and call scheduleFlush().
    • Network failure buffer leaked across cleared sessions
      buildReport() now filters buffer entries by timestamp >= session.createdAt so a fresh session cannot inherit failures from a cleared one.
    Changed
    • "Clear All Data" now actually clears everything
      sessions + screenshots + voice transcripts + element annotations + annotation badges + network failure buffer. Applied to both the dashboard panel's Clear button and the compact toolbar's settings card. Confirm dialog updated to list what's being wiped.
    • Every report starts with root cause + TL;DR
      GitHub issues, Jira tickets, PDF reports, and Quick Bug modal descriptions all lead with these two lines so a reader understands the bug without scrolling.
    v1.2.0
    2026-04-09
    Added — API
    • TraceBug.quickCapture()
      one-shot bug capture flow: screenshot + auto-filled modal + 1-click copy to GitHub/Jira/Text. Keyboard shortcut: Ctrl+Shift+B. Cuts bug reporting from ~7 clicks to 2.
    • TraceBug.setUser({ id, email, name })
      identify users for session attribution, persisted in localStorage
    • TraceBug.getUser() / TraceBug.clearUser()
      query and clear identified user
    • TraceBug.markAsBug()
      flag current session as a bug (adds isBug: true)
    • TraceBug.getCompactReport()
      2-sentence Slack-friendly summary of the session
    • TraceBug.getErrorCount() / TraceBug.exportSessionJSON()
      CI/CD integration helpers
    • TraceBug.use(plugin) / TraceBug.removePlugin(name)
      plugin registration API
    • TraceBug.on(event, callback)
      subscribe to lifecycle hooks (session:start, error:captured, screenshot:taken, report:generated, etc.)
    • TraceBugUser type
      exported
    • takeScreenshot({ includeAnnotations })
      option — capture page with annotation badges visible
    Added — Features
    • Theme system
      dark/light/auto themes with 45+ CSS custom property design tokens, follows prefers-color-scheme in auto mode
    • Configurable toolbar position
      toolbarPosition: 'right' | 'left' | 'bottom-right' | 'bottom-left'
    • Draggable toolbar
      drag to any position, persisted in tracebug_toolbar_pos localStorage key
    • Mobile FAB mode
      viewport < 768px collapses toolbar to a single floating action button; panel becomes full-width bottom sheet
    • First-run onboarding
      4-step tooltip tour shown once, "?" help button on toolbar to replay
    • Console capture levels
      captureConsole: 'errors' | 'warnings' | 'all' | 'none' (new event types: console_warn, console_log)
    • Tab-based session detail
      Overview / Timeline / Errors / Export tabs with sticky header (bug title + severity badge)
    • Session search & filter
      search by error message, URL, or session ID; filter by all/errors/healthy
    • Session auto-naming
      sessions named by primary page (e.g., "Login Session")
    • Toast notifications
      visual feedback for actions with aria-live announcements for screen readers
    • Clickable annotation badges
      numbered badges on annotated elements open a popover with intent, severity, and comment
    • Screenshots in annotation list panel
      alongside element annotations and draw regions, with inline previews and per-item download
    • Screenshot auto-download
      screenshots and "Save Annotated" auto-download PNG files to the user's system
    • Extension screenshot via chrome.tabs.captureVisibleTab
      replaces html2canvas in the Chrome Extension for CORS-safe captures
    • CLI tool
      npx tracebug init auto-detects framework (React, Next.js, Vue, Angular, Svelte, Nuxt, vanilla) and prints setup snippet
    • Custom keyboard shortcuts
      shortcuts: { screenshot, annotate, draw } config option
    Added — Website & SEO
    • Chrome Web Store publication
      one-click install at chromewebstore.google.com/detail/fdemmibikigigkfjngclmdheeajhdgaj
    • Cross-browser support docs
      Chrome, Edge, Brave, Opera (Chrome Web Store); npm SDK for Firefox/Safari
    • 4 programmatic SEO pages
      /compare/sentry-alternative, /compare/logrocket-alternative, /compare/bugsnag-alternative, /compare/frontend-bug-reporting-tool
    • Sitemap.xml + robots.txt
      via Next.js metadata API
    • JSON-LD structured data
      (SoftwareApplication schema) in root layout
    • Per-page metadata
      unique title/description/OG for docs page
    • OG image
      PNG via Next.js ImageResponse route (replaces SVG that social platforms couldn't render)
    • Security headers
      X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy in next.config.js
    • Scroll-reveal animations
      IntersectionObserver-based with prefers-reduced-motion respect
    • Mobile-responsive comparison table
      card layout on < md viewports
    Added — Infrastructure
    • Config validation
      runtime checks on init() (projectId required, maxEvents/maxSessions must be positive); invalid values warn and fall back to defaults
    • OSS infrastructure
      CONTRIBUTING.md, CHANGELOG.md, .github/ISSUE_TEMPLATE/ (bug_report.md, feature_request.md), .github/workflows/ci.yml
    • README badges
      npm version, monthly downloads, GitHub stars, MIT license
    • ui/ module directory
      extracted dashboard helpers (helpers.ts, toast.ts, index.ts) from the 2000-line dashboard.ts
    Fixed
    • Global error boundary
      entire init() body + all collectors + dashboard mount wrapped in try/catch; SDK never crashes host app
    • Resilient fetch/XHR wrappers
      original function ALWAYS called even if tracking throws; handles Request objects, URL objects, strings
    • Footer privacy link
      changed from # to /privacy
    • Docs page metadata
      unique title/description instead of falling back to root layout
    Changed
    • All UI components migrated from hardcoded colors to CSS custom properties (var(--tb-*))
    • Collectors hardened with try/catch — never break host app event handling
    • html2canvas pinned to exact version 1.4.1 (removed caret range)
    v1.1.1
    2026-03-12
    Initial Public Release
    • Session recording (clicks, inputs, navigation, API calls, errors)
    • Screenshot capture with annotation editor (rectangles, arrows, text)
    • Voice bug descriptions via Web Speech API
    • Element annotation mode (click elements to attach feedback)
    • Draw mode (rectangles/ellipses on live page)
    • GitHub Issue and Jira Ticket export (one-click copy)
    • PDF report generation
    • Auto-generated reproduction steps
    • Auto bug title and flow summary
    • Environment detection (browser, OS, viewport, device, connection)
    • Privacy: passwords, credit cards, SSNs, tokens auto-redacted
    • Framework noise filtering (Next.js, Webpack, Vite, Turbopack)
    • Chrome Extension (Manifest V3, CSP-safe injection)
    • npm package with ESM + CJS + IIFE + TypeScript declarations