browsertrack 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/AGENTS.md +6 -2
  2. package/dist/{chunk-ILRYKMME.js → chunk-3HOXPTM2.js} +97 -3
  3. package/dist/chunk-3HOXPTM2.js.map +1 -0
  4. package/dist/{chunk-G2Y3CXCY.js → chunk-464D4U2U.js} +86 -3
  5. package/dist/chunk-464D4U2U.js.map +1 -0
  6. package/dist/{chunk-SPCIROIU.js → chunk-7OCOQGDN.js} +24 -5
  7. package/dist/chunk-7OCOQGDN.js.map +1 -0
  8. package/dist/{chunk-SKCMT2DE.js → chunk-INXDWPJW.js} +806 -160
  9. package/dist/chunk-INXDWPJW.js.map +1 -0
  10. package/dist/cli/index.js +202 -6
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/client/index.cjs +809 -161
  13. package/dist/client/index.d.ts +62 -11
  14. package/dist/client/index.js +7 -3
  15. package/dist/client.iife.js +206 -27
  16. package/dist/{notes-CBvN91Wf.d.ts → commands-fjuqKzkm.d.ts} +125 -91
  17. package/dist/core/index.d.ts +2 -2
  18. package/dist/daemon/index.d.ts +3 -3
  19. package/dist/daemon/index.js +2 -2
  20. package/dist/{engine-CeT9URuN.d.ts → engine-CmchnMDq.d.ts} +13 -2
  21. package/dist/index.d.ts +4 -4
  22. package/dist/index.js +4 -4
  23. package/dist/mcp/index.d.ts +4 -4
  24. package/dist/mcp/index.js +2 -2
  25. package/dist/{projects-CY8ungMt.d.ts → projects-DB7S312i.d.ts} +1 -1
  26. package/dist/{server-Dd8NX2Mk.d.ts → server-DiVmTrIR.d.ts} +1 -1
  27. package/docs/component-resolver.md +108 -0
  28. package/docs/index.md +3 -1
  29. package/docs/mcp-reference.md +15 -2
  30. package/docs/scenarios-flows.md +86 -0
  31. package/docs/visual-notes.md +36 -0
  32. package/package.json +1 -1
  33. package/packages/client/src/client.ts +18 -1
  34. package/packages/client/src/config.ts +84 -1
  35. package/packages/client/src/index.ts +4 -1
  36. package/packages/client/src/interceptors/interaction.ts +3 -0
  37. package/packages/client/src/notes/inspector.ts +640 -166
  38. package/packages/client/src/source/resolver.ts +272 -0
  39. package/packages/core/src/types/events.ts +3 -0
  40. package/packages/core/src/types/notes.ts +36 -0
  41. package/packages/daemon/src/notes/engine.ts +6 -0
  42. package/packages/daemon/src/server/ws.ts +23 -1
  43. package/packages/daemon/src/storage/db.ts +106 -3
  44. package/packages/mcp/src/handlers.ts +59 -0
  45. package/packages/mcp/src/tools.ts +28 -0
  46. package/test/client/component-resolver.test.ts +141 -0
  47. package/test/client/interceptors.test.ts +120 -0
  48. package/test/daemon/scenario-storage.test.ts +158 -0
  49. package/dist/chunk-G2Y3CXCY.js.map +0 -1
  50. package/dist/chunk-ILRYKMME.js.map +0 -1
  51. package/dist/chunk-SKCMT2DE.js.map +0 -1
  52. package/dist/chunk-SPCIROIU.js.map +0 -1
@@ -64,4 +64,40 @@ The bottom-right floating toolbar gives quick access:
64
64
  - **`🎯 Element`**: Toggle element inspection mode.
65
65
  - **`📐 Region`**: Activate rectangle drag mode.
66
66
  - **`📄 Page`**: Open full-page note modal.
67
+ - **`🎬 Flow`**: Start/finish sequential scenario recording.
67
68
  - **`📌 Notes (N)`**: Toggle visibility of all note markers on screen.
69
+
70
+ ---
71
+
72
+ ## 🙈 Hiding the Tool via Query String (Headless / Clean Mode)
73
+
74
+ When running automated visual regression tests, Cypress, Playwright, or giving clean demo presentations, you can hide the visible BrowserTrack UI (dock, pins, overlays) completely using URL query parameters:
75
+
76
+ ### 1. Built-in Query Parameters
77
+ Simply append any of the following to your page URL:
78
+ - `?bt=0` or `?bt=false` or `?bt=hidden` or `?bt=off`
79
+ - `?browsertrack=false` or `?browsertrack=0` or `?browsertrack=hidden`
80
+ - `?no_bt` / `?no_bt=1` or `?no_browsertrack=1`
81
+ - `?hide_bt=1` or `?hide_browsertrack=1`
82
+
83
+ ```text
84
+ http://localhost:3000/dashboard?bt=false
85
+ ```
86
+
87
+ ### 2. Custom Query Parameter Configuration
88
+ You can also define your own custom query parameters in client options:
89
+ ```typescript
90
+ import { init } from 'browsertrack/client';
91
+
92
+ init({
93
+ hideQueryParam: ['cypress', 'clean_view', 'no_ui'],
94
+ // or hide by default in specific environments:
95
+ hidden: process.env.NODE_ENV === 'test',
96
+ });
97
+ ```
98
+
99
+ When hidden:
100
+ - The floating toolbar and on-screen note pins are not displayed.
101
+ - Alt+Click hover highlights and selection shortcuts are inactive.
102
+ - Background diagnostics (runtime errors, console capture, network logging, MCP command execution) continue working seamlessly in headless mode.
103
+ - Programmatic visibility can be restored anytime via `client.setUIVisible(true)`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browsertrack",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Local browser diagnostics + MCP bridge for coding agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,10 @@ import { WebSocketTransport } from './transport/websocket.js';
22
22
  import { NoteInspector } from './notes/inspector.js';
23
23
 
24
24
  export class BrowserTrackClient {
25
- public options: Required<Omit<BrowserDiagClientOptions, 'notes'>> & { notes: Required<NonNullable<BrowserDiagClientOptions['notes']>> };
25
+ public options: Required<Omit<BrowserDiagClientOptions, 'notes' | 'hideQueryParam'>> & {
26
+ hideQueryParam?: string | string[];
27
+ notes: Required<NonNullable<BrowserDiagClientOptions['notes']>>;
28
+ };
26
29
  private breadcrumbs: BreadcrumbBuffer;
27
30
  private transport: WebSocketTransport;
28
31
  private screenshotDriver: ScreenshotDriver;
@@ -56,6 +59,10 @@ export class BrowserTrackClient {
56
59
  this.inspector = new NoteInspector(this.transport, this.screenshotDriver, {
57
60
  shortcut: this.options.notes.shortcut,
58
61
  maskSelectors: this.options.notes.maskSelectors,
62
+ showToolbar: this.options.notes.showToolbar,
63
+ showBadges: this.options.notes.showBadges,
64
+ hidden: this.options.hidden,
65
+ hideQueryParam: this.options.hideQueryParam,
59
66
  });
60
67
  }
61
68
  }
@@ -142,6 +149,16 @@ export class BrowserTrackClient {
142
149
  }
143
150
  }
144
151
 
152
+ public isUIVisible(): boolean {
153
+ return this.inspector ? this.inspector.isVisible() : false;
154
+ }
155
+
156
+ public setUIVisible(visible: boolean): void {
157
+ if (this.inspector) {
158
+ this.inspector.setVisible(visible);
159
+ }
160
+ }
161
+
145
162
  public setInspectMode(mode: 'element' | 'region' | 'page' | 'idle'): void {
146
163
  if (this.inspector) {
147
164
  this.inspector.setMode(mode);
@@ -12,12 +12,25 @@ export interface BrowserDiagClientOptions {
12
12
  enabled?: boolean;
13
13
  shortcut?: string;
14
14
  showBadges?: boolean;
15
+ showToolbar?: boolean;
15
16
  maskSelectors?: string[];
16
17
  };
18
+ /**
19
+ * Hide visible BrowserTrack UI (toolbar dock, pins, hover overlay) by default.
20
+ */
21
+ hidden?: boolean;
22
+ /**
23
+ * Custom query parameter(s) used to hide the UI (e.g. 'e2e', 'no_ui', 'clean').
24
+ * Built-in query params like ?bt=0, ?bt=false, ?bt=hidden, ?browsertrack=false, ?no_bt are supported automatically.
25
+ */
26
+ hideQueryParam?: string | string[];
17
27
  debug?: boolean;
18
28
  }
19
29
 
20
- export const DEFAULT_OPTIONS: Required<Omit<BrowserDiagClientOptions, 'notes'>> & { notes: Required<NonNullable<BrowserDiagClientOptions['notes']>> } = {
30
+ export const DEFAULT_OPTIONS: Required<Omit<BrowserDiagClientOptions, 'notes' | 'hideQueryParam'>> & {
31
+ hideQueryParam?: string | string[];
32
+ notes: Required<NonNullable<BrowserDiagClientOptions['notes']>>;
33
+ } = {
21
34
  daemonUrl: 'ws://127.0.0.1:7331',
22
35
  projectId: '',
23
36
  maxBreadcrumbs: 50,
@@ -31,7 +44,77 @@ export const DEFAULT_OPTIONS: Required<Omit<BrowserDiagClientOptions, 'notes'>>
31
44
  enabled: true,
32
45
  shortcut: 'Alt+Click',
33
46
  showBadges: true,
47
+ showToolbar: true,
34
48
  maskSelectors: ['input[type="password"]', '[data-sensitive]'],
35
49
  },
50
+ hidden: false,
51
+ hideQueryParam: undefined,
36
52
  debug: false,
37
53
  };
54
+
55
+ const HIDE_VALUES = new Set(['0', 'false', 'hidden', 'hide', 'off', 'none', 'disabled', 'ui_off', 'silent']);
56
+
57
+ /**
58
+ * Checks if the tool's visible UI should be hidden based on URL search query parameters.
59
+ */
60
+ export function shouldHideUIFromUrl(customParam?: string | string[], searchString?: string): boolean {
61
+ let search = searchString;
62
+ if (search === undefined) {
63
+ if (typeof window === 'undefined' || !window.location) return false;
64
+ search = window.location.search;
65
+ }
66
+
67
+ if (!search) return false;
68
+
69
+ try {
70
+ const params = new URLSearchParams(search);
71
+
72
+ // 1. Check custom parameters if configured
73
+ if (customParam) {
74
+ const customKeys = Array.isArray(customParam) ? customParam : [customParam];
75
+ for (const key of customKeys) {
76
+ if (params.has(key)) {
77
+ const val = (params.get(key) || '').toLowerCase().trim();
78
+ if (val === '' || val === '1' || val === 'true' || HIDE_VALUES.has(val)) {
79
+ return true;
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ // 2. Boolean flags without values or with 1/true: ?no_bt, ?no_browsertrack, ?hide_bt, ?hide_browsertrack
86
+ for (const flag of ['no_bt', 'no_browsertrack', 'hide_bt', 'hide_browsertrack']) {
87
+ if (params.has(flag)) {
88
+ const val = (params.get(flag) || '').toLowerCase().trim();
89
+ if (val === '' || val === '1' || val === 'true' || val === 'yes') {
90
+ return true;
91
+ }
92
+ }
93
+ }
94
+
95
+ // 3. Value-based parameters: ?bt=false, ?bt=0, ?bt=hidden, ?bt=off
96
+ if (params.has('bt')) {
97
+ const val = (params.get('bt') || '').toLowerCase().trim();
98
+ if (HIDE_VALUES.has(val)) return true;
99
+ }
100
+
101
+ if (params.has('browsertrack')) {
102
+ const val = (params.get('browsertrack') || '').toLowerCase().trim();
103
+ if (HIDE_VALUES.has(val)) return true;
104
+ }
105
+
106
+ if (params.has('bt_ui')) {
107
+ const val = (params.get('bt_ui') || '').toLowerCase().trim();
108
+ if (HIDE_VALUES.has(val) || val === '0' || val === 'false') return true;
109
+ }
110
+
111
+ if (params.has('bt_hide')) {
112
+ const val = (params.get('bt_hide') || '').toLowerCase().trim();
113
+ if (val === '' || val === '1' || val === 'true') return true;
114
+ }
115
+ } catch {
116
+ // Defensive in non-standard environments
117
+ }
118
+
119
+ return false;
120
+ }
@@ -7,6 +7,7 @@ export * from './breadcrumbs.js';
7
7
  export * from './screenshot/driver.js';
8
8
  export * from './screenshot/browser-script-driver.js';
9
9
  export * from './notes/inspector.js';
10
+ export * from './source/resolver.js';
10
11
 
11
12
  let defaultClient: BrowserTrackClient | null = null;
12
13
 
@@ -40,9 +41,11 @@ if (typeof window !== 'undefined') {
40
41
  const autoInit = currentScript?.getAttribute('data-auto-init') !== 'false';
41
42
  const daemonUrl = currentScript?.getAttribute('data-daemon-url') || undefined;
42
43
  const projectId = currentScript?.getAttribute('data-project-id') || undefined;
44
+ const hidden = currentScript?.getAttribute('data-hidden') === 'true';
45
+ const hideQueryParam = currentScript?.getAttribute('data-hide-query-param') || undefined;
43
46
 
44
47
  if (autoInit) {
45
- init({ daemonUrl, projectId });
48
+ init({ daemonUrl, projectId, hidden, hideQueryParam });
46
49
  }
47
50
  } catch {
48
51
  // If auto-start fails, don't crash
@@ -1,5 +1,6 @@
1
1
  import type { Breadcrumb, ElementSummary } from '../../../core/src/index.js';
2
2
  import { getSemanticSelector, truncate } from '../../../core/src/index.js';
3
+ import { resolveComponentSource } from '../source/resolver.js';
3
4
 
4
5
  export type InteractionCallback = (breadcrumb: Breadcrumb, elementSummary?: ElementSummary) => void;
5
6
 
@@ -12,6 +13,7 @@ export function extractElementSummary(el: HTMLElement | Element): ElementSummary
12
13
  const tag = el.tagName.toLowerCase();
13
14
  const id = el.id || undefined;
14
15
  const classes = Array.from(el.classList || []);
16
+ const componentSource = resolveComponentSource(el as HTMLElement);
15
17
 
16
18
  let boundingRect: ElementSummary['boundingRect'] = undefined;
17
19
  let visible = true;
@@ -53,6 +55,7 @@ export function extractElementSummary(el: HTMLElement | Element): ElementSummary
53
55
  visible,
54
56
  innerText,
55
57
  outerHTML,
58
+ componentSource,
56
59
  };
57
60
  }
58
61