refinekit 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # reFiner
2
+
3
+ Leave visual feedback directly on any web page. Click an element, type what should change, and reFiner saves your notes as structured annotations that AI coding tools can read and act on.
4
+
5
+ ## What it does
6
+
7
+ 1. You add a single line to your HTML file
8
+ 2. A small toolbar appears on your page
9
+ 3. Click any element to leave a note about what should change
10
+ 4. Copy all your notes and paste them into an AI coding tool like [Claude Code](https://claude.com/claude-code) — it knows exactly which elements to fix
11
+
12
+ reFiner stays out of the way. It doesn't change your page's appearance or break any styles.
13
+
14
+ ## Getting started
15
+
16
+ ### Step 1: Add reFiner to your page
17
+
18
+ Open your HTML file and paste this line just before the closing `</body>` tag:
19
+
20
+ ```html
21
+ <script src="https://unpkg.com/refinekit/dist/refiner.js"></script>
22
+ ```
23
+
24
+ Your file should look something like this:
25
+
26
+ ```html
27
+ <!DOCTYPE html>
28
+ <html>
29
+ <head>
30
+ <title>My Page</title>
31
+ </head>
32
+ <body>
33
+ <!-- your page content here -->
34
+
35
+ <script src="https://unpkg.com/refinekit/dist/refiner.js"></script>
36
+ </body>
37
+ </html>
38
+ ```
39
+
40
+ ### Step 2: Open your page in a browser
41
+
42
+ Open the HTML file in Chrome, Safari, Firefox, or any modern browser. You'll see a small pen icon in the bottom-right corner — that's the reFiner toolbar.
43
+
44
+ ### Step 3: Start annotating
45
+
46
+ 1. Click the **pen icon** to expand the toolbar
47
+ 2. Click any element on the page — a heading, a button, an image, anything
48
+ 3. A dialog appears. Type what should change (e.g. "Make this font bigger" or "Change this color to blue")
49
+ 4. Click **Add** (or press `Cmd+Enter` on Mac / `Ctrl+Enter` on Windows)
50
+ 5. A numbered marker appears on the element
51
+
52
+ Repeat for as many elements as you'd like to annotate.
53
+
54
+ ### Step 4: Copy your annotations
55
+
56
+ Click the **copy icon** in the toolbar. All your annotations are copied to your clipboard as a formatted list, ready to paste into Claude Code or any AI coding assistant.
57
+
58
+ What gets copied looks like this:
59
+
60
+ ```
61
+ # Design Annotations — My Page Title
62
+
63
+ ## 1.
64
+ Element: body > main > h2
65
+ Issue: Make this font bigger and bolder
66
+
67
+ ## 2.
68
+ Element: #hero > .cta-button
69
+ Issue: Change this color to blue and add more padding
70
+ ```
71
+
72
+ The AI agent uses the element selectors to find and fix exactly the right elements in your code.
73
+
74
+ ## Toolbar guide
75
+
76
+ | Button | What it does |
77
+ |--------|-------------|
78
+ | Pen / X | Show or hide the toolbar |
79
+ | Number badge | Shows how many annotations you've added |
80
+ | Copy | Copy all annotations to clipboard |
81
+ | Trash | Remove all annotations |
82
+ | Gear | Open settings |
83
+
84
+ ### Settings
85
+
86
+ - **Marker Colour** — change the color of the numbered markers
87
+ - **Clear on copy** — automatically remove annotations after copying them
88
+ - **Block page interactions** — prevents you from accidentally clicking links or buttons while annotating (on by default)
89
+
90
+ ## Using reFiner with Claude Code
91
+
92
+ [Claude Code](https://claude.com/claude-code) is an AI coding tool that can read your reFiner annotations and make the changes for you.
93
+
94
+ ### Quick setup
95
+
96
+ If you already have Claude Code installed, just type:
97
+
98
+ ```
99
+ /refiner
100
+ ```
101
+
102
+ Claude Code will detect your project and add reFiner for you automatically.
103
+
104
+ ### Autonomous design critique
105
+
106
+ Want Claude to review your page's design on its own? Type:
107
+
108
+ ```
109
+ /refiner-self-driving
110
+ ```
111
+
112
+ Claude opens your page in a browser and drives through it like a design reviewer — clicking elements, adding expert feedback on typography, spacing, colors, and layout. You watch it work in real time.
113
+
114
+ ### Real-time sync with MCP
115
+
116
+ By default, you copy annotations and paste them into Claude Code. But you can skip the copy-paste entirely by running the reFiner MCP server:
117
+
118
+ ```bash
119
+ npx refinekit-mcp server
120
+ ```
121
+
122
+ Once running, annotations flow directly to Claude Code as you add them. The settings panel in reFiner will show "MCP Connected" to confirm the link is active.
123
+
124
+ To make this permanent in Claude Code:
125
+
126
+ ```bash
127
+ npx refinekit-mcp init
128
+ ```
129
+
130
+ ### Two-session workflow
131
+
132
+ The most powerful setup uses two Claude Code sessions at once:
133
+
134
+ 1. **Session 1** runs `/refiner-self-driving` — it reviews your page and adds design annotations
135
+ 2. **Session 2** watches for those annotations and fixes the code to address each one
136
+
137
+ You watch Session 1 critique the design while Session 2 implements the fixes — fully hands-free.
138
+
139
+ ---
140
+
141
+ ## Advanced
142
+
143
+ Everything below is for developers who want more control over reFiner.
144
+
145
+ ### npm install
146
+
147
+ ```bash
148
+ npm install refinekit
149
+ ```
150
+
151
+ ```js
152
+ import { Refiner } from 'refinekit';
153
+
154
+ const refiner = new Refiner();
155
+ ```
156
+
157
+ ### Configuration
158
+
159
+ #### Script tag attributes
160
+
161
+ ```html
162
+ <script
163
+ src="https://unpkg.com/refinekit/dist/refiner.js"
164
+ data-refiner-enabled="true"
165
+ data-refiner-position="right"
166
+ data-refinekit-mcp-enabled="true"
167
+ data-refinekit-mcp-port="4848"
168
+ ></script>
169
+ ```
170
+
171
+ | Attribute | Values | Default | Description |
172
+ |-----------|--------|---------|-------------|
173
+ | `data-refiner-enabled` | `true` / `false` | `true` | Whether to activate on load |
174
+ | `data-refiner-position` | `left` / `right` | `right` | Which side of the viewport |
175
+ | `data-refinekit-mcp-enabled` | `true` / `false` | `true` | Auto-discover MCP server |
176
+ | `data-refinekit-mcp-port` | number | `4848` | MCP server HTTP port |
177
+
178
+ #### Constructor options
179
+
180
+ ```js
181
+ const refiner = new Refiner({
182
+ enabled: true,
183
+ position: 'right',
184
+ mcpEnabled: true,
185
+ mcpPort: 4848,
186
+ });
187
+ ```
188
+
189
+ ### JavaScript API
190
+
191
+ The instance is available at `window.__refiner` when loaded via script tag.
192
+
193
+ ```js
194
+ const r = window.__refiner;
195
+
196
+ r.enable(); // show the toolbar and overlay
197
+ r.disable(); // hide everything
198
+ r.destroy(); // remove from DOM entirely
199
+
200
+ r.getAnnotations(); // returns Annotation[]
201
+ r.getAnnotationCount(); // returns number
202
+ r.formatForAgent(); // returns markdown string
203
+ r.copyAnnotations(); // copies markdown to clipboard
204
+ r.clearAnnotations(); // removes all annotations
205
+ ```
206
+
207
+ ### MCP server details
208
+
209
+ #### MCP tools
210
+
211
+ | Tool | Description |
212
+ |------|-------------|
213
+ | `refiner_list_sessions` | List all annotation sessions |
214
+ | `refiner_get_all_pending` | Get all unresolved annotations |
215
+ | `refiner_resolve` | Mark an annotation as resolved with a summary |
216
+ | `refiner_dismiss` | Dismiss an annotation with a reason |
217
+ | `refiner_watch_annotations` | Block until a new annotation arrives (for continuous watching) |
218
+
219
+ #### HTTP API
220
+
221
+ | Method | Endpoint | Description |
222
+ |--------|----------|-------------|
223
+ | `GET` | `/health` | Health check |
224
+ | `POST` | `/sessions` | Create a session `{ url, title }` |
225
+ | `GET` | `/sessions` | List all sessions |
226
+ | `GET` | `/sessions/:id` | Get session with annotations |
227
+ | `POST` | `/sessions/:id/annotations` | Add annotation `{ targetSelector, targetRect, text }` |
228
+ | `PATCH` | `/annotations/:id` | Resolve `{ resolved: true, summary }` or dismiss `{ dismissed: true, reason }` |
229
+ | `GET` | `/pending` | Get all pending annotations |
230
+ | `GET` | `/events` | SSE stream for real-time updates |
231
+
232
+ #### Environment variables
233
+
234
+ | Variable | Default | Description |
235
+ |----------|---------|-------------|
236
+ | `REFINER_PORT` | `4848` | HTTP server port |
237
+ | `REFINER_STORE` | SQLite at `~/.refiner/store.db` | Set to `memory` for in-memory storage |
238
+
239
+ #### Verify setup
240
+
241
+ ```bash
242
+ npx refinekit-mcp doctor
243
+ ```
244
+
245
+ ### Installing Claude Code skills manually
246
+
247
+ ```bash
248
+ # From the refiner project directory
249
+ ln -sf "$(pwd)/skills/refiner" ~/.claude/skills/refiner
250
+ ln -sf "$(pwd)/skills/refiner-self-driving" ~/.claude/skills/refiner-self-driving
251
+ ```
252
+
253
+ Restart Claude Code after installing.
254
+
255
+ ### Development
256
+
257
+ ```bash
258
+ git clone https://github.com/llewellynathan/refiner.git
259
+ cd refiner
260
+ npm install
261
+ npm run build # one-off build
262
+ npm run watch # rebuild on changes
263
+ ```
264
+
265
+ Open `examples/test.html` in a browser to test.
266
+
267
+ #### MCP server development
268
+
269
+ ```bash
270
+ cd mcp
271
+ npm install
272
+ npm run build # one-off build
273
+ npm run dev # rebuild on changes
274
+ ```
275
+
276
+ ## License
277
+
278
+ MIT
@@ -0,0 +1,14 @@
1
+ export declare class AnnotationDialog {
2
+ private root;
3
+ readonly el: HTMLElement;
4
+ private textarea;
5
+ private addBtn;
6
+ onSubmit?: (text: string) => void;
7
+ onCancel?: () => void;
8
+ constructor(root: ShadowRoot);
9
+ private render;
10
+ private submit;
11
+ show(x: number, y: number): void;
12
+ hide(): void;
13
+ isVisible(): boolean;
14
+ }
@@ -0,0 +1,19 @@
1
+ import { AnnotationStore } from './annotation-store';
2
+ export declare class AnnotationMarkers {
3
+ private root;
4
+ private store;
5
+ private markers;
6
+ private container;
7
+ private rafId;
8
+ private color;
9
+ constructor(root: ShadowRoot, store: AnnotationStore);
10
+ private addMarker;
11
+ private updateMarker;
12
+ private removeMarker;
13
+ private renumber;
14
+ private positionMarker;
15
+ private queryTarget;
16
+ setColor(color: string): void;
17
+ clearAll(): void;
18
+ private repositionAll;
19
+ }
@@ -0,0 +1,18 @@
1
+ import { Annotation } from './types';
2
+ type Listener = (annotation: Annotation) => void;
3
+ export declare class AnnotationStore {
4
+ private annotations;
5
+ private listeners;
6
+ add(targetSelector: string, targetRect: DOMRect, text: string): Annotation;
7
+ resolve(id: string): void;
8
+ remove(id: string): void;
9
+ get(id: string): Annotation | undefined;
10
+ getAll(): Annotation[];
11
+ getPending(): Annotation[];
12
+ getCount(): number;
13
+ exportJSON(): string;
14
+ on(event: string, listener: Listener): void;
15
+ off(event: string, listener: Listener): void;
16
+ private emit;
17
+ }
18
+ export {};
@@ -0,0 +1,4 @@
1
+ import { Refiner } from './refiner';
2
+ import type { Annotation, RefinerOptions } from './types';
3
+ export { Refiner };
4
+ export type { Annotation, RefinerOptions };
@@ -0,0 +1,18 @@
1
+ import { AnnotationStore } from './annotation-store';
2
+ export declare class McpBridge {
3
+ private store;
4
+ private baseUrl;
5
+ private sessionId;
6
+ private connected;
7
+ private retryTimer;
8
+ onChange?: (connected: boolean) => void;
9
+ constructor(store: AnnotationStore, port?: number);
10
+ private discover;
11
+ private startRetry;
12
+ private stopRetry;
13
+ private createSession;
14
+ private postAnnotation;
15
+ private patchAnnotation;
16
+ isConnected(): boolean;
17
+ destroy(): void;
18
+ }
@@ -0,0 +1,20 @@
1
+ export declare class Overlay {
2
+ private root;
3
+ readonly el: HTMLElement;
4
+ private highlight;
5
+ private enabled;
6
+ private blocking;
7
+ private currentTarget;
8
+ private highlightColor;
9
+ onClick?: (target: Element, rect: DOMRect) => void;
10
+ constructor(root: ShadowRoot);
11
+ private isOverOwnUI;
12
+ private handleMouseMove;
13
+ private handleClick;
14
+ private getElementAt;
15
+ private showHighlight;
16
+ private hideHighlight;
17
+ setHighlightColor(color: string): void;
18
+ setBlocking(blocking: boolean): void;
19
+ setEnabled(enabled: boolean): void;
20
+ }
@@ -0,0 +1,24 @@
1
+ import { RefinerOptions } from './types';
2
+ export declare class Refiner {
3
+ private host;
4
+ private shadow;
5
+ private store;
6
+ private toolbar;
7
+ private overlay;
8
+ private dialog;
9
+ private markers;
10
+ private settings;
11
+ private mcpBridge;
12
+ private currentTarget;
13
+ private currentRect;
14
+ private clearOnCopy;
15
+ constructor(options?: RefinerOptions);
16
+ enable(): void;
17
+ disable(): void;
18
+ destroy(): void;
19
+ getAnnotations(): import("./types").Annotation[];
20
+ getAnnotationCount(): number;
21
+ formatForAgent(): string;
22
+ clearAnnotations(): void;
23
+ copyAnnotations(): void;
24
+ }
@@ -0,0 +1,2 @@
1
+ var Refiner=function(t){"use strict";class e{constructor(){this.annotations=new Map,this.listeners=new Map}add(t,e,n){const i={id:crypto.randomUUID(),targetSelector:t,targetRect:{x:e.x,y:e.y,width:e.width,height:e.height},text:n,timestamp:Date.now(),resolved:!1};return this.annotations.set(i.id,i),this.emit("add",i),i}resolve(t){const e=this.annotations.get(t);e&&(e.resolved=!0,this.emit("resolve",e))}remove(t){const e=this.annotations.get(t);e&&(this.annotations.delete(t),this.emit("remove",e))}get(t){return this.annotations.get(t)}getAll(){return Array.from(this.annotations.values())}getPending(){return this.getAll().filter(t=>!t.resolved)}getCount(){return this.annotations.size}exportJSON(){return JSON.stringify(this.getAll(),null,2)}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){this.listeners.get(t)?.delete(e)}emit(t,e){this.listeners.get(t)?.forEach(t=>t(e))}}class n{constructor(t){this.root=t,this.collapsed=!0,this.settingsOpen=!1,this.el=document.createElement("div"),this.el.className="refiner-toolbar",this.el.setAttribute("data-refiner-toolbar",""),this.el.setAttribute("data-collapsed","true"),this.render(),t.appendChild(this.el),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.collapsed=!1,this.el.setAttribute("data-collapsed","false"),this.updateBadgeVisibility()})})}render(){const t=document.createElement("div");t.className="toolbar-pill",this.innerEl=document.createElement("div"),this.innerEl.className="toolbar-inner",this.countBadge=document.createElement("span"),this.countBadge.className="toolbar-count",this.countBadge.textContent="0",this.innerEl.appendChild(this.createBtn(this.countBadge,"Annotations",null));const e='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';this.copyBtn=this.createBtn(e,"Copy annotations",()=>{this.copyBtn.classList.contains("disabled")||(this.onCopy?.(),this.copyBtn.querySelector(".toolbar-icon").innerHTML='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>',setTimeout(()=>{this.copyBtn.querySelector(".toolbar-icon").innerHTML=e},1500))}),this.copyBtn.classList.add("disabled"),this.innerEl.appendChild(this.copyBtn),this.clearBtn=this.createBtn('<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>',"Clear all",()=>{this.clearBtn.classList.contains("disabled")||this.onClear?.()}),this.clearBtn.classList.add("disabled"),this.innerEl.appendChild(this.clearBtn),this.innerEl.appendChild(this.createBtn('<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',"Settings",()=>this.onSettings?.()));const n=document.createElement("div");n.className="toolbar-divider",this.innerEl.appendChild(n),t.appendChild(this.innerEl);const i='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>';this.toggleBtn=this.createBtn(i,"",()=>this.toggleCollapse()),this.toggleBtn.classList.add("toolbar-toggle-btn"),t.appendChild(this.toggleBtn),this.expandBadge=document.createElement("span"),this.expandBadge.className="toolbar-expand-badge hidden",this.expandBadge.textContent="0",t.appendChild(this.expandBadge),this.el.appendChild(t),this.el.addEventListener("transitionend",()=>{this.toggleBtn.querySelector(".toolbar-icon").innerHTML=this.collapsed?i:'<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>'})}createBtn(t,e,n){const i=document.createElement("button");i.className="toolbar-btn";const s=document.createElement("span");if(s.className="toolbar-icon","string"==typeof t?s.innerHTML=t:s.appendChild(t),i.appendChild(s),e){const t=document.createElement("span");t.className="toolbar-tooltip",t.textContent=e,i.appendChild(t)}return n&&i.addEventListener("click",n),i}toggleCollapse(){this.collapsed=!this.collapsed,this.el.setAttribute("data-collapsed",String(this.collapsed)),this.updateBadgeVisibility(),this.collapsed&&this.onCollapse?.()}setSettingsOpen(t){this.settingsOpen=t,this.el.classList.toggle("tooltips-hidden",t)}updateCount(t){this.countBadge.textContent=String(t),this.expandBadge.textContent=String(t),this.updateBadgeVisibility(t);const e=0===t;this.copyBtn.classList.toggle("disabled",e),this.clearBtn.classList.toggle("disabled",e)}updateBadgeVisibility(t){const e=t??parseInt(this.expandBadge.textContent||"0",10);this.expandBadge.classList.toggle("hidden",0===e||!this.collapsed)}}class i{constructor(t){this.root=t,this.enabled=!0,this.blocking=!0,this.currentTarget=null,this.highlightColor="#7C3AED",this.handleMouseMove=t=>{if(!this.enabled)return;if(this.isOverOwnUI(t.clientX,t.clientY))return void this.hideHighlight();const e=this.getElementAt(t.clientX,t.clientY);e&&e!==this.currentTarget&&(this.currentTarget=e,this.showHighlight(e))},this.handleClick=t=>{if(!this.enabled)return;if(this.isOverOwnUI(t.clientX,t.clientY))return;t.preventDefault(),t.stopPropagation();const e=this.getElementAt(t.clientX,t.clientY);if(e){const t=e.getBoundingClientRect();this.onClick?.(e,t)}},this.el=document.createElement("div"),this.el.className="refiner-overlay",this.el.setAttribute("data-blocking","true"),this.highlight=document.createElement("div"),this.highlight.className="refiner-highlight",this.highlight.style.display="none",t.appendChild(this.highlight),t.appendChild(this.el),this.el.addEventListener("mousemove",this.handleMouseMove),this.el.addEventListener("click",this.handleClick),this.el.addEventListener("mouseleave",()=>this.hideHighlight())}isOverOwnUI(t,e){const n=this.root.elementFromPoint(t,e);return!!n&&(n!==this.el&&n!==this.highlight)}getElementAt(t,e){this.el.style.pointerEvents="none",this.highlight.style.pointerEvents="none";const n=document.elementFromPoint(t,e);return this.el.style.pointerEvents="",this.highlight.style.pointerEvents="",n&&n===this.root.host?null:n}showHighlight(t){const e=t.getBoundingClientRect();this.highlight.style.display="block",this.highlight.style.top=e.top-2+"px",this.highlight.style.left=e.left-2+"px",this.highlight.style.width=`${e.width+4}px`,this.highlight.style.height=`${e.height+4}px`,this.highlight.style.borderColor=this.highlightColor}hideHighlight(){this.highlight.style.display="none",this.currentTarget=null}setHighlightColor(t){this.highlightColor=t}setBlocking(t){this.blocking=t,this.el.setAttribute("data-blocking",String(t)),t||this.hideHighlight()}setEnabled(t){this.enabled=t,this.el.classList.toggle("hidden",!t),t||this.hideHighlight()}}class s{constructor(t){this.root=t,this.el=document.createElement("div"),this.el.className="refiner-dialog hidden",this.render(),t.appendChild(this.el)}render(){const t=document.createElement("div");t.className="dialog-header";const e=document.createElement("span");e.textContent="What should change?",t.appendChild(e),this.el.appendChild(t),this.textarea=document.createElement("textarea"),this.textarea.className="dialog-textarea",this.textarea.placeholder="Describe the issue or improvement...",this.textarea.addEventListener("input",()=>{this.addBtn.disabled=0===this.textarea.value.trim().length}),this.textarea.addEventListener("keydown",t=>{"Enter"===t.key&&(t.metaKey||t.ctrlKey)&&this.textarea.value.trim()&&this.submit(),"Escape"===t.key&&(this.hide(),this.onCancel?.())}),this.el.appendChild(this.textarea);const n=document.createElement("div");n.className="dialog-actions";const i=document.createElement("button");i.className="dialog-btn dialog-btn-cancel",i.textContent="Cancel",i.addEventListener("click",()=>{this.hide(),this.onCancel?.()}),this.addBtn=document.createElement("button"),this.addBtn.className="dialog-btn dialog-btn-add",this.addBtn.textContent="Add",this.addBtn.disabled=!0,this.addBtn.addEventListener("click",()=>this.submit()),n.appendChild(i),n.appendChild(this.addBtn),this.el.appendChild(n)}submit(){const t=this.textarea.value.trim();t&&(this.onSubmit?.(t),this.hide())}show(t,e){let n=t+12,i=e+12;n+320>window.innerWidth-16&&(n=t-320-12),i+200>window.innerHeight-16&&(i=e-200-12),this.el.style.left=`${Math.max(16,n)}px`,this.el.style.top=`${Math.max(16,i)}px`,this.el.classList.remove("hidden"),this.textarea.value="",this.addBtn.disabled=!0,requestAnimationFrame(()=>this.textarea.focus())}hide(){this.el.classList.add("hidden"),this.textarea.value=""}isVisible(){return!this.el.classList.contains("hidden")}}class o{constructor(t,e){this.root=t,this.store=e,this.markers=new Map,this.rafId=null,this.color="#7C3AED",this.container=document.createElement("div"),this.container.className="refiner-markers",t.appendChild(this.container),e.on("add",t=>this.addMarker(t)),e.on("resolve",t=>this.updateMarker(t)),e.on("remove",t=>this.removeMarker(t.id));const n=()=>this.repositionAll();window.addEventListener("scroll",n,{passive:!0}),window.addEventListener("resize",n,{passive:!0})}addMarker(t){const e=document.createElement("div");e.className="refiner-marker",e.setAttribute("data-annotation-marker",t.id),e.setAttribute("data-resolved",String(t.resolved)),e.style.background=this.color;const n=this.markers.size+1;e.textContent=String(n);const i=document.createElement("div");i.className="marker-tooltip";const s=document.createElement("div");s.textContent=t.text,i.appendChild(s);const o=document.createElement("div");o.className="marker-tooltip-actions";const r=document.createElement("button");r.className="marker-tooltip-btn resolve",r.textContent="Resolve",r.addEventListener("click",e=>{e.stopPropagation(),this.store.resolve(t.id)});const a=document.createElement("button");a.className="marker-tooltip-btn delete",a.textContent="Delete",a.addEventListener("click",e=>{e.stopPropagation(),this.store.remove(t.id)}),o.appendChild(r),o.appendChild(a),i.appendChild(o),e.appendChild(i),this.positionMarker(e,t),this.container.appendChild(e),this.markers.set(t.id,{el:e,annotation:t})}updateMarker(t){const e=this.markers.get(t.id);e&&(e.annotation=t,e.el.setAttribute("data-resolved",String(t.resolved)))}removeMarker(t){const e=this.markers.get(t);e&&(e.el.remove(),this.markers.delete(t),this.renumber())}renumber(){let t=1;for(const[,e]of this.markers){const n=e.el.childNodes[0];n&&n.nodeType===Node.TEXT_NODE&&(n.textContent=String(t)),t++}}positionMarker(t,e){const n=this.queryTarget(e.targetSelector);if(n){const e=n.getBoundingClientRect();t.style.top=e.top-8+"px",t.style.left=e.right-8+"px"}else t.style.top=e.targetRect.y-8+"px",t.style.left=e.targetRect.x+e.targetRect.width-8+"px"}queryTarget(t){try{return document.querySelector(t)}catch{return null}}setColor(t){this.color=t;for(const[,e]of this.markers)e.el.style.background=t}clearAll(){for(const[t]of this.markers)this.removeMarker(t)}repositionAll(){null===this.rafId&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null;for(const[,t]of this.markers)this.positionMarker(t.el,t.annotation)}))}}const r=[{id:"purple",color:"#7C3AED"},{id:"blue",color:"#2563EB"},{id:"green",color:"#059669"},{id:"yellow",color:"#D97706"},{id:"orange",color:"#EA580C"},{id:"red",color:"#DC2626"},{id:"pink",color:"#DB2777"}];class a{constructor(t){this.root=t,this.visible=!1,this.settings={clearOnCopy:!1,blockInteractions:!0,markerColor:"#7C3AED"},this.el=document.createElement("div"),this.el.className="settings-panel hidden",this.render(),t.appendChild(this.el)}render(){const t=document.createElement("div");t.className="settings-header";const e=document.createElement("span");e.className="settings-title",e.textContent="reFiner";const n=document.createElement("span");n.className="settings-version",n.textContent="v0.1.0",t.appendChild(e),t.appendChild(n),this.el.appendChild(t),this.el.appendChild(this.createDivider());const i=document.createElement("div");i.className="settings-section";const s=document.createElement("span");s.className="settings-label",s.textContent="Marker Colour",i.appendChild(s);const o=document.createElement("div");o.className="settings-color-row";for(const t of r){const e=document.createElement("button");e.className="settings-swatch",e.style.background=t.color,e.setAttribute("data-color",t.color),t.color===this.settings.markerColor&&e.classList.add("selected"),e.addEventListener("click",()=>{o.querySelectorAll(".settings-swatch").forEach(t=>t.classList.remove("selected")),e.classList.add("selected"),this.settings.markerColor=t.color,this.emitChange()}),o.appendChild(e)}i.appendChild(o),this.el.appendChild(i),this.el.appendChild(this.createDivider()),this.el.appendChild(this.createCheckbox("Clear on copy",this.settings.clearOnCopy,t=>{this.settings.clearOnCopy=t,this.emitChange()})),this.el.appendChild(this.createCheckbox("Block page interactions",this.settings.blockInteractions,t=>{this.settings.blockInteractions=t,this.emitChange()})),this.el.appendChild(this.createDivider());const a=document.createElement("div");a.className="settings-mcp-row",this.mcpDot=document.createElement("span"),this.mcpDot.className="settings-mcp-dot disconnected",this.mcpLabel=document.createElement("span"),this.mcpLabel.className="settings-check-label",this.mcpLabel.textContent="MCP Disconnected",a.appendChild(this.mcpDot),a.appendChild(this.mcpLabel),this.el.appendChild(a)}createCheckbox(t,e,n){const i=document.createElement("label");i.className="settings-check-row";const s=document.createElement("input");s.type="checkbox",s.className="settings-checkbox",s.checked=e,s.addEventListener("change",()=>n(s.checked));const o=document.createElement("span");return o.className="settings-check-label",o.textContent=t,i.appendChild(s),i.appendChild(o),i}createDivider(){const t=document.createElement("div");return t.className="settings-divider",t}emitChange(){this.onChange?.({...this.settings})}toggle(){this.visible=!this.visible,this.el.classList.toggle("hidden",!this.visible)}hide(){this.visible=!1,this.el.classList.add("hidden")}isVisible(){return this.visible}setMcpStatus(t){this.mcpDot.className="settings-mcp-dot "+(t?"connected":"disconnected"),this.mcpLabel.textContent=t?"MCP Connected":"MCP Disconnected"}getSettings(){return{...this.settings}}}class l{constructor(t,e=4848){this.store=t,this.sessionId=null,this.connected=!1,this.retryTimer=null,this.baseUrl=`http://localhost:${e}`,this.discover(),this.store.on("add",t=>this.postAnnotation(t)),this.store.on("resolve",t=>this.patchAnnotation(t))}async discover(){try{const t=await fetch(`${this.baseUrl}/health`),e=await t.json();e&&"object"==typeof e&&"status"in e&&"ok"===e.status&&(this.connected=!0,this.onChange?.(!0),await this.createSession(),this.stopRetry())}catch{this.connected=!1,this.onChange?.(!1),this.startRetry()}}startRetry(){this.retryTimer||(this.retryTimer=setInterval(()=>this.discover(),5e3))}stopRetry(){this.retryTimer&&(clearInterval(this.retryTimer),this.retryTimer=null)}async createSession(){try{const t=await fetch(`${this.baseUrl}/sessions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:window.location.href,title:document.title||window.location.pathname})}),e=await t.json();this.sessionId=e.id}catch{}}async postAnnotation(t){if(this.connected&&this.sessionId)try{await fetch(`${this.baseUrl}/sessions/${this.sessionId}/annotations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({targetSelector:t.targetSelector,targetRect:t.targetRect,text:t.text})})}catch{}}async patchAnnotation(t){if(this.connected)try{await fetch(`${this.baseUrl}/annotations/${t.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({resolved:!0,summary:"Resolved from browser"})})}catch{}}isConnected(){return this.connected}destroy(){this.stopRetry()}}class d{constructor(t={}){this.mcpBridge=null,this.currentTarget=null,this.currentRect=null,this.clearOnCopy=!1,this.host=document.createElement("div"),this.host.id="refiner-host",this.shadow=this.host.attachShadow({mode:"open"});const r=document.createElement("style");r.textContent='\n :host {\n all: initial;\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', system-ui, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n color: #1a1a2e;\n }\n\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* ── Toolbar ── */\n\n .refiner-toolbar {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10;\n user-select: none;\n }\n\n .toolbar-pill {\n display: flex;\n align-items: center;\n position: relative;\n background: #1a1a2e;\n border-radius: 100px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15);\n padding: 6px;\n transform: scale(1);\n transform-origin: right center;\n transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n .refiner-toolbar[data-collapsed="true"] .toolbar-pill {\n transform: scale(0.92);\n }\n\n .toolbar-inner {\n display: flex;\n align-items: center;\n gap: 2px;\n overflow: hidden;\n clip-path: inset(0);\n max-width: 300px;\n opacity: 1;\n padding-right: 2px;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s ease 0.1s,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .refiner-toolbar[data-collapsed="true"] .toolbar-inner {\n max-width: 0;\n opacity: 0;\n padding-right: 0;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.15s ease,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .toolbar-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: #a0a0b8;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n\n .toolbar-btn:hover {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .toolbar-btn.active {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n }\n\n .toolbar-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .toolbar-count {\n font-size: 14px;\n font-weight: 700;\n min-width: 18px;\n text-align: center;\n }\n\n .toolbar-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n margin: 0 4px;\n flex-shrink: 0;\n }\n\n /* Tooltip */\n .toolbar-tooltip {\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 10px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n\n .toolbar-tooltip::after {\n content: \'\';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1a1a2e;\n }\n\n .toolbar-btn:hover .toolbar-tooltip {\n opacity: 1;\n }\n\n .tooltips-hidden .toolbar-tooltip {\n display: none;\n }\n\n .toolbar-btn.disabled {\n opacity: 0.3;\n cursor: default;\n }\n\n .toolbar-btn.disabled:hover {\n color: #a0a0b8;\n background: transparent;\n }\n\n /* Toggle button (always visible) */\n .toolbar-toggle-btn {\n flex-shrink: 0;\n }\n\n /* Badge for collapsed state */\n .toolbar-expand-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n border-radius: 10px;\n background: #DC2626;\n color: #ffffff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);\n }\n\n .toolbar-expand-badge.hidden {\n display: none;\n }\n\n /* ── Settings Panel ── */\n\n .settings-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 300px;\n z-index: 12;\n background: #1a1a2e;\n border-radius: 16px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 20px;\n color: #e8e8f0;\n transform-origin: bottom right;\n transition: transform 0.25s ease, opacity 0.1s ease;\n transform: scale(1);\n opacity: 1;\n }\n\n .settings-panel.hidden {\n transform: scale(0.4);\n opacity: 0;\n pointer-events: none;\n }\n\n .settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n }\n\n .settings-title {\n font-size: 16px;\n font-weight: 700;\n font-style: normal;\n color: #ffffff;\n }\n\n .settings-version {\n font-size: 12px;\n color: #6b6b80;\n font-weight: 500;\n }\n\n .settings-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.08);\n margin: 16px 0;\n }\n\n .settings-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .settings-label {\n font-size: 14px;\n font-weight: 500;\n color: #c0c0d0;\n }\n\n .settings-color-row {\n display: flex;\n gap: 8px;\n }\n\n .settings-swatch {\n width: 24px;\n height: 24px;\n border-radius: 4px;\n border: 2px solid transparent;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s;\n outline: none;\n }\n\n .settings-swatch:hover {\n transform: scale(1.1);\n }\n\n .settings-swatch.selected {\n border-color: #ffffff;\n transform: scale(1.1);\n }\n\n .settings-check-row {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n padding: 2px 0;\n }\n\n .settings-checkbox {\n appearance: none;\n -webkit-appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 5px;\n border: 2px solid #4a4a60;\n background: transparent;\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n transition: background 0.15s, border-color 0.15s;\n }\n\n .settings-checkbox:checked {\n background: #2563EB;\n border-color: #2563EB;\n }\n\n .settings-checkbox:checked::after {\n content: \'\';\n position: absolute;\n top: 2px;\n left: 5px;\n width: 5px;\n height: 9px;\n border: solid #ffffff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .settings-check-label {\n font-size: 14px;\n font-weight: 500;\n color: #e8e8f0;\n }\n\n /* ── Overlay ── */\n\n .refiner-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n cursor: crosshair;\n z-index: 1;\n }\n\n .refiner-overlay[data-blocking="true"] {\n pointer-events: all;\n }\n\n .refiner-overlay[data-blocking="false"] {\n pointer-events: none;\n }\n\n .refiner-overlay.hidden {\n display: none;\n }\n\n /* ── Highlight ── */\n\n .refiner-highlight {\n position: fixed;\n pointer-events: none;\n border: 2px dashed;\n border-radius: 3px;\n z-index: 2;\n transition: all 0.1s ease;\n }\n\n /* ── Dialog ── */\n\n .refiner-dialog {\n position: fixed;\n width: 320px;\n background: #1a1a2e;\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 14px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 16px;\n z-index: 11;\n color: #e8e8f0;\n animation: dialog-in 0.2s ease;\n }\n\n @keyframes dialog-in {\n from { opacity: 0; transform: translateY(4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n\n .refiner-dialog.hidden {\n display: none;\n }\n\n .dialog-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .dialog-header span {\n font-size: 12px;\n font-weight: 600;\n color: #c0c0d0;\n }\n\n .dialog-textarea {\n width: 100%;\n min-height: 72px;\n padding: 10px 12px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: #e8e8f0;\n background: rgba(255, 255, 255, 0.06);\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .dialog-textarea:focus {\n border-color: rgba(255, 255, 255, 0.25);\n }\n\n .dialog-textarea::placeholder {\n color: #6b6b80;\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 12px;\n }\n\n .dialog-btn {\n height: 32px;\n padding: 0 14px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .dialog-btn-cancel {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: #a0a0b8;\n }\n\n .dialog-btn-cancel:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #e8e8f0;\n }\n\n .dialog-btn-add {\n background: #2563EB;\n border: none;\n color: #ffffff;\n }\n\n .dialog-btn-add:hover {\n background: #3B82F6;\n }\n\n .dialog-btn-add:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n\n /* ── Markers ── */\n\n .refiner-marker {\n position: fixed;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: transform 0.15s;\n pointer-events: all;\n }\n\n .refiner-marker:hover {\n transform: scale(1.2);\n }\n\n .refiner-marker[data-resolved="true"] {\n opacity: 0.4;\n }\n\n .marker-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n width: 220px;\n padding: 10px 12px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n line-height: 1.4;\n border-radius: 10px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .refiner-marker:hover .marker-tooltip {\n opacity: 1;\n }\n\n .marker-tooltip-actions {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n border-top: 1px solid rgba(255,255,255,0.1);\n padding-top: 8px;\n }\n\n .marker-tooltip-btn {\n height: 22px;\n padding: 0 8px;\n border-radius: 5px;\n border: none;\n font-size: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .marker-tooltip-btn.resolve {\n background: #34D399;\n color: #0a2e1f;\n }\n\n .marker-tooltip-btn.resolve:hover {\n background: #4ade80;\n }\n\n .marker-tooltip-btn.delete {\n background: rgba(255,255,255,0.1);\n color: #e8e8f0;\n }\n\n .marker-tooltip-btn.delete:hover {\n background: #FF6B6B;\n color: #fff;\n }\n\n /* MCP status */\n .settings-mcp-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n\n .settings-mcp-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .settings-mcp-dot.connected {\n background: #34D399;\n box-shadow: 0 0 6px #34D39980;\n }\n\n .settings-mcp-dot.disconnected {\n background: #6B7280;\n }\n',this.shadow.appendChild(r),this.store=new e,this.toolbar=new n(this.shadow),this.settings=new a(this.shadow),this.overlay=new i(this.shadow),this.dialog=new s(this.shadow),this.markers=new o(this.shadow,this.store),this.toolbar.onCopy=()=>this.copyAnnotations(),this.toolbar.onClear=()=>this.clearAnnotations(),this.toolbar.onSettings=()=>{this.settings.toggle(),this.toolbar.setSettingsOpen(this.settings.isVisible())},this.toolbar.onCollapse=()=>{this.settings.hide(),this.toolbar.setSettingsOpen(!1)},this.settings.onChange=t=>{this.clearOnCopy=t.clearOnCopy,this.overlay.setBlocking(t.blockInteractions),this.markers.setColor(t.markerColor),this.overlay.setHighlightColor(t.markerColor)},this.overlay.onClick=(t,e)=>{if(this.settings.isVisible())return void this.settings.hide();if(this.dialog.isVisible())return void this.dialog.hide();this.currentTarget=t,this.currentRect=e;const n=e.left+e.width/2,i=e.top+e.height/2;this.dialog.show(n,i)},this.dialog.onSubmit=t=>{if(this.currentTarget&&this.currentRect){const e=function(t){if(t.id)return`#${CSS.escape(t.id)}`;if(t.classList.length>0){const e=`${t.tagName.toLowerCase()}.${Array.from(t.classList).map(CSS.escape).join(".")}`;if(1===document.querySelectorAll(e).length)return e}const e=[];let n=t;for(;n&&n!==document.documentElement;){const t=n.tagName.toLowerCase(),i=n.parentElement;if(n.id){e.unshift(`#${CSS.escape(n.id)}`);break}if(i){const s=Array.from(i.children).filter(t=>t.tagName===n.tagName);if(1===s.length)e.unshift(t);else{const i=s.indexOf(n)+1;e.unshift(`${t}:nth-child(${i})`)}}else e.unshift(t);n=i}return e.join(" > ")}(this.currentTarget);this.store.add(e,this.currentRect,t),this.toolbar.updateCount(this.store.getCount())}this.currentTarget=null,this.currentRect=null},this.dialog.onCancel=()=>{this.currentTarget=null,this.currentRect=null},this.store.on("resolve",()=>this.toolbar.updateCount(this.store.getCount())),this.store.on("remove",()=>this.toolbar.updateCount(this.store.getCount())),!1!==t.mcpEnabled&&(this.mcpBridge=new l(this.store,t.mcpPort),this.mcpBridge.onChange=t=>{this.settings.setMcpStatus(t)}),document.body.appendChild(this.host),!1===t.enabled&&this.disable()}enable(){this.host.style.display="",this.overlay.setEnabled(!0)}disable(){this.host.style.display="none",this.overlay.setEnabled(!1)}destroy(){this.mcpBridge?.destroy(),this.host.remove()}getAnnotations(){return this.store.getAll()}getAnnotationCount(){return this.store.getCount()}formatForAgent(){const t=this.store.getAll();if(0===t.length)return"No annotations.";const e=[`# Design Annotations — ${document.title||window.location.pathname}`,""];for(let n=0;n<t.length;n++){const i=t[n],s=i.resolved?" (resolved)":"";e.push(`## ${n+1}.${s}`),e.push(`**Element:** \`${i.targetSelector}\``),e.push(`**Issue:** ${i.text}`),e.push("")}return e.join("\n")}clearAnnotations(){const t=this.store.getAll();for(const e of t)this.store.remove(e.id);this.toolbar.updateCount(0)}copyAnnotations(){const t=this.formatForAgent();navigator.clipboard.writeText(t),this.clearOnCopy&&this.clearAnnotations()}}if("undefined"!=typeof window&&"undefined"!=typeof document){const t=()=>{if(window.__refiner)return;const t=document.currentScript,e=t?.dataset.refinerPosition??"right",n="false"!==t?.dataset.refinerEnabled,i=t?.dataset.refinerMcpPort?parseInt(t.dataset.refinerMcpPort,10):void 0,s="false"!==t?.dataset.refinerMcpEnabled,o=new d({position:e,enabled:n,mcpPort:i,mcpEnabled:s});window.__refiner=o};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}return t.Refiner=d,t}({});
2
+ //# sourceMappingURL=refiner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refiner.js","sources":["../src/annotation-store.ts","../src/toolbar.ts","../src/overlay.ts","../src/annotation-dialog.ts","../src/annotation-marker.ts","../src/settings.ts","../src/mcp-bridge.ts","../src/refiner.ts","../src/styles.ts","../src/selector.ts","../src/index.ts"],"sourcesContent":["import { Annotation } from './types';\n\ntype Listener = (annotation: Annotation) => void;\n\nexport class AnnotationStore {\n private annotations: Map<string, Annotation> = new Map();\n private listeners: Map<string, Set<Listener>> = new Map();\n\n add(targetSelector: string, targetRect: DOMRect, text: string): Annotation {\n const annotation: Annotation = {\n id: crypto.randomUUID(),\n targetSelector,\n targetRect: {\n x: targetRect.x,\n y: targetRect.y,\n width: targetRect.width,\n height: targetRect.height,\n },\n text,\n timestamp: Date.now(),\n resolved: false,\n };\n this.annotations.set(annotation.id, annotation);\n this.emit('add', annotation);\n return annotation;\n }\n\n resolve(id: string): void {\n const annotation = this.annotations.get(id);\n if (annotation) {\n annotation.resolved = true;\n this.emit('resolve', annotation);\n }\n }\n\n remove(id: string): void {\n const annotation = this.annotations.get(id);\n if (annotation) {\n this.annotations.delete(id);\n this.emit('remove', annotation);\n }\n }\n\n get(id: string): Annotation | undefined {\n return this.annotations.get(id);\n }\n\n getAll(): Annotation[] {\n return Array.from(this.annotations.values());\n }\n\n getPending(): Annotation[] {\n return this.getAll().filter((a) => !a.resolved);\n }\n\n getCount(): number {\n return this.annotations.size;\n }\n\n exportJSON(): string {\n return JSON.stringify(this.getAll(), null, 2);\n }\n\n on(event: string, listener: Listener): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off(event: string, listener: Listener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n private emit(event: string, annotation: Annotation): void {\n this.listeners.get(event)?.forEach((fn) => fn(annotation));\n }\n}\n","export class Toolbar {\n readonly el: HTMLElement;\n private collapsed = true;\n private countBadge!: HTMLElement;\n private expandBadge!: HTMLElement;\n private innerEl!: HTMLElement;\n private copyBtn!: HTMLElement;\n private clearBtn!: HTMLElement;\n private toggleBtn!: HTMLElement;\n private settingsOpen = false;\n\n onCopy?: () => void;\n onClear?: () => void;\n onSettings?: () => void;\n onCollapse?: () => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'refiner-toolbar';\n this.el.setAttribute('data-refiner-toolbar', '');\n this.el.setAttribute('data-collapsed', 'true');\n this.render();\n root.appendChild(this.el);\n\n // Expand on first load after a short delay\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this.collapsed = false;\n this.el.setAttribute('data-collapsed', 'false');\n this.updateBadgeVisibility();\n });\n });\n }\n\n private render(): void {\n const pill = document.createElement('div');\n pill.className = 'toolbar-pill';\n\n // Inner (collapsible buttons)\n this.innerEl = document.createElement('div');\n this.innerEl.className = 'toolbar-inner';\n\n // Note count\n this.countBadge = document.createElement('span');\n this.countBadge.className = 'toolbar-count';\n this.countBadge.textContent = '0';\n this.innerEl.appendChild(this.createBtn(\n this.countBadge,\n 'Annotations',\n null,\n ));\n\n // Copy\n const copyIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"/></svg>`;\n const checkIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`;\n this.copyBtn = this.createBtn(\n copyIcon,\n 'Copy annotations',\n () => {\n if (this.copyBtn.classList.contains('disabled')) return;\n this.onCopy?.();\n this.copyBtn.querySelector('.toolbar-icon')!.innerHTML = checkIcon;\n setTimeout(() => {\n this.copyBtn.querySelector('.toolbar-icon')!.innerHTML = copyIcon;\n }, 1500);\n },\n );\n this.copyBtn.classList.add('disabled');\n this.innerEl.appendChild(this.copyBtn);\n\n // Clear all\n this.clearBtn = this.createBtn(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>`,\n 'Clear all',\n () => {\n if (this.clearBtn.classList.contains('disabled')) return;\n this.onClear?.();\n },\n );\n this.clearBtn.classList.add('disabled');\n this.innerEl.appendChild(this.clearBtn);\n\n // Settings\n this.innerEl.appendChild(this.createBtn(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`,\n 'Settings',\n () => this.onSettings?.(),\n ));\n\n // Divider\n const divider = document.createElement('div');\n divider.className = 'toolbar-divider';\n this.innerEl.appendChild(divider);\n\n pill.appendChild(this.innerEl);\n\n // Toggle button (always visible — pen when collapsed, X when expanded)\n const penIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\"/></svg>`;\n const xIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`;\n\n this.toggleBtn = this.createBtn(\n penIcon,\n '',\n () => this.toggleCollapse(),\n );\n this.toggleBtn.classList.add('toolbar-toggle-btn');\n pill.appendChild(this.toggleBtn);\n\n // Badge for collapsed state\n this.expandBadge = document.createElement('span');\n this.expandBadge.className = 'toolbar-expand-badge hidden';\n this.expandBadge.textContent = '0';\n pill.appendChild(this.expandBadge);\n\n this.el.appendChild(pill);\n\n // Update toggle icon on transition end\n this.el.addEventListener('transitionend', () => {\n const icon = this.toggleBtn.querySelector('.toolbar-icon')!;\n icon.innerHTML = this.collapsed ? penIcon : xIcon;\n });\n }\n\n private createBtn(content: string | HTMLElement, tooltip: string, onClick: (() => void) | null): HTMLElement {\n const btn = document.createElement('button');\n btn.className = 'toolbar-btn';\n\n const iconWrap = document.createElement('span');\n iconWrap.className = 'toolbar-icon';\n if (typeof content === 'string') {\n iconWrap.innerHTML = content;\n } else {\n iconWrap.appendChild(content);\n }\n btn.appendChild(iconWrap);\n\n if (tooltip) {\n const tip = document.createElement('span');\n tip.className = 'toolbar-tooltip';\n tip.textContent = tooltip;\n btn.appendChild(tip);\n }\n\n if (onClick) {\n btn.addEventListener('click', onClick);\n }\n\n return btn;\n }\n\n private toggleCollapse(): void {\n this.collapsed = !this.collapsed;\n this.el.setAttribute('data-collapsed', String(this.collapsed));\n this.updateBadgeVisibility();\n if (this.collapsed) {\n this.onCollapse?.();\n }\n }\n\n setSettingsOpen(open: boolean): void {\n this.settingsOpen = open;\n this.el.classList.toggle('tooltips-hidden', open);\n }\n\n updateCount(count: number): void {\n this.countBadge.textContent = String(count);\n this.expandBadge.textContent = String(count);\n this.updateBadgeVisibility(count);\n\n const empty = count === 0;\n this.copyBtn.classList.toggle('disabled', empty);\n this.clearBtn.classList.toggle('disabled', empty);\n }\n\n private updateBadgeVisibility(count?: number): void {\n const c = count ?? parseInt(this.expandBadge.textContent || '0', 10);\n this.expandBadge.classList.toggle('hidden', c === 0 || !this.collapsed);\n }\n}\n","export class Overlay {\n readonly el: HTMLElement;\n private highlight: HTMLElement;\n private enabled = true;\n private blocking = true;\n private currentTarget: Element | null = null;\n private highlightColor = '#7C3AED';\n\n onClick?: (target: Element, rect: DOMRect) => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'refiner-overlay';\n this.el.setAttribute('data-blocking', 'true');\n\n this.highlight = document.createElement('div');\n this.highlight.className = 'refiner-highlight';\n this.highlight.style.display = 'none';\n\n root.appendChild(this.highlight);\n root.appendChild(this.el);\n\n this.el.addEventListener('mousemove', this.handleMouseMove);\n this.el.addEventListener('click', this.handleClick);\n this.el.addEventListener('mouseleave', () => this.hideHighlight());\n }\n\n private isOverOwnUI(x: number, y: number): boolean {\n const shadowEl = this.root.elementFromPoint(x, y);\n if (!shadowEl) return false;\n if (shadowEl === this.el || shadowEl === this.highlight) return false;\n return true;\n }\n\n private handleMouseMove = (e: MouseEvent): void => {\n if (!this.enabled) return;\n if (this.isOverOwnUI(e.clientX, e.clientY)) {\n this.hideHighlight();\n return;\n }\n\n const target = this.getElementAt(e.clientX, e.clientY);\n if (target && target !== this.currentTarget) {\n this.currentTarget = target;\n this.showHighlight(target);\n }\n };\n\n private handleClick = (e: MouseEvent): void => {\n if (!this.enabled) return;\n if (this.isOverOwnUI(e.clientX, e.clientY)) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n const target = this.getElementAt(e.clientX, e.clientY);\n if (target) {\n const rect = target.getBoundingClientRect();\n this.onClick?.(target, rect);\n }\n };\n\n private getElementAt(x: number, y: number): Element | null {\n this.el.style.pointerEvents = 'none';\n this.highlight.style.pointerEvents = 'none';\n\n const el = document.elementFromPoint(x, y);\n\n this.el.style.pointerEvents = '';\n this.highlight.style.pointerEvents = '';\n\n if (el && el === this.root.host) return null;\n return el;\n }\n\n private showHighlight(target: Element): void {\n const rect = target.getBoundingClientRect();\n this.highlight.style.display = 'block';\n this.highlight.style.top = `${rect.top - 2}px`;\n this.highlight.style.left = `${rect.left - 2}px`;\n this.highlight.style.width = `${rect.width + 4}px`;\n this.highlight.style.height = `${rect.height + 4}px`;\n this.highlight.style.borderColor = this.highlightColor;\n }\n\n private hideHighlight(): void {\n this.highlight.style.display = 'none';\n this.currentTarget = null;\n }\n\n setHighlightColor(color: string): void {\n this.highlightColor = color;\n }\n\n setBlocking(blocking: boolean): void {\n this.blocking = blocking;\n this.el.setAttribute('data-blocking', String(blocking));\n if (!blocking) {\n this.hideHighlight();\n }\n }\n\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n this.el.classList.toggle('hidden', !enabled);\n if (!enabled) this.hideHighlight();\n }\n}\n","export class AnnotationDialog {\n readonly el: HTMLElement;\n private textarea!: HTMLTextAreaElement;\n private addBtn!: HTMLButtonElement;\n\n onSubmit?: (text: string) => void;\n onCancel?: () => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'refiner-dialog hidden';\n this.render();\n root.appendChild(this.el);\n }\n\n private render(): void {\n // Header\n const header = document.createElement('div');\n header.className = 'dialog-header';\n const label = document.createElement('span');\n label.textContent = 'What should change?';\n header.appendChild(label);\n this.el.appendChild(header);\n\n // Textarea\n this.textarea = document.createElement('textarea');\n this.textarea.className = 'dialog-textarea';\n this.textarea.placeholder = 'Describe the issue or improvement...';\n this.textarea.addEventListener('input', () => {\n this.addBtn.disabled = this.textarea.value.trim().length === 0;\n });\n this.textarea.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey) && this.textarea.value.trim()) {\n this.submit();\n }\n if (e.key === 'Escape') {\n this.hide();\n this.onCancel?.();\n }\n });\n this.el.appendChild(this.textarea);\n\n // Actions\n const actions = document.createElement('div');\n actions.className = 'dialog-actions';\n\n const cancelBtn = document.createElement('button');\n cancelBtn.className = 'dialog-btn dialog-btn-cancel';\n cancelBtn.textContent = 'Cancel';\n cancelBtn.addEventListener('click', () => {\n this.hide();\n this.onCancel?.();\n });\n\n this.addBtn = document.createElement('button');\n this.addBtn.className = 'dialog-btn dialog-btn-add';\n this.addBtn.textContent = 'Add';\n this.addBtn.disabled = true;\n this.addBtn.addEventListener('click', () => this.submit());\n\n actions.appendChild(cancelBtn);\n actions.appendChild(this.addBtn);\n this.el.appendChild(actions);\n }\n\n private submit(): void {\n const text = this.textarea.value.trim();\n if (text) {\n this.onSubmit?.(text);\n this.hide();\n }\n }\n\n show(x: number, y: number): void {\n // Position: prefer below-right of click, but keep on screen\n const dialogW = 320;\n const dialogH = 200;\n let left = x + 12;\n let top = y + 12;\n\n if (left + dialogW > window.innerWidth - 16) {\n left = x - dialogW - 12;\n }\n if (top + dialogH > window.innerHeight - 16) {\n top = y - dialogH - 12;\n }\n\n this.el.style.left = `${Math.max(16, left)}px`;\n this.el.style.top = `${Math.max(16, top)}px`;\n this.el.classList.remove('hidden');\n\n this.textarea.value = '';\n this.addBtn.disabled = true;\n requestAnimationFrame(() => this.textarea.focus());\n }\n\n hide(): void {\n this.el.classList.add('hidden');\n this.textarea.value = '';\n }\n\n isVisible(): boolean {\n return !this.el.classList.contains('hidden');\n }\n}\n","import { Annotation } from './types';\nimport { AnnotationStore } from './annotation-store';\n\ninterface MarkerElement {\n el: HTMLElement;\n annotation: Annotation;\n}\n\nexport class AnnotationMarkers {\n private markers: Map<string, MarkerElement> = new Map();\n private container: HTMLElement;\n private rafId: number | null = null;\n private color = '#7C3AED';\n\n constructor(private root: ShadowRoot, private store: AnnotationStore) {\n this.container = document.createElement('div');\n this.container.className = 'refiner-markers';\n root.appendChild(this.container);\n\n store.on('add', (annotation) => this.addMarker(annotation));\n store.on('resolve', (annotation) => this.updateMarker(annotation));\n store.on('remove', (annotation) => this.removeMarker(annotation.id));\n\n const reposition = () => this.repositionAll();\n window.addEventListener('scroll', reposition, { passive: true });\n window.addEventListener('resize', reposition, { passive: true });\n }\n\n private addMarker(annotation: Annotation): void {\n const el = document.createElement('div');\n el.className = 'refiner-marker';\n el.setAttribute('data-annotation-marker', annotation.id);\n el.setAttribute('data-resolved', String(annotation.resolved));\n el.style.background = this.color;\n\n const index = this.markers.size + 1;\n el.textContent = String(index);\n\n // Tooltip\n const tooltip = document.createElement('div');\n tooltip.className = 'marker-tooltip';\n\n const tooltipText = document.createElement('div');\n tooltipText.textContent = annotation.text;\n tooltip.appendChild(tooltipText);\n\n const tooltipActions = document.createElement('div');\n tooltipActions.className = 'marker-tooltip-actions';\n\n const resolveBtn = document.createElement('button');\n resolveBtn.className = 'marker-tooltip-btn resolve';\n resolveBtn.textContent = 'Resolve';\n resolveBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.store.resolve(annotation.id);\n });\n\n const deleteBtn = document.createElement('button');\n deleteBtn.className = 'marker-tooltip-btn delete';\n deleteBtn.textContent = 'Delete';\n deleteBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.store.remove(annotation.id);\n });\n\n tooltipActions.appendChild(resolveBtn);\n tooltipActions.appendChild(deleteBtn);\n tooltip.appendChild(tooltipActions);\n el.appendChild(tooltip);\n\n this.positionMarker(el, annotation);\n this.container.appendChild(el);\n this.markers.set(annotation.id, { el, annotation });\n }\n\n private updateMarker(annotation: Annotation): void {\n const marker = this.markers.get(annotation.id);\n if (marker) {\n marker.annotation = annotation;\n marker.el.setAttribute('data-resolved', String(annotation.resolved));\n }\n }\n\n private removeMarker(id: string): void {\n const marker = this.markers.get(id);\n if (marker) {\n marker.el.remove();\n this.markers.delete(id);\n this.renumber();\n }\n }\n\n private renumber(): void {\n let i = 1;\n for (const [, marker] of this.markers) {\n const firstText = marker.el.childNodes[0];\n if (firstText && firstText.nodeType === Node.TEXT_NODE) {\n firstText.textContent = String(i);\n }\n i++;\n }\n }\n\n private positionMarker(el: HTMLElement, annotation: Annotation): void {\n const target = this.queryTarget(annotation.targetSelector);\n if (target) {\n const rect = target.getBoundingClientRect();\n el.style.top = `${rect.top - 8}px`;\n el.style.left = `${rect.right - 8}px`;\n } else {\n el.style.top = `${annotation.targetRect.y - 8}px`;\n el.style.left = `${annotation.targetRect.x + annotation.targetRect.width - 8}px`;\n }\n }\n\n private queryTarget(selector: string): Element | null {\n try {\n return document.querySelector(selector);\n } catch {\n return null;\n }\n }\n\n setColor(color: string): void {\n this.color = color;\n for (const [, marker] of this.markers) {\n marker.el.style.background = color;\n }\n }\n\n clearAll(): void {\n for (const [id] of this.markers) {\n this.removeMarker(id);\n }\n }\n\n private repositionAll(): void {\n if (this.rafId !== null) return;\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n for (const [, marker] of this.markers) {\n this.positionMarker(marker.el, marker.annotation);\n }\n });\n }\n}\n","const MARKER_COLORS = [\n { id: 'purple', color: '#7C3AED' },\n { id: 'blue', color: '#2563EB' },\n { id: 'green', color: '#059669' },\n { id: 'yellow', color: '#D97706' },\n { id: 'orange', color: '#EA580C' },\n { id: 'red', color: '#DC2626' },\n { id: 'pink', color: '#DB2777' },\n];\n\nexport interface Settings {\n clearOnCopy: boolean;\n blockInteractions: boolean;\n markerColor: string;\n}\n\nexport class SettingsPanel {\n readonly el: HTMLElement;\n private visible = false;\n private mcpDot!: HTMLElement;\n private mcpLabel!: HTMLElement;\n private settings: Settings = {\n clearOnCopy: false,\n blockInteractions: true,\n markerColor: '#7C3AED',\n };\n\n onChange?: (settings: Settings) => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'settings-panel hidden';\n this.render();\n root.appendChild(this.el);\n }\n\n private render(): void {\n // Header\n const header = document.createElement('div');\n header.className = 'settings-header';\n const title = document.createElement('span');\n title.className = 'settings-title';\n title.textContent = 'reFiner';\n const version = document.createElement('span');\n version.className = 'settings-version';\n version.textContent = 'v0.1.0';\n header.appendChild(title);\n header.appendChild(version);\n this.el.appendChild(header);\n\n this.el.appendChild(this.createDivider());\n\n // Marker color\n const colorSection = document.createElement('div');\n colorSection.className = 'settings-section';\n const colorLabel = document.createElement('span');\n colorLabel.className = 'settings-label';\n colorLabel.textContent = 'Marker Colour';\n colorSection.appendChild(colorLabel);\n\n const colorRow = document.createElement('div');\n colorRow.className = 'settings-color-row';\n for (const mc of MARKER_COLORS) {\n const swatch = document.createElement('button');\n swatch.className = 'settings-swatch';\n swatch.style.background = mc.color;\n swatch.setAttribute('data-color', mc.color);\n if (mc.color === this.settings.markerColor) {\n swatch.classList.add('selected');\n }\n swatch.addEventListener('click', () => {\n colorRow.querySelectorAll('.settings-swatch').forEach((s) =>\n s.classList.remove('selected')\n );\n swatch.classList.add('selected');\n this.settings.markerColor = mc.color;\n this.emitChange();\n });\n colorRow.appendChild(swatch);\n }\n colorSection.appendChild(colorRow);\n this.el.appendChild(colorSection);\n\n this.el.appendChild(this.createDivider());\n\n // Clear on copy\n this.el.appendChild(this.createCheckbox(\n 'Clear on copy',\n this.settings.clearOnCopy,\n (checked) => {\n this.settings.clearOnCopy = checked;\n this.emitChange();\n },\n ));\n\n // Block page interactions\n this.el.appendChild(this.createCheckbox(\n 'Block page interactions',\n this.settings.blockInteractions,\n (checked) => {\n this.settings.blockInteractions = checked;\n this.emitChange();\n },\n ));\n\n this.el.appendChild(this.createDivider());\n\n // MCP status\n const mcpRow = document.createElement('div');\n mcpRow.className = 'settings-mcp-row';\n\n this.mcpDot = document.createElement('span');\n this.mcpDot.className = 'settings-mcp-dot disconnected';\n\n this.mcpLabel = document.createElement('span');\n this.mcpLabel.className = 'settings-check-label';\n this.mcpLabel.textContent = 'MCP Disconnected';\n\n mcpRow.appendChild(this.mcpDot);\n mcpRow.appendChild(this.mcpLabel);\n this.el.appendChild(mcpRow);\n }\n\n private createCheckbox(label: string, initial: boolean, onChange: (v: boolean) => void): HTMLElement {\n const row = document.createElement('label');\n row.className = 'settings-check-row';\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.className = 'settings-checkbox';\n checkbox.checked = initial;\n checkbox.addEventListener('change', () => onChange(checkbox.checked));\n\n const text = document.createElement('span');\n text.className = 'settings-check-label';\n text.textContent = label;\n\n row.appendChild(checkbox);\n row.appendChild(text);\n return row;\n }\n\n private createDivider(): HTMLElement {\n const div = document.createElement('div');\n div.className = 'settings-divider';\n return div;\n }\n\n private emitChange(): void {\n this.onChange?.({ ...this.settings });\n }\n\n toggle(): void {\n this.visible = !this.visible;\n this.el.classList.toggle('hidden', !this.visible);\n }\n\n hide(): void {\n this.visible = false;\n this.el.classList.add('hidden');\n }\n\n isVisible(): boolean {\n return this.visible;\n }\n\n setMcpStatus(connected: boolean): void {\n this.mcpDot.className = `settings-mcp-dot ${connected ? 'connected' : 'disconnected'}`;\n this.mcpLabel.textContent = connected ? 'MCP Connected' : 'MCP Disconnected';\n }\n\n getSettings(): Settings {\n return { ...this.settings };\n }\n}\n","import { AnnotationStore } from './annotation-store';\nimport { Annotation } from './types';\n\nexport class McpBridge {\n private baseUrl: string;\n private sessionId: string | null = null;\n private connected = false;\n private retryTimer: ReturnType<typeof setInterval> | null = null;\n\n onChange?: (connected: boolean) => void;\n\n constructor(\n private store: AnnotationStore,\n port: number = 4848,\n ) {\n this.baseUrl = `http://localhost:${port}`;\n this.discover();\n\n // Wire up store events\n this.store.on('add', (annotation) => this.postAnnotation(annotation));\n this.store.on('resolve', (annotation) => this.patchAnnotation(annotation));\n }\n\n private async discover(): Promise<void> {\n try {\n const res = await fetch(`${this.baseUrl}/health`);\n const data = await res.json();\n if (data && typeof data === 'object' && 'status' in data && data.status === 'ok') {\n this.connected = true;\n this.onChange?.(true);\n await this.createSession();\n this.stopRetry();\n }\n } catch {\n this.connected = false;\n this.onChange?.(false);\n this.startRetry();\n }\n }\n\n private startRetry(): void {\n if (this.retryTimer) return;\n this.retryTimer = setInterval(() => this.discover(), 5000);\n }\n\n private stopRetry(): void {\n if (this.retryTimer) {\n clearInterval(this.retryTimer);\n this.retryTimer = null;\n }\n }\n\n private async createSession(): Promise<void> {\n try {\n const res = await fetch(`${this.baseUrl}/sessions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n url: window.location.href,\n title: document.title || window.location.pathname,\n }),\n });\n const session = await res.json();\n this.sessionId = session.id;\n } catch {\n // Session creation failed — annotations won't sync but local still works\n }\n }\n\n private async postAnnotation(annotation: Annotation): Promise<void> {\n if (!this.connected || !this.sessionId) return;\n\n try {\n await fetch(`${this.baseUrl}/sessions/${this.sessionId}/annotations`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n targetSelector: annotation.targetSelector,\n targetRect: annotation.targetRect,\n text: annotation.text,\n }),\n });\n } catch {\n // Silently fail — local annotation still exists\n }\n }\n\n private async patchAnnotation(annotation: Annotation): Promise<void> {\n if (!this.connected) return;\n\n try {\n await fetch(`${this.baseUrl}/annotations/${annotation.id}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n resolved: true,\n summary: 'Resolved from browser',\n }),\n });\n } catch {\n // Silently fail\n }\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n destroy(): void {\n this.stopRetry();\n }\n}\n","import { RefinerOptions } from './types';\nimport { STYLES } from './styles';\nimport { AnnotationStore } from './annotation-store';\nimport { Toolbar } from './toolbar';\nimport { Overlay } from './overlay';\nimport { AnnotationDialog } from './annotation-dialog';\nimport { AnnotationMarkers } from './annotation-marker';\nimport { SettingsPanel } from './settings';\nimport { generateSelector } from './selector';\nimport { McpBridge } from './mcp-bridge';\n\nexport class Refiner {\n private host: HTMLDivElement;\n private shadow: ShadowRoot;\n private store: AnnotationStore;\n private toolbar: Toolbar;\n private overlay: Overlay;\n private dialog: AnnotationDialog;\n private markers: AnnotationMarkers;\n private settings: SettingsPanel;\n private mcpBridge: McpBridge | null = null;\n private currentTarget: Element | null = null;\n private currentRect: DOMRect | null = null;\n private clearOnCopy = false;\n\n constructor(options: RefinerOptions = {}) {\n // Create shadow host\n this.host = document.createElement('div');\n this.host.id = 'refiner-host';\n this.shadow = this.host.attachShadow({ mode: 'open' });\n\n // Inject styles\n const style = document.createElement('style');\n style.textContent = STYLES;\n this.shadow.appendChild(style);\n\n // Initialize components\n this.store = new AnnotationStore();\n this.toolbar = new Toolbar(this.shadow);\n this.settings = new SettingsPanel(this.shadow);\n this.overlay = new Overlay(this.shadow);\n this.dialog = new AnnotationDialog(this.shadow);\n this.markers = new AnnotationMarkers(this.shadow, this.store);\n\n // Wire up toolbar\n this.toolbar.onCopy = () => this.copyAnnotations();\n this.toolbar.onClear = () => this.clearAnnotations();\n this.toolbar.onSettings = () => {\n this.settings.toggle();\n this.toolbar.setSettingsOpen(this.settings.isVisible());\n };\n\n this.toolbar.onCollapse = () => {\n this.settings.hide();\n this.toolbar.setSettingsOpen(false);\n };\n\n // Wire up settings\n this.settings.onChange = (s) => {\n this.clearOnCopy = s.clearOnCopy;\n this.overlay.setBlocking(s.blockInteractions);\n this.markers.setColor(s.markerColor);\n this.overlay.setHighlightColor(s.markerColor);\n };\n\n // Wire up overlay click\n this.overlay.onClick = (target, rect) => {\n if (this.settings.isVisible()) {\n this.settings.hide();\n return;\n }\n if (this.dialog.isVisible()) {\n this.dialog.hide();\n return;\n }\n this.currentTarget = target;\n this.currentRect = rect;\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n this.dialog.show(centerX, centerY);\n };\n\n // Wire up dialog submit\n this.dialog.onSubmit = (text) => {\n if (this.currentTarget && this.currentRect) {\n const selector = generateSelector(this.currentTarget);\n this.store.add(selector, this.currentRect, text);\n this.toolbar.updateCount(this.store.getCount());\n }\n this.currentTarget = null;\n this.currentRect = null;\n };\n\n this.dialog.onCancel = () => {\n this.currentTarget = null;\n this.currentRect = null;\n };\n\n // Update count on resolve/remove\n this.store.on('resolve', () => this.toolbar.updateCount(this.store.getCount()));\n this.store.on('remove', () => this.toolbar.updateCount(this.store.getCount()));\n\n // MCP bridge (auto-discover by default)\n if (options.mcpEnabled !== false) {\n this.mcpBridge = new McpBridge(this.store, options.mcpPort);\n this.mcpBridge.onChange = (connected) => {\n this.settings.setMcpStatus(connected);\n };\n }\n\n // Mount\n document.body.appendChild(this.host);\n\n if (options.enabled === false) {\n this.disable();\n }\n }\n\n enable(): void {\n this.host.style.display = '';\n this.overlay.setEnabled(true);\n }\n\n disable(): void {\n this.host.style.display = 'none';\n this.overlay.setEnabled(false);\n }\n\n destroy(): void {\n this.mcpBridge?.destroy();\n this.host.remove();\n }\n\n getAnnotations() {\n return this.store.getAll();\n }\n\n getAnnotationCount(): number {\n return this.store.getCount();\n }\n\n formatForAgent(): string {\n const annotations = this.store.getAll();\n if (annotations.length === 0) return 'No annotations.';\n\n const pageTitle = document.title || window.location.pathname;\n const lines: string[] = [`# Design Annotations — ${pageTitle}`, ''];\n\n for (let i = 0; i < annotations.length; i++) {\n const a = annotations[i];\n const status = a.resolved ? ' (resolved)' : '';\n lines.push(`## ${i + 1}.${status}`);\n lines.push(`**Element:** \\`${a.targetSelector}\\``);\n lines.push(`**Issue:** ${a.text}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n\n clearAnnotations(): void {\n const all = this.store.getAll();\n for (const a of all) {\n this.store.remove(a.id);\n }\n this.toolbar.updateCount(0);\n }\n\n copyAnnotations(): void {\n const text = this.formatForAgent();\n navigator.clipboard.writeText(text);\n\n if (this.clearOnCopy) {\n this.clearAnnotations();\n }\n }\n}\n","export const STYLES = `\n :host {\n all: initial;\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n color: #1a1a2e;\n }\n\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* ── Toolbar ── */\n\n .refiner-toolbar {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10;\n user-select: none;\n }\n\n .toolbar-pill {\n display: flex;\n align-items: center;\n position: relative;\n background: #1a1a2e;\n border-radius: 100px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15);\n padding: 6px;\n transform: scale(1);\n transform-origin: right center;\n transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n .refiner-toolbar[data-collapsed=\"true\"] .toolbar-pill {\n transform: scale(0.92);\n }\n\n .toolbar-inner {\n display: flex;\n align-items: center;\n gap: 2px;\n overflow: hidden;\n clip-path: inset(0);\n max-width: 300px;\n opacity: 1;\n padding-right: 2px;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s ease 0.1s,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .refiner-toolbar[data-collapsed=\"true\"] .toolbar-inner {\n max-width: 0;\n opacity: 0;\n padding-right: 0;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.15s ease,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .toolbar-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: #a0a0b8;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n\n .toolbar-btn:hover {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .toolbar-btn.active {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n }\n\n .toolbar-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .toolbar-count {\n font-size: 14px;\n font-weight: 700;\n min-width: 18px;\n text-align: center;\n }\n\n .toolbar-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n margin: 0 4px;\n flex-shrink: 0;\n }\n\n /* Tooltip */\n .toolbar-tooltip {\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 10px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n\n .toolbar-tooltip::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1a1a2e;\n }\n\n .toolbar-btn:hover .toolbar-tooltip {\n opacity: 1;\n }\n\n .tooltips-hidden .toolbar-tooltip {\n display: none;\n }\n\n .toolbar-btn.disabled {\n opacity: 0.3;\n cursor: default;\n }\n\n .toolbar-btn.disabled:hover {\n color: #a0a0b8;\n background: transparent;\n }\n\n /* Toggle button (always visible) */\n .toolbar-toggle-btn {\n flex-shrink: 0;\n }\n\n /* Badge for collapsed state */\n .toolbar-expand-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n border-radius: 10px;\n background: #DC2626;\n color: #ffffff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);\n }\n\n .toolbar-expand-badge.hidden {\n display: none;\n }\n\n /* ── Settings Panel ── */\n\n .settings-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 300px;\n z-index: 12;\n background: #1a1a2e;\n border-radius: 16px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 20px;\n color: #e8e8f0;\n transform-origin: bottom right;\n transition: transform 0.25s ease, opacity 0.1s ease;\n transform: scale(1);\n opacity: 1;\n }\n\n .settings-panel.hidden {\n transform: scale(0.4);\n opacity: 0;\n pointer-events: none;\n }\n\n .settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n }\n\n .settings-title {\n font-size: 16px;\n font-weight: 700;\n font-style: normal;\n color: #ffffff;\n }\n\n .settings-version {\n font-size: 12px;\n color: #6b6b80;\n font-weight: 500;\n }\n\n .settings-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.08);\n margin: 16px 0;\n }\n\n .settings-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .settings-label {\n font-size: 14px;\n font-weight: 500;\n color: #c0c0d0;\n }\n\n .settings-color-row {\n display: flex;\n gap: 8px;\n }\n\n .settings-swatch {\n width: 24px;\n height: 24px;\n border-radius: 4px;\n border: 2px solid transparent;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s;\n outline: none;\n }\n\n .settings-swatch:hover {\n transform: scale(1.1);\n }\n\n .settings-swatch.selected {\n border-color: #ffffff;\n transform: scale(1.1);\n }\n\n .settings-check-row {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n padding: 2px 0;\n }\n\n .settings-checkbox {\n appearance: none;\n -webkit-appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 5px;\n border: 2px solid #4a4a60;\n background: transparent;\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n transition: background 0.15s, border-color 0.15s;\n }\n\n .settings-checkbox:checked {\n background: #2563EB;\n border-color: #2563EB;\n }\n\n .settings-checkbox:checked::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 5px;\n width: 5px;\n height: 9px;\n border: solid #ffffff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .settings-check-label {\n font-size: 14px;\n font-weight: 500;\n color: #e8e8f0;\n }\n\n /* ── Overlay ── */\n\n .refiner-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n cursor: crosshair;\n z-index: 1;\n }\n\n .refiner-overlay[data-blocking=\"true\"] {\n pointer-events: all;\n }\n\n .refiner-overlay[data-blocking=\"false\"] {\n pointer-events: none;\n }\n\n .refiner-overlay.hidden {\n display: none;\n }\n\n /* ── Highlight ── */\n\n .refiner-highlight {\n position: fixed;\n pointer-events: none;\n border: 2px dashed;\n border-radius: 3px;\n z-index: 2;\n transition: all 0.1s ease;\n }\n\n /* ── Dialog ── */\n\n .refiner-dialog {\n position: fixed;\n width: 320px;\n background: #1a1a2e;\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 14px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 16px;\n z-index: 11;\n color: #e8e8f0;\n animation: dialog-in 0.2s ease;\n }\n\n @keyframes dialog-in {\n from { opacity: 0; transform: translateY(4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n\n .refiner-dialog.hidden {\n display: none;\n }\n\n .dialog-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .dialog-header span {\n font-size: 12px;\n font-weight: 600;\n color: #c0c0d0;\n }\n\n .dialog-textarea {\n width: 100%;\n min-height: 72px;\n padding: 10px 12px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: #e8e8f0;\n background: rgba(255, 255, 255, 0.06);\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .dialog-textarea:focus {\n border-color: rgba(255, 255, 255, 0.25);\n }\n\n .dialog-textarea::placeholder {\n color: #6b6b80;\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 12px;\n }\n\n .dialog-btn {\n height: 32px;\n padding: 0 14px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .dialog-btn-cancel {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: #a0a0b8;\n }\n\n .dialog-btn-cancel:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #e8e8f0;\n }\n\n .dialog-btn-add {\n background: #2563EB;\n border: none;\n color: #ffffff;\n }\n\n .dialog-btn-add:hover {\n background: #3B82F6;\n }\n\n .dialog-btn-add:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n\n /* ── Markers ── */\n\n .refiner-marker {\n position: fixed;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: transform 0.15s;\n pointer-events: all;\n }\n\n .refiner-marker:hover {\n transform: scale(1.2);\n }\n\n .refiner-marker[data-resolved=\"true\"] {\n opacity: 0.4;\n }\n\n .marker-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n width: 220px;\n padding: 10px 12px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n line-height: 1.4;\n border-radius: 10px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .refiner-marker:hover .marker-tooltip {\n opacity: 1;\n }\n\n .marker-tooltip-actions {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n border-top: 1px solid rgba(255,255,255,0.1);\n padding-top: 8px;\n }\n\n .marker-tooltip-btn {\n height: 22px;\n padding: 0 8px;\n border-radius: 5px;\n border: none;\n font-size: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .marker-tooltip-btn.resolve {\n background: #34D399;\n color: #0a2e1f;\n }\n\n .marker-tooltip-btn.resolve:hover {\n background: #4ade80;\n }\n\n .marker-tooltip-btn.delete {\n background: rgba(255,255,255,0.1);\n color: #e8e8f0;\n }\n\n .marker-tooltip-btn.delete:hover {\n background: #FF6B6B;\n color: #fff;\n }\n\n /* MCP status */\n .settings-mcp-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n\n .settings-mcp-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .settings-mcp-dot.connected {\n background: #34D399;\n box-shadow: 0 0 6px #34D39980;\n }\n\n .settings-mcp-dot.disconnected {\n background: #6B7280;\n }\n`;\n","/**\n * Generate a stable CSS selector for a DOM element.\n * Priority: #id > tag.class > nth-child path\n */\nexport function generateSelector(el: Element): string {\n if (el.id) {\n return `#${CSS.escape(el.id)}`;\n }\n\n // Try tag + distinctive class\n if (el.classList.length > 0) {\n const tag = el.tagName.toLowerCase();\n const classSelector = `${tag}.${Array.from(el.classList).map(CSS.escape).join('.')}`;\n if (document.querySelectorAll(classSelector).length === 1) {\n return classSelector;\n }\n }\n\n // Build nth-child path\n const parts: string[] = [];\n let current: Element | null = el;\n\n while (current && current !== document.documentElement) {\n const tag = current.tagName.toLowerCase();\n const parent: Element | null = current.parentElement;\n\n if (current.id) {\n parts.unshift(`#${CSS.escape(current.id)}`);\n break;\n }\n\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n (c: Element) => c.tagName === current!.tagName\n );\n if (siblings.length === 1) {\n parts.unshift(tag);\n } else {\n const index = siblings.indexOf(current) + 1;\n parts.unshift(`${tag}:nth-child(${index})`);\n }\n } else {\n parts.unshift(tag);\n }\n\n current = parent;\n }\n\n return parts.join(' > ');\n}\n","import { Refiner } from './refiner';\nimport type { Annotation, RefinerOptions } from './types';\n\nexport { Refiner };\nexport type { Annotation, RefinerOptions };\n\n// Auto-initialize when loaded via script tag\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const init = () => {\n // Skip if already initialized (e.g. bookmarklet + script tag both present)\n if ((window as any).__refiner) return;\n\n // Read config from script tag data attributes\n const script = document.currentScript as HTMLScriptElement | null;\n const position = (script?.dataset.refinerPosition as 'left' | 'right') ?? 'right';\n const enabled = script?.dataset.refinerEnabled !== 'false';\n const mcpPort = script?.dataset.refinerMcpPort ? parseInt(script.dataset.refinerMcpPort, 10) : undefined;\n const mcpEnabled = script?.dataset.refinerMcpEnabled !== 'false';\n\n const refiner = new Refiner({ position, enabled, mcpPort, mcpEnabled });\n (window as any).__refiner = refiner;\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init);\n } else {\n init();\n }\n}\n"],"names":["AnnotationStore","constructor","this","annotations","Map","listeners","add","targetSelector","targetRect","text","annotation","id","crypto","randomUUID","x","y","width","height","timestamp","Date","now","resolved","set","emit","resolve","get","remove","delete","getAll","Array","from","values","getPending","filter","a","getCount","size","exportJSON","JSON","stringify","on","event","listener","has","Set","off","forEach","fn","Toolbar","root","collapsed","settingsOpen","el","document","createElement","className","setAttribute","render","appendChild","requestAnimationFrame","updateBadgeVisibility","pill","innerEl","countBadge","textContent","createBtn","copyIcon","copyBtn","classList","contains","onCopy","querySelector","innerHTML","setTimeout","clearBtn","onClear","onSettings","divider","penIcon","toggleBtn","toggleCollapse","expandBadge","addEventListener","content","tooltip","onClick","btn","iconWrap","tip","String","onCollapse","setSettingsOpen","open","toggle","updateCount","count","empty","c","parseInt","Overlay","enabled","blocking","currentTarget","highlightColor","handleMouseMove","e","isOverOwnUI","clientX","clientY","hideHighlight","target","getElementAt","showHighlight","handleClick","preventDefault","stopPropagation","rect","getBoundingClientRect","highlight","style","display","shadowEl","elementFromPoint","pointerEvents","host","top","left","borderColor","setHighlightColor","color","setBlocking","setEnabled","AnnotationDialog","header","label","textarea","placeholder","addBtn","disabled","value","trim","length","key","metaKey","ctrlKey","submit","hide","onCancel","actions","cancelBtn","onSubmit","show","window","innerWidth","innerHeight","Math","max","focus","isVisible","AnnotationMarkers","store","markers","rafId","container","addMarker","updateMarker","removeMarker","reposition","repositionAll","passive","background","index","tooltipText","tooltipActions","resolveBtn","deleteBtn","positionMarker","marker","renumber","i","firstText","childNodes","nodeType","Node","TEXT_NODE","queryTarget","right","selector","setColor","clearAll","MARKER_COLORS","SettingsPanel","visible","settings","clearOnCopy","blockInteractions","markerColor","title","version","createDivider","colorSection","colorLabel","colorRow","mc","swatch","querySelectorAll","s","emitChange","createCheckbox","checked","mcpRow","mcpDot","mcpLabel","initial","onChange","row","checkbox","type","div","setMcpStatus","connected","getSettings","McpBridge","port","sessionId","retryTimer","baseUrl","discover","postAnnotation","patchAnnotation","res","fetch","data","json","status","createSession","stopRetry","startRetry","setInterval","clearInterval","method","headers","body","url","location","href","pathname","session","summary","isConnected","destroy","Refiner","options","mcpBridge","currentRect","shadow","attachShadow","mode","toolbar","overlay","dialog","copyAnnotations","clearAnnotations","centerX","centerY","CSS","escape","classSelector","tagName","toLowerCase","map","join","parts","current","documentElement","tag","parent","parentElement","unshift","siblings","children","indexOf","generateSelector","mcpEnabled","mcpPort","disable","enable","getAnnotations","getAnnotationCount","formatForAgent","lines","push","all","navigator","clipboard","writeText","init","__refiner","script","currentScript","position","dataset","refinerPosition","refinerEnabled","refinerMcpPort","undefined","refinerMcpEnabled","refiner","readyState"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ class t{constructor(){this.annotations=new Map,this.listeners=new Map}add(t,e,n){const i={id:crypto.randomUUID(),targetSelector:t,targetRect:{x:e.x,y:e.y,width:e.width,height:e.height},text:n,timestamp:Date.now(),resolved:!1};return this.annotations.set(i.id,i),this.emit("add",i),i}resolve(t){const e=this.annotations.get(t);e&&(e.resolved=!0,this.emit("resolve",e))}remove(t){const e=this.annotations.get(t);e&&(this.annotations.delete(t),this.emit("remove",e))}get(t){return this.annotations.get(t)}getAll(){return Array.from(this.annotations.values())}getPending(){return this.getAll().filter(t=>!t.resolved)}getCount(){return this.annotations.size}exportJSON(){return JSON.stringify(this.getAll(),null,2)}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){this.listeners.get(t)?.delete(e)}emit(t,e){this.listeners.get(t)?.forEach(t=>t(e))}}class e{constructor(t){this.root=t,this.collapsed=!0,this.settingsOpen=!1,this.el=document.createElement("div"),this.el.className="refiner-toolbar",this.el.setAttribute("data-refiner-toolbar",""),this.el.setAttribute("data-collapsed","true"),this.render(),t.appendChild(this.el),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.collapsed=!1,this.el.setAttribute("data-collapsed","false"),this.updateBadgeVisibility()})})}render(){const t=document.createElement("div");t.className="toolbar-pill",this.innerEl=document.createElement("div"),this.innerEl.className="toolbar-inner",this.countBadge=document.createElement("span"),this.countBadge.className="toolbar-count",this.countBadge.textContent="0",this.innerEl.appendChild(this.createBtn(this.countBadge,"Annotations",null));const e='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';this.copyBtn=this.createBtn(e,"Copy annotations",()=>{this.copyBtn.classList.contains("disabled")||(this.onCopy?.(),this.copyBtn.querySelector(".toolbar-icon").innerHTML='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>',setTimeout(()=>{this.copyBtn.querySelector(".toolbar-icon").innerHTML=e},1500))}),this.copyBtn.classList.add("disabled"),this.innerEl.appendChild(this.copyBtn),this.clearBtn=this.createBtn('<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>',"Clear all",()=>{this.clearBtn.classList.contains("disabled")||this.onClear?.()}),this.clearBtn.classList.add("disabled"),this.innerEl.appendChild(this.clearBtn),this.innerEl.appendChild(this.createBtn('<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>',"Settings",()=>this.onSettings?.()));const n=document.createElement("div");n.className="toolbar-divider",this.innerEl.appendChild(n),t.appendChild(this.innerEl);const i='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>';this.toggleBtn=this.createBtn(i,"",()=>this.toggleCollapse()),this.toggleBtn.classList.add("toolbar-toggle-btn"),t.appendChild(this.toggleBtn),this.expandBadge=document.createElement("span"),this.expandBadge.className="toolbar-expand-badge hidden",this.expandBadge.textContent="0",t.appendChild(this.expandBadge),this.el.appendChild(t),this.el.addEventListener("transitionend",()=>{this.toggleBtn.querySelector(".toolbar-icon").innerHTML=this.collapsed?i:'<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>'})}createBtn(t,e,n){const i=document.createElement("button");i.className="toolbar-btn";const s=document.createElement("span");if(s.className="toolbar-icon","string"==typeof t?s.innerHTML=t:s.appendChild(t),i.appendChild(s),e){const t=document.createElement("span");t.className="toolbar-tooltip",t.textContent=e,i.appendChild(t)}return n&&i.addEventListener("click",n),i}toggleCollapse(){this.collapsed=!this.collapsed,this.el.setAttribute("data-collapsed",String(this.collapsed)),this.updateBadgeVisibility(),this.collapsed&&this.onCollapse?.()}setSettingsOpen(t){this.settingsOpen=t,this.el.classList.toggle("tooltips-hidden",t)}updateCount(t){this.countBadge.textContent=String(t),this.expandBadge.textContent=String(t),this.updateBadgeVisibility(t);const e=0===t;this.copyBtn.classList.toggle("disabled",e),this.clearBtn.classList.toggle("disabled",e)}updateBadgeVisibility(t){const e=t??parseInt(this.expandBadge.textContent||"0",10);this.expandBadge.classList.toggle("hidden",0===e||!this.collapsed)}}class n{constructor(t){this.root=t,this.enabled=!0,this.blocking=!0,this.currentTarget=null,this.highlightColor="#7C3AED",this.handleMouseMove=t=>{if(!this.enabled)return;if(this.isOverOwnUI(t.clientX,t.clientY))return void this.hideHighlight();const e=this.getElementAt(t.clientX,t.clientY);e&&e!==this.currentTarget&&(this.currentTarget=e,this.showHighlight(e))},this.handleClick=t=>{if(!this.enabled)return;if(this.isOverOwnUI(t.clientX,t.clientY))return;t.preventDefault(),t.stopPropagation();const e=this.getElementAt(t.clientX,t.clientY);if(e){const t=e.getBoundingClientRect();this.onClick?.(e,t)}},this.el=document.createElement("div"),this.el.className="refiner-overlay",this.el.setAttribute("data-blocking","true"),this.highlight=document.createElement("div"),this.highlight.className="refiner-highlight",this.highlight.style.display="none",t.appendChild(this.highlight),t.appendChild(this.el),this.el.addEventListener("mousemove",this.handleMouseMove),this.el.addEventListener("click",this.handleClick),this.el.addEventListener("mouseleave",()=>this.hideHighlight())}isOverOwnUI(t,e){const n=this.root.elementFromPoint(t,e);return!!n&&(n!==this.el&&n!==this.highlight)}getElementAt(t,e){this.el.style.pointerEvents="none",this.highlight.style.pointerEvents="none";const n=document.elementFromPoint(t,e);return this.el.style.pointerEvents="",this.highlight.style.pointerEvents="",n&&n===this.root.host?null:n}showHighlight(t){const e=t.getBoundingClientRect();this.highlight.style.display="block",this.highlight.style.top=e.top-2+"px",this.highlight.style.left=e.left-2+"px",this.highlight.style.width=`${e.width+4}px`,this.highlight.style.height=`${e.height+4}px`,this.highlight.style.borderColor=this.highlightColor}hideHighlight(){this.highlight.style.display="none",this.currentTarget=null}setHighlightColor(t){this.highlightColor=t}setBlocking(t){this.blocking=t,this.el.setAttribute("data-blocking",String(t)),t||this.hideHighlight()}setEnabled(t){this.enabled=t,this.el.classList.toggle("hidden",!t),t||this.hideHighlight()}}class i{constructor(t){this.root=t,this.el=document.createElement("div"),this.el.className="refiner-dialog hidden",this.render(),t.appendChild(this.el)}render(){const t=document.createElement("div");t.className="dialog-header";const e=document.createElement("span");e.textContent="What should change?",t.appendChild(e),this.el.appendChild(t),this.textarea=document.createElement("textarea"),this.textarea.className="dialog-textarea",this.textarea.placeholder="Describe the issue or improvement...",this.textarea.addEventListener("input",()=>{this.addBtn.disabled=0===this.textarea.value.trim().length}),this.textarea.addEventListener("keydown",t=>{"Enter"===t.key&&(t.metaKey||t.ctrlKey)&&this.textarea.value.trim()&&this.submit(),"Escape"===t.key&&(this.hide(),this.onCancel?.())}),this.el.appendChild(this.textarea);const n=document.createElement("div");n.className="dialog-actions";const i=document.createElement("button");i.className="dialog-btn dialog-btn-cancel",i.textContent="Cancel",i.addEventListener("click",()=>{this.hide(),this.onCancel?.()}),this.addBtn=document.createElement("button"),this.addBtn.className="dialog-btn dialog-btn-add",this.addBtn.textContent="Add",this.addBtn.disabled=!0,this.addBtn.addEventListener("click",()=>this.submit()),n.appendChild(i),n.appendChild(this.addBtn),this.el.appendChild(n)}submit(){const t=this.textarea.value.trim();t&&(this.onSubmit?.(t),this.hide())}show(t,e){let n=t+12,i=e+12;n+320>window.innerWidth-16&&(n=t-320-12),i+200>window.innerHeight-16&&(i=e-200-12),this.el.style.left=`${Math.max(16,n)}px`,this.el.style.top=`${Math.max(16,i)}px`,this.el.classList.remove("hidden"),this.textarea.value="",this.addBtn.disabled=!0,requestAnimationFrame(()=>this.textarea.focus())}hide(){this.el.classList.add("hidden"),this.textarea.value=""}isVisible(){return!this.el.classList.contains("hidden")}}class s{constructor(t,e){this.root=t,this.store=e,this.markers=new Map,this.rafId=null,this.color="#7C3AED",this.container=document.createElement("div"),this.container.className="refiner-markers",t.appendChild(this.container),e.on("add",t=>this.addMarker(t)),e.on("resolve",t=>this.updateMarker(t)),e.on("remove",t=>this.removeMarker(t.id));const n=()=>this.repositionAll();window.addEventListener("scroll",n,{passive:!0}),window.addEventListener("resize",n,{passive:!0})}addMarker(t){const e=document.createElement("div");e.className="refiner-marker",e.setAttribute("data-annotation-marker",t.id),e.setAttribute("data-resolved",String(t.resolved)),e.style.background=this.color;const n=this.markers.size+1;e.textContent=String(n);const i=document.createElement("div");i.className="marker-tooltip";const s=document.createElement("div");s.textContent=t.text,i.appendChild(s);const o=document.createElement("div");o.className="marker-tooltip-actions";const r=document.createElement("button");r.className="marker-tooltip-btn resolve",r.textContent="Resolve",r.addEventListener("click",e=>{e.stopPropagation(),this.store.resolve(t.id)});const a=document.createElement("button");a.className="marker-tooltip-btn delete",a.textContent="Delete",a.addEventListener("click",e=>{e.stopPropagation(),this.store.remove(t.id)}),o.appendChild(r),o.appendChild(a),i.appendChild(o),e.appendChild(i),this.positionMarker(e,t),this.container.appendChild(e),this.markers.set(t.id,{el:e,annotation:t})}updateMarker(t){const e=this.markers.get(t.id);e&&(e.annotation=t,e.el.setAttribute("data-resolved",String(t.resolved)))}removeMarker(t){const e=this.markers.get(t);e&&(e.el.remove(),this.markers.delete(t),this.renumber())}renumber(){let t=1;for(const[,e]of this.markers){const n=e.el.childNodes[0];n&&n.nodeType===Node.TEXT_NODE&&(n.textContent=String(t)),t++}}positionMarker(t,e){const n=this.queryTarget(e.targetSelector);if(n){const e=n.getBoundingClientRect();t.style.top=e.top-8+"px",t.style.left=e.right-8+"px"}else t.style.top=e.targetRect.y-8+"px",t.style.left=e.targetRect.x+e.targetRect.width-8+"px"}queryTarget(t){try{return document.querySelector(t)}catch{return null}}setColor(t){this.color=t;for(const[,e]of this.markers)e.el.style.background=t}clearAll(){for(const[t]of this.markers)this.removeMarker(t)}repositionAll(){null===this.rafId&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null;for(const[,t]of this.markers)this.positionMarker(t.el,t.annotation)}))}}const o=[{id:"purple",color:"#7C3AED"},{id:"blue",color:"#2563EB"},{id:"green",color:"#059669"},{id:"yellow",color:"#D97706"},{id:"orange",color:"#EA580C"},{id:"red",color:"#DC2626"},{id:"pink",color:"#DB2777"}];class r{constructor(t){this.root=t,this.visible=!1,this.settings={clearOnCopy:!1,blockInteractions:!0,markerColor:"#7C3AED"},this.el=document.createElement("div"),this.el.className="settings-panel hidden",this.render(),t.appendChild(this.el)}render(){const t=document.createElement("div");t.className="settings-header";const e=document.createElement("span");e.className="settings-title",e.textContent="reFiner";const n=document.createElement("span");n.className="settings-version",n.textContent="v0.1.0",t.appendChild(e),t.appendChild(n),this.el.appendChild(t),this.el.appendChild(this.createDivider());const i=document.createElement("div");i.className="settings-section";const s=document.createElement("span");s.className="settings-label",s.textContent="Marker Colour",i.appendChild(s);const r=document.createElement("div");r.className="settings-color-row";for(const t of o){const e=document.createElement("button");e.className="settings-swatch",e.style.background=t.color,e.setAttribute("data-color",t.color),t.color===this.settings.markerColor&&e.classList.add("selected"),e.addEventListener("click",()=>{r.querySelectorAll(".settings-swatch").forEach(t=>t.classList.remove("selected")),e.classList.add("selected"),this.settings.markerColor=t.color,this.emitChange()}),r.appendChild(e)}i.appendChild(r),this.el.appendChild(i),this.el.appendChild(this.createDivider()),this.el.appendChild(this.createCheckbox("Clear on copy",this.settings.clearOnCopy,t=>{this.settings.clearOnCopy=t,this.emitChange()})),this.el.appendChild(this.createCheckbox("Block page interactions",this.settings.blockInteractions,t=>{this.settings.blockInteractions=t,this.emitChange()})),this.el.appendChild(this.createDivider());const a=document.createElement("div");a.className="settings-mcp-row",this.mcpDot=document.createElement("span"),this.mcpDot.className="settings-mcp-dot disconnected",this.mcpLabel=document.createElement("span"),this.mcpLabel.className="settings-check-label",this.mcpLabel.textContent="MCP Disconnected",a.appendChild(this.mcpDot),a.appendChild(this.mcpLabel),this.el.appendChild(a)}createCheckbox(t,e,n){const i=document.createElement("label");i.className="settings-check-row";const s=document.createElement("input");s.type="checkbox",s.className="settings-checkbox",s.checked=e,s.addEventListener("change",()=>n(s.checked));const o=document.createElement("span");return o.className="settings-check-label",o.textContent=t,i.appendChild(s),i.appendChild(o),i}createDivider(){const t=document.createElement("div");return t.className="settings-divider",t}emitChange(){this.onChange?.({...this.settings})}toggle(){this.visible=!this.visible,this.el.classList.toggle("hidden",!this.visible)}hide(){this.visible=!1,this.el.classList.add("hidden")}isVisible(){return this.visible}setMcpStatus(t){this.mcpDot.className="settings-mcp-dot "+(t?"connected":"disconnected"),this.mcpLabel.textContent=t?"MCP Connected":"MCP Disconnected"}getSettings(){return{...this.settings}}}class a{constructor(t,e=4848){this.store=t,this.sessionId=null,this.connected=!1,this.retryTimer=null,this.baseUrl=`http://localhost:${e}`,this.discover(),this.store.on("add",t=>this.postAnnotation(t)),this.store.on("resolve",t=>this.patchAnnotation(t))}async discover(){try{const t=await fetch(`${this.baseUrl}/health`),e=await t.json();e&&"object"==typeof e&&"status"in e&&"ok"===e.status&&(this.connected=!0,this.onChange?.(!0),await this.createSession(),this.stopRetry())}catch{this.connected=!1,this.onChange?.(!1),this.startRetry()}}startRetry(){this.retryTimer||(this.retryTimer=setInterval(()=>this.discover(),5e3))}stopRetry(){this.retryTimer&&(clearInterval(this.retryTimer),this.retryTimer=null)}async createSession(){try{const t=await fetch(`${this.baseUrl}/sessions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:window.location.href,title:document.title||window.location.pathname})}),e=await t.json();this.sessionId=e.id}catch{}}async postAnnotation(t){if(this.connected&&this.sessionId)try{await fetch(`${this.baseUrl}/sessions/${this.sessionId}/annotations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({targetSelector:t.targetSelector,targetRect:t.targetRect,text:t.text})})}catch{}}async patchAnnotation(t){if(this.connected)try{await fetch(`${this.baseUrl}/annotations/${t.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({resolved:!0,summary:"Resolved from browser"})})}catch{}}isConnected(){return this.connected}destroy(){this.stopRetry()}}class l{constructor(o={}){this.mcpBridge=null,this.currentTarget=null,this.currentRect=null,this.clearOnCopy=!1,this.host=document.createElement("div"),this.host.id="refiner-host",this.shadow=this.host.attachShadow({mode:"open"});const l=document.createElement("style");l.textContent='\n :host {\n all: initial;\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', system-ui, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n color: #1a1a2e;\n }\n\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* ── Toolbar ── */\n\n .refiner-toolbar {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10;\n user-select: none;\n }\n\n .toolbar-pill {\n display: flex;\n align-items: center;\n position: relative;\n background: #1a1a2e;\n border-radius: 100px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15);\n padding: 6px;\n transform: scale(1);\n transform-origin: right center;\n transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n .refiner-toolbar[data-collapsed="true"] .toolbar-pill {\n transform: scale(0.92);\n }\n\n .toolbar-inner {\n display: flex;\n align-items: center;\n gap: 2px;\n overflow: hidden;\n clip-path: inset(0);\n max-width: 300px;\n opacity: 1;\n padding-right: 2px;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s ease 0.1s,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .refiner-toolbar[data-collapsed="true"] .toolbar-inner {\n max-width: 0;\n opacity: 0;\n padding-right: 0;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.15s ease,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .toolbar-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: #a0a0b8;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n\n .toolbar-btn:hover {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .toolbar-btn.active {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n }\n\n .toolbar-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .toolbar-count {\n font-size: 14px;\n font-weight: 700;\n min-width: 18px;\n text-align: center;\n }\n\n .toolbar-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n margin: 0 4px;\n flex-shrink: 0;\n }\n\n /* Tooltip */\n .toolbar-tooltip {\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 10px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n\n .toolbar-tooltip::after {\n content: \'\';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1a1a2e;\n }\n\n .toolbar-btn:hover .toolbar-tooltip {\n opacity: 1;\n }\n\n .tooltips-hidden .toolbar-tooltip {\n display: none;\n }\n\n .toolbar-btn.disabled {\n opacity: 0.3;\n cursor: default;\n }\n\n .toolbar-btn.disabled:hover {\n color: #a0a0b8;\n background: transparent;\n }\n\n /* Toggle button (always visible) */\n .toolbar-toggle-btn {\n flex-shrink: 0;\n }\n\n /* Badge for collapsed state */\n .toolbar-expand-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n border-radius: 10px;\n background: #DC2626;\n color: #ffffff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);\n }\n\n .toolbar-expand-badge.hidden {\n display: none;\n }\n\n /* ── Settings Panel ── */\n\n .settings-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 300px;\n z-index: 12;\n background: #1a1a2e;\n border-radius: 16px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 20px;\n color: #e8e8f0;\n transform-origin: bottom right;\n transition: transform 0.25s ease, opacity 0.1s ease;\n transform: scale(1);\n opacity: 1;\n }\n\n .settings-panel.hidden {\n transform: scale(0.4);\n opacity: 0;\n pointer-events: none;\n }\n\n .settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n }\n\n .settings-title {\n font-size: 16px;\n font-weight: 700;\n font-style: normal;\n color: #ffffff;\n }\n\n .settings-version {\n font-size: 12px;\n color: #6b6b80;\n font-weight: 500;\n }\n\n .settings-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.08);\n margin: 16px 0;\n }\n\n .settings-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .settings-label {\n font-size: 14px;\n font-weight: 500;\n color: #c0c0d0;\n }\n\n .settings-color-row {\n display: flex;\n gap: 8px;\n }\n\n .settings-swatch {\n width: 24px;\n height: 24px;\n border-radius: 4px;\n border: 2px solid transparent;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s;\n outline: none;\n }\n\n .settings-swatch:hover {\n transform: scale(1.1);\n }\n\n .settings-swatch.selected {\n border-color: #ffffff;\n transform: scale(1.1);\n }\n\n .settings-check-row {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n padding: 2px 0;\n }\n\n .settings-checkbox {\n appearance: none;\n -webkit-appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 5px;\n border: 2px solid #4a4a60;\n background: transparent;\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n transition: background 0.15s, border-color 0.15s;\n }\n\n .settings-checkbox:checked {\n background: #2563EB;\n border-color: #2563EB;\n }\n\n .settings-checkbox:checked::after {\n content: \'\';\n position: absolute;\n top: 2px;\n left: 5px;\n width: 5px;\n height: 9px;\n border: solid #ffffff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .settings-check-label {\n font-size: 14px;\n font-weight: 500;\n color: #e8e8f0;\n }\n\n /* ── Overlay ── */\n\n .refiner-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n cursor: crosshair;\n z-index: 1;\n }\n\n .refiner-overlay[data-blocking="true"] {\n pointer-events: all;\n }\n\n .refiner-overlay[data-blocking="false"] {\n pointer-events: none;\n }\n\n .refiner-overlay.hidden {\n display: none;\n }\n\n /* ── Highlight ── */\n\n .refiner-highlight {\n position: fixed;\n pointer-events: none;\n border: 2px dashed;\n border-radius: 3px;\n z-index: 2;\n transition: all 0.1s ease;\n }\n\n /* ── Dialog ── */\n\n .refiner-dialog {\n position: fixed;\n width: 320px;\n background: #1a1a2e;\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 14px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 16px;\n z-index: 11;\n color: #e8e8f0;\n animation: dialog-in 0.2s ease;\n }\n\n @keyframes dialog-in {\n from { opacity: 0; transform: translateY(4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n\n .refiner-dialog.hidden {\n display: none;\n }\n\n .dialog-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .dialog-header span {\n font-size: 12px;\n font-weight: 600;\n color: #c0c0d0;\n }\n\n .dialog-textarea {\n width: 100%;\n min-height: 72px;\n padding: 10px 12px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: #e8e8f0;\n background: rgba(255, 255, 255, 0.06);\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .dialog-textarea:focus {\n border-color: rgba(255, 255, 255, 0.25);\n }\n\n .dialog-textarea::placeholder {\n color: #6b6b80;\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 12px;\n }\n\n .dialog-btn {\n height: 32px;\n padding: 0 14px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .dialog-btn-cancel {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: #a0a0b8;\n }\n\n .dialog-btn-cancel:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #e8e8f0;\n }\n\n .dialog-btn-add {\n background: #2563EB;\n border: none;\n color: #ffffff;\n }\n\n .dialog-btn-add:hover {\n background: #3B82F6;\n }\n\n .dialog-btn-add:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n\n /* ── Markers ── */\n\n .refiner-marker {\n position: fixed;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: transform 0.15s;\n pointer-events: all;\n }\n\n .refiner-marker:hover {\n transform: scale(1.2);\n }\n\n .refiner-marker[data-resolved="true"] {\n opacity: 0.4;\n }\n\n .marker-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n width: 220px;\n padding: 10px 12px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n line-height: 1.4;\n border-radius: 10px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .refiner-marker:hover .marker-tooltip {\n opacity: 1;\n }\n\n .marker-tooltip-actions {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n border-top: 1px solid rgba(255,255,255,0.1);\n padding-top: 8px;\n }\n\n .marker-tooltip-btn {\n height: 22px;\n padding: 0 8px;\n border-radius: 5px;\n border: none;\n font-size: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .marker-tooltip-btn.resolve {\n background: #34D399;\n color: #0a2e1f;\n }\n\n .marker-tooltip-btn.resolve:hover {\n background: #4ade80;\n }\n\n .marker-tooltip-btn.delete {\n background: rgba(255,255,255,0.1);\n color: #e8e8f0;\n }\n\n .marker-tooltip-btn.delete:hover {\n background: #FF6B6B;\n color: #fff;\n }\n\n /* MCP status */\n .settings-mcp-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n\n .settings-mcp-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .settings-mcp-dot.connected {\n background: #34D399;\n box-shadow: 0 0 6px #34D39980;\n }\n\n .settings-mcp-dot.disconnected {\n background: #6B7280;\n }\n',this.shadow.appendChild(l),this.store=new t,this.toolbar=new e(this.shadow),this.settings=new r(this.shadow),this.overlay=new n(this.shadow),this.dialog=new i(this.shadow),this.markers=new s(this.shadow,this.store),this.toolbar.onCopy=()=>this.copyAnnotations(),this.toolbar.onClear=()=>this.clearAnnotations(),this.toolbar.onSettings=()=>{this.settings.toggle(),this.toolbar.setSettingsOpen(this.settings.isVisible())},this.toolbar.onCollapse=()=>{this.settings.hide(),this.toolbar.setSettingsOpen(!1)},this.settings.onChange=t=>{this.clearOnCopy=t.clearOnCopy,this.overlay.setBlocking(t.blockInteractions),this.markers.setColor(t.markerColor),this.overlay.setHighlightColor(t.markerColor)},this.overlay.onClick=(t,e)=>{if(this.settings.isVisible())return void this.settings.hide();if(this.dialog.isVisible())return void this.dialog.hide();this.currentTarget=t,this.currentRect=e;const n=e.left+e.width/2,i=e.top+e.height/2;this.dialog.show(n,i)},this.dialog.onSubmit=t=>{if(this.currentTarget&&this.currentRect){const e=function(t){if(t.id)return`#${CSS.escape(t.id)}`;if(t.classList.length>0){const e=`${t.tagName.toLowerCase()}.${Array.from(t.classList).map(CSS.escape).join(".")}`;if(1===document.querySelectorAll(e).length)return e}const e=[];let n=t;for(;n&&n!==document.documentElement;){const t=n.tagName.toLowerCase(),i=n.parentElement;if(n.id){e.unshift(`#${CSS.escape(n.id)}`);break}if(i){const s=Array.from(i.children).filter(t=>t.tagName===n.tagName);if(1===s.length)e.unshift(t);else{const i=s.indexOf(n)+1;e.unshift(`${t}:nth-child(${i})`)}}else e.unshift(t);n=i}return e.join(" > ")}(this.currentTarget);this.store.add(e,this.currentRect,t),this.toolbar.updateCount(this.store.getCount())}this.currentTarget=null,this.currentRect=null},this.dialog.onCancel=()=>{this.currentTarget=null,this.currentRect=null},this.store.on("resolve",()=>this.toolbar.updateCount(this.store.getCount())),this.store.on("remove",()=>this.toolbar.updateCount(this.store.getCount())),!1!==o.mcpEnabled&&(this.mcpBridge=new a(this.store,o.mcpPort),this.mcpBridge.onChange=t=>{this.settings.setMcpStatus(t)}),document.body.appendChild(this.host),!1===o.enabled&&this.disable()}enable(){this.host.style.display="",this.overlay.setEnabled(!0)}disable(){this.host.style.display="none",this.overlay.setEnabled(!1)}destroy(){this.mcpBridge?.destroy(),this.host.remove()}getAnnotations(){return this.store.getAll()}getAnnotationCount(){return this.store.getCount()}formatForAgent(){const t=this.store.getAll();if(0===t.length)return"No annotations.";const e=[`# Design Annotations — ${document.title||window.location.pathname}`,""];for(let n=0;n<t.length;n++){const i=t[n],s=i.resolved?" (resolved)":"";e.push(`## ${n+1}.${s}`),e.push(`**Element:** \`${i.targetSelector}\``),e.push(`**Issue:** ${i.text}`),e.push("")}return e.join("\n")}clearAnnotations(){const t=this.store.getAll();for(const e of t)this.store.remove(e.id);this.toolbar.updateCount(0)}copyAnnotations(){const t=this.formatForAgent();navigator.clipboard.writeText(t),this.clearOnCopy&&this.clearAnnotations()}}if("undefined"!=typeof window&&"undefined"!=typeof document){const t=()=>{if(window.__refiner)return;const t=document.currentScript,e=t?.dataset.refinerPosition??"right",n="false"!==t?.dataset.refinerEnabled,i=t?.dataset.refinerMcpPort?parseInt(t.dataset.refinerMcpPort,10):void 0,s="false"!==t?.dataset.refinerMcpEnabled,o=new l({position:e,enabled:n,mcpPort:i,mcpEnabled:s});window.__refiner=o};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t()}export{l as Refiner};
2
+ //# sourceMappingURL=refiner.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refiner.mjs","sources":["../src/annotation-store.ts","../src/toolbar.ts","../src/overlay.ts","../src/annotation-dialog.ts","../src/annotation-marker.ts","../src/settings.ts","../src/mcp-bridge.ts","../src/refiner.ts","../src/styles.ts","../src/selector.ts","../src/index.ts"],"sourcesContent":["import { Annotation } from './types';\n\ntype Listener = (annotation: Annotation) => void;\n\nexport class AnnotationStore {\n private annotations: Map<string, Annotation> = new Map();\n private listeners: Map<string, Set<Listener>> = new Map();\n\n add(targetSelector: string, targetRect: DOMRect, text: string): Annotation {\n const annotation: Annotation = {\n id: crypto.randomUUID(),\n targetSelector,\n targetRect: {\n x: targetRect.x,\n y: targetRect.y,\n width: targetRect.width,\n height: targetRect.height,\n },\n text,\n timestamp: Date.now(),\n resolved: false,\n };\n this.annotations.set(annotation.id, annotation);\n this.emit('add', annotation);\n return annotation;\n }\n\n resolve(id: string): void {\n const annotation = this.annotations.get(id);\n if (annotation) {\n annotation.resolved = true;\n this.emit('resolve', annotation);\n }\n }\n\n remove(id: string): void {\n const annotation = this.annotations.get(id);\n if (annotation) {\n this.annotations.delete(id);\n this.emit('remove', annotation);\n }\n }\n\n get(id: string): Annotation | undefined {\n return this.annotations.get(id);\n }\n\n getAll(): Annotation[] {\n return Array.from(this.annotations.values());\n }\n\n getPending(): Annotation[] {\n return this.getAll().filter((a) => !a.resolved);\n }\n\n getCount(): number {\n return this.annotations.size;\n }\n\n exportJSON(): string {\n return JSON.stringify(this.getAll(), null, 2);\n }\n\n on(event: string, listener: Listener): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n off(event: string, listener: Listener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n private emit(event: string, annotation: Annotation): void {\n this.listeners.get(event)?.forEach((fn) => fn(annotation));\n }\n}\n","export class Toolbar {\n readonly el: HTMLElement;\n private collapsed = true;\n private countBadge!: HTMLElement;\n private expandBadge!: HTMLElement;\n private innerEl!: HTMLElement;\n private copyBtn!: HTMLElement;\n private clearBtn!: HTMLElement;\n private toggleBtn!: HTMLElement;\n private settingsOpen = false;\n\n onCopy?: () => void;\n onClear?: () => void;\n onSettings?: () => void;\n onCollapse?: () => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'refiner-toolbar';\n this.el.setAttribute('data-refiner-toolbar', '');\n this.el.setAttribute('data-collapsed', 'true');\n this.render();\n root.appendChild(this.el);\n\n // Expand on first load after a short delay\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n this.collapsed = false;\n this.el.setAttribute('data-collapsed', 'false');\n this.updateBadgeVisibility();\n });\n });\n }\n\n private render(): void {\n const pill = document.createElement('div');\n pill.className = 'toolbar-pill';\n\n // Inner (collapsible buttons)\n this.innerEl = document.createElement('div');\n this.innerEl.className = 'toolbar-inner';\n\n // Note count\n this.countBadge = document.createElement('span');\n this.countBadge.className = 'toolbar-count';\n this.countBadge.textContent = '0';\n this.innerEl.appendChild(this.createBtn(\n this.countBadge,\n 'Annotations',\n null,\n ));\n\n // Copy\n const copyIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"/></svg>`;\n const checkIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`;\n this.copyBtn = this.createBtn(\n copyIcon,\n 'Copy annotations',\n () => {\n if (this.copyBtn.classList.contains('disabled')) return;\n this.onCopy?.();\n this.copyBtn.querySelector('.toolbar-icon')!.innerHTML = checkIcon;\n setTimeout(() => {\n this.copyBtn.querySelector('.toolbar-icon')!.innerHTML = copyIcon;\n }, 1500);\n },\n );\n this.copyBtn.classList.add('disabled');\n this.innerEl.appendChild(this.copyBtn);\n\n // Clear all\n this.clearBtn = this.createBtn(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>`,\n 'Clear all',\n () => {\n if (this.clearBtn.classList.contains('disabled')) return;\n this.onClear?.();\n },\n );\n this.clearBtn.classList.add('disabled');\n this.innerEl.appendChild(this.clearBtn);\n\n // Settings\n this.innerEl.appendChild(this.createBtn(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`,\n 'Settings',\n () => this.onSettings?.(),\n ));\n\n // Divider\n const divider = document.createElement('div');\n divider.className = 'toolbar-divider';\n this.innerEl.appendChild(divider);\n\n pill.appendChild(this.innerEl);\n\n // Toggle button (always visible — pen when collapsed, X when expanded)\n const penIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\"/></svg>`;\n const xIcon = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`;\n\n this.toggleBtn = this.createBtn(\n penIcon,\n '',\n () => this.toggleCollapse(),\n );\n this.toggleBtn.classList.add('toolbar-toggle-btn');\n pill.appendChild(this.toggleBtn);\n\n // Badge for collapsed state\n this.expandBadge = document.createElement('span');\n this.expandBadge.className = 'toolbar-expand-badge hidden';\n this.expandBadge.textContent = '0';\n pill.appendChild(this.expandBadge);\n\n this.el.appendChild(pill);\n\n // Update toggle icon on transition end\n this.el.addEventListener('transitionend', () => {\n const icon = this.toggleBtn.querySelector('.toolbar-icon')!;\n icon.innerHTML = this.collapsed ? penIcon : xIcon;\n });\n }\n\n private createBtn(content: string | HTMLElement, tooltip: string, onClick: (() => void) | null): HTMLElement {\n const btn = document.createElement('button');\n btn.className = 'toolbar-btn';\n\n const iconWrap = document.createElement('span');\n iconWrap.className = 'toolbar-icon';\n if (typeof content === 'string') {\n iconWrap.innerHTML = content;\n } else {\n iconWrap.appendChild(content);\n }\n btn.appendChild(iconWrap);\n\n if (tooltip) {\n const tip = document.createElement('span');\n tip.className = 'toolbar-tooltip';\n tip.textContent = tooltip;\n btn.appendChild(tip);\n }\n\n if (onClick) {\n btn.addEventListener('click', onClick);\n }\n\n return btn;\n }\n\n private toggleCollapse(): void {\n this.collapsed = !this.collapsed;\n this.el.setAttribute('data-collapsed', String(this.collapsed));\n this.updateBadgeVisibility();\n if (this.collapsed) {\n this.onCollapse?.();\n }\n }\n\n setSettingsOpen(open: boolean): void {\n this.settingsOpen = open;\n this.el.classList.toggle('tooltips-hidden', open);\n }\n\n updateCount(count: number): void {\n this.countBadge.textContent = String(count);\n this.expandBadge.textContent = String(count);\n this.updateBadgeVisibility(count);\n\n const empty = count === 0;\n this.copyBtn.classList.toggle('disabled', empty);\n this.clearBtn.classList.toggle('disabled', empty);\n }\n\n private updateBadgeVisibility(count?: number): void {\n const c = count ?? parseInt(this.expandBadge.textContent || '0', 10);\n this.expandBadge.classList.toggle('hidden', c === 0 || !this.collapsed);\n }\n}\n","export class Overlay {\n readonly el: HTMLElement;\n private highlight: HTMLElement;\n private enabled = true;\n private blocking = true;\n private currentTarget: Element | null = null;\n private highlightColor = '#7C3AED';\n\n onClick?: (target: Element, rect: DOMRect) => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'refiner-overlay';\n this.el.setAttribute('data-blocking', 'true');\n\n this.highlight = document.createElement('div');\n this.highlight.className = 'refiner-highlight';\n this.highlight.style.display = 'none';\n\n root.appendChild(this.highlight);\n root.appendChild(this.el);\n\n this.el.addEventListener('mousemove', this.handleMouseMove);\n this.el.addEventListener('click', this.handleClick);\n this.el.addEventListener('mouseleave', () => this.hideHighlight());\n }\n\n private isOverOwnUI(x: number, y: number): boolean {\n const shadowEl = this.root.elementFromPoint(x, y);\n if (!shadowEl) return false;\n if (shadowEl === this.el || shadowEl === this.highlight) return false;\n return true;\n }\n\n private handleMouseMove = (e: MouseEvent): void => {\n if (!this.enabled) return;\n if (this.isOverOwnUI(e.clientX, e.clientY)) {\n this.hideHighlight();\n return;\n }\n\n const target = this.getElementAt(e.clientX, e.clientY);\n if (target && target !== this.currentTarget) {\n this.currentTarget = target;\n this.showHighlight(target);\n }\n };\n\n private handleClick = (e: MouseEvent): void => {\n if (!this.enabled) return;\n if (this.isOverOwnUI(e.clientX, e.clientY)) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n const target = this.getElementAt(e.clientX, e.clientY);\n if (target) {\n const rect = target.getBoundingClientRect();\n this.onClick?.(target, rect);\n }\n };\n\n private getElementAt(x: number, y: number): Element | null {\n this.el.style.pointerEvents = 'none';\n this.highlight.style.pointerEvents = 'none';\n\n const el = document.elementFromPoint(x, y);\n\n this.el.style.pointerEvents = '';\n this.highlight.style.pointerEvents = '';\n\n if (el && el === this.root.host) return null;\n return el;\n }\n\n private showHighlight(target: Element): void {\n const rect = target.getBoundingClientRect();\n this.highlight.style.display = 'block';\n this.highlight.style.top = `${rect.top - 2}px`;\n this.highlight.style.left = `${rect.left - 2}px`;\n this.highlight.style.width = `${rect.width + 4}px`;\n this.highlight.style.height = `${rect.height + 4}px`;\n this.highlight.style.borderColor = this.highlightColor;\n }\n\n private hideHighlight(): void {\n this.highlight.style.display = 'none';\n this.currentTarget = null;\n }\n\n setHighlightColor(color: string): void {\n this.highlightColor = color;\n }\n\n setBlocking(blocking: boolean): void {\n this.blocking = blocking;\n this.el.setAttribute('data-blocking', String(blocking));\n if (!blocking) {\n this.hideHighlight();\n }\n }\n\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n this.el.classList.toggle('hidden', !enabled);\n if (!enabled) this.hideHighlight();\n }\n}\n","export class AnnotationDialog {\n readonly el: HTMLElement;\n private textarea!: HTMLTextAreaElement;\n private addBtn!: HTMLButtonElement;\n\n onSubmit?: (text: string) => void;\n onCancel?: () => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'refiner-dialog hidden';\n this.render();\n root.appendChild(this.el);\n }\n\n private render(): void {\n // Header\n const header = document.createElement('div');\n header.className = 'dialog-header';\n const label = document.createElement('span');\n label.textContent = 'What should change?';\n header.appendChild(label);\n this.el.appendChild(header);\n\n // Textarea\n this.textarea = document.createElement('textarea');\n this.textarea.className = 'dialog-textarea';\n this.textarea.placeholder = 'Describe the issue or improvement...';\n this.textarea.addEventListener('input', () => {\n this.addBtn.disabled = this.textarea.value.trim().length === 0;\n });\n this.textarea.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey) && this.textarea.value.trim()) {\n this.submit();\n }\n if (e.key === 'Escape') {\n this.hide();\n this.onCancel?.();\n }\n });\n this.el.appendChild(this.textarea);\n\n // Actions\n const actions = document.createElement('div');\n actions.className = 'dialog-actions';\n\n const cancelBtn = document.createElement('button');\n cancelBtn.className = 'dialog-btn dialog-btn-cancel';\n cancelBtn.textContent = 'Cancel';\n cancelBtn.addEventListener('click', () => {\n this.hide();\n this.onCancel?.();\n });\n\n this.addBtn = document.createElement('button');\n this.addBtn.className = 'dialog-btn dialog-btn-add';\n this.addBtn.textContent = 'Add';\n this.addBtn.disabled = true;\n this.addBtn.addEventListener('click', () => this.submit());\n\n actions.appendChild(cancelBtn);\n actions.appendChild(this.addBtn);\n this.el.appendChild(actions);\n }\n\n private submit(): void {\n const text = this.textarea.value.trim();\n if (text) {\n this.onSubmit?.(text);\n this.hide();\n }\n }\n\n show(x: number, y: number): void {\n // Position: prefer below-right of click, but keep on screen\n const dialogW = 320;\n const dialogH = 200;\n let left = x + 12;\n let top = y + 12;\n\n if (left + dialogW > window.innerWidth - 16) {\n left = x - dialogW - 12;\n }\n if (top + dialogH > window.innerHeight - 16) {\n top = y - dialogH - 12;\n }\n\n this.el.style.left = `${Math.max(16, left)}px`;\n this.el.style.top = `${Math.max(16, top)}px`;\n this.el.classList.remove('hidden');\n\n this.textarea.value = '';\n this.addBtn.disabled = true;\n requestAnimationFrame(() => this.textarea.focus());\n }\n\n hide(): void {\n this.el.classList.add('hidden');\n this.textarea.value = '';\n }\n\n isVisible(): boolean {\n return !this.el.classList.contains('hidden');\n }\n}\n","import { Annotation } from './types';\nimport { AnnotationStore } from './annotation-store';\n\ninterface MarkerElement {\n el: HTMLElement;\n annotation: Annotation;\n}\n\nexport class AnnotationMarkers {\n private markers: Map<string, MarkerElement> = new Map();\n private container: HTMLElement;\n private rafId: number | null = null;\n private color = '#7C3AED';\n\n constructor(private root: ShadowRoot, private store: AnnotationStore) {\n this.container = document.createElement('div');\n this.container.className = 'refiner-markers';\n root.appendChild(this.container);\n\n store.on('add', (annotation) => this.addMarker(annotation));\n store.on('resolve', (annotation) => this.updateMarker(annotation));\n store.on('remove', (annotation) => this.removeMarker(annotation.id));\n\n const reposition = () => this.repositionAll();\n window.addEventListener('scroll', reposition, { passive: true });\n window.addEventListener('resize', reposition, { passive: true });\n }\n\n private addMarker(annotation: Annotation): void {\n const el = document.createElement('div');\n el.className = 'refiner-marker';\n el.setAttribute('data-annotation-marker', annotation.id);\n el.setAttribute('data-resolved', String(annotation.resolved));\n el.style.background = this.color;\n\n const index = this.markers.size + 1;\n el.textContent = String(index);\n\n // Tooltip\n const tooltip = document.createElement('div');\n tooltip.className = 'marker-tooltip';\n\n const tooltipText = document.createElement('div');\n tooltipText.textContent = annotation.text;\n tooltip.appendChild(tooltipText);\n\n const tooltipActions = document.createElement('div');\n tooltipActions.className = 'marker-tooltip-actions';\n\n const resolveBtn = document.createElement('button');\n resolveBtn.className = 'marker-tooltip-btn resolve';\n resolveBtn.textContent = 'Resolve';\n resolveBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.store.resolve(annotation.id);\n });\n\n const deleteBtn = document.createElement('button');\n deleteBtn.className = 'marker-tooltip-btn delete';\n deleteBtn.textContent = 'Delete';\n deleteBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.store.remove(annotation.id);\n });\n\n tooltipActions.appendChild(resolveBtn);\n tooltipActions.appendChild(deleteBtn);\n tooltip.appendChild(tooltipActions);\n el.appendChild(tooltip);\n\n this.positionMarker(el, annotation);\n this.container.appendChild(el);\n this.markers.set(annotation.id, { el, annotation });\n }\n\n private updateMarker(annotation: Annotation): void {\n const marker = this.markers.get(annotation.id);\n if (marker) {\n marker.annotation = annotation;\n marker.el.setAttribute('data-resolved', String(annotation.resolved));\n }\n }\n\n private removeMarker(id: string): void {\n const marker = this.markers.get(id);\n if (marker) {\n marker.el.remove();\n this.markers.delete(id);\n this.renumber();\n }\n }\n\n private renumber(): void {\n let i = 1;\n for (const [, marker] of this.markers) {\n const firstText = marker.el.childNodes[0];\n if (firstText && firstText.nodeType === Node.TEXT_NODE) {\n firstText.textContent = String(i);\n }\n i++;\n }\n }\n\n private positionMarker(el: HTMLElement, annotation: Annotation): void {\n const target = this.queryTarget(annotation.targetSelector);\n if (target) {\n const rect = target.getBoundingClientRect();\n el.style.top = `${rect.top - 8}px`;\n el.style.left = `${rect.right - 8}px`;\n } else {\n el.style.top = `${annotation.targetRect.y - 8}px`;\n el.style.left = `${annotation.targetRect.x + annotation.targetRect.width - 8}px`;\n }\n }\n\n private queryTarget(selector: string): Element | null {\n try {\n return document.querySelector(selector);\n } catch {\n return null;\n }\n }\n\n setColor(color: string): void {\n this.color = color;\n for (const [, marker] of this.markers) {\n marker.el.style.background = color;\n }\n }\n\n clearAll(): void {\n for (const [id] of this.markers) {\n this.removeMarker(id);\n }\n }\n\n private repositionAll(): void {\n if (this.rafId !== null) return;\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n for (const [, marker] of this.markers) {\n this.positionMarker(marker.el, marker.annotation);\n }\n });\n }\n}\n","const MARKER_COLORS = [\n { id: 'purple', color: '#7C3AED' },\n { id: 'blue', color: '#2563EB' },\n { id: 'green', color: '#059669' },\n { id: 'yellow', color: '#D97706' },\n { id: 'orange', color: '#EA580C' },\n { id: 'red', color: '#DC2626' },\n { id: 'pink', color: '#DB2777' },\n];\n\nexport interface Settings {\n clearOnCopy: boolean;\n blockInteractions: boolean;\n markerColor: string;\n}\n\nexport class SettingsPanel {\n readonly el: HTMLElement;\n private visible = false;\n private mcpDot!: HTMLElement;\n private mcpLabel!: HTMLElement;\n private settings: Settings = {\n clearOnCopy: false,\n blockInteractions: true,\n markerColor: '#7C3AED',\n };\n\n onChange?: (settings: Settings) => void;\n\n constructor(private root: ShadowRoot) {\n this.el = document.createElement('div');\n this.el.className = 'settings-panel hidden';\n this.render();\n root.appendChild(this.el);\n }\n\n private render(): void {\n // Header\n const header = document.createElement('div');\n header.className = 'settings-header';\n const title = document.createElement('span');\n title.className = 'settings-title';\n title.textContent = 'reFiner';\n const version = document.createElement('span');\n version.className = 'settings-version';\n version.textContent = 'v0.1.0';\n header.appendChild(title);\n header.appendChild(version);\n this.el.appendChild(header);\n\n this.el.appendChild(this.createDivider());\n\n // Marker color\n const colorSection = document.createElement('div');\n colorSection.className = 'settings-section';\n const colorLabel = document.createElement('span');\n colorLabel.className = 'settings-label';\n colorLabel.textContent = 'Marker Colour';\n colorSection.appendChild(colorLabel);\n\n const colorRow = document.createElement('div');\n colorRow.className = 'settings-color-row';\n for (const mc of MARKER_COLORS) {\n const swatch = document.createElement('button');\n swatch.className = 'settings-swatch';\n swatch.style.background = mc.color;\n swatch.setAttribute('data-color', mc.color);\n if (mc.color === this.settings.markerColor) {\n swatch.classList.add('selected');\n }\n swatch.addEventListener('click', () => {\n colorRow.querySelectorAll('.settings-swatch').forEach((s) =>\n s.classList.remove('selected')\n );\n swatch.classList.add('selected');\n this.settings.markerColor = mc.color;\n this.emitChange();\n });\n colorRow.appendChild(swatch);\n }\n colorSection.appendChild(colorRow);\n this.el.appendChild(colorSection);\n\n this.el.appendChild(this.createDivider());\n\n // Clear on copy\n this.el.appendChild(this.createCheckbox(\n 'Clear on copy',\n this.settings.clearOnCopy,\n (checked) => {\n this.settings.clearOnCopy = checked;\n this.emitChange();\n },\n ));\n\n // Block page interactions\n this.el.appendChild(this.createCheckbox(\n 'Block page interactions',\n this.settings.blockInteractions,\n (checked) => {\n this.settings.blockInteractions = checked;\n this.emitChange();\n },\n ));\n\n this.el.appendChild(this.createDivider());\n\n // MCP status\n const mcpRow = document.createElement('div');\n mcpRow.className = 'settings-mcp-row';\n\n this.mcpDot = document.createElement('span');\n this.mcpDot.className = 'settings-mcp-dot disconnected';\n\n this.mcpLabel = document.createElement('span');\n this.mcpLabel.className = 'settings-check-label';\n this.mcpLabel.textContent = 'MCP Disconnected';\n\n mcpRow.appendChild(this.mcpDot);\n mcpRow.appendChild(this.mcpLabel);\n this.el.appendChild(mcpRow);\n }\n\n private createCheckbox(label: string, initial: boolean, onChange: (v: boolean) => void): HTMLElement {\n const row = document.createElement('label');\n row.className = 'settings-check-row';\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.className = 'settings-checkbox';\n checkbox.checked = initial;\n checkbox.addEventListener('change', () => onChange(checkbox.checked));\n\n const text = document.createElement('span');\n text.className = 'settings-check-label';\n text.textContent = label;\n\n row.appendChild(checkbox);\n row.appendChild(text);\n return row;\n }\n\n private createDivider(): HTMLElement {\n const div = document.createElement('div');\n div.className = 'settings-divider';\n return div;\n }\n\n private emitChange(): void {\n this.onChange?.({ ...this.settings });\n }\n\n toggle(): void {\n this.visible = !this.visible;\n this.el.classList.toggle('hidden', !this.visible);\n }\n\n hide(): void {\n this.visible = false;\n this.el.classList.add('hidden');\n }\n\n isVisible(): boolean {\n return this.visible;\n }\n\n setMcpStatus(connected: boolean): void {\n this.mcpDot.className = `settings-mcp-dot ${connected ? 'connected' : 'disconnected'}`;\n this.mcpLabel.textContent = connected ? 'MCP Connected' : 'MCP Disconnected';\n }\n\n getSettings(): Settings {\n return { ...this.settings };\n }\n}\n","import { AnnotationStore } from './annotation-store';\nimport { Annotation } from './types';\n\nexport class McpBridge {\n private baseUrl: string;\n private sessionId: string | null = null;\n private connected = false;\n private retryTimer: ReturnType<typeof setInterval> | null = null;\n\n onChange?: (connected: boolean) => void;\n\n constructor(\n private store: AnnotationStore,\n port: number = 4848,\n ) {\n this.baseUrl = `http://localhost:${port}`;\n this.discover();\n\n // Wire up store events\n this.store.on('add', (annotation) => this.postAnnotation(annotation));\n this.store.on('resolve', (annotation) => this.patchAnnotation(annotation));\n }\n\n private async discover(): Promise<void> {\n try {\n const res = await fetch(`${this.baseUrl}/health`);\n const data = await res.json();\n if (data && typeof data === 'object' && 'status' in data && data.status === 'ok') {\n this.connected = true;\n this.onChange?.(true);\n await this.createSession();\n this.stopRetry();\n }\n } catch {\n this.connected = false;\n this.onChange?.(false);\n this.startRetry();\n }\n }\n\n private startRetry(): void {\n if (this.retryTimer) return;\n this.retryTimer = setInterval(() => this.discover(), 5000);\n }\n\n private stopRetry(): void {\n if (this.retryTimer) {\n clearInterval(this.retryTimer);\n this.retryTimer = null;\n }\n }\n\n private async createSession(): Promise<void> {\n try {\n const res = await fetch(`${this.baseUrl}/sessions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n url: window.location.href,\n title: document.title || window.location.pathname,\n }),\n });\n const session = await res.json();\n this.sessionId = session.id;\n } catch {\n // Session creation failed — annotations won't sync but local still works\n }\n }\n\n private async postAnnotation(annotation: Annotation): Promise<void> {\n if (!this.connected || !this.sessionId) return;\n\n try {\n await fetch(`${this.baseUrl}/sessions/${this.sessionId}/annotations`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n targetSelector: annotation.targetSelector,\n targetRect: annotation.targetRect,\n text: annotation.text,\n }),\n });\n } catch {\n // Silently fail — local annotation still exists\n }\n }\n\n private async patchAnnotation(annotation: Annotation): Promise<void> {\n if (!this.connected) return;\n\n try {\n await fetch(`${this.baseUrl}/annotations/${annotation.id}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n resolved: true,\n summary: 'Resolved from browser',\n }),\n });\n } catch {\n // Silently fail\n }\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n destroy(): void {\n this.stopRetry();\n }\n}\n","import { RefinerOptions } from './types';\nimport { STYLES } from './styles';\nimport { AnnotationStore } from './annotation-store';\nimport { Toolbar } from './toolbar';\nimport { Overlay } from './overlay';\nimport { AnnotationDialog } from './annotation-dialog';\nimport { AnnotationMarkers } from './annotation-marker';\nimport { SettingsPanel } from './settings';\nimport { generateSelector } from './selector';\nimport { McpBridge } from './mcp-bridge';\n\nexport class Refiner {\n private host: HTMLDivElement;\n private shadow: ShadowRoot;\n private store: AnnotationStore;\n private toolbar: Toolbar;\n private overlay: Overlay;\n private dialog: AnnotationDialog;\n private markers: AnnotationMarkers;\n private settings: SettingsPanel;\n private mcpBridge: McpBridge | null = null;\n private currentTarget: Element | null = null;\n private currentRect: DOMRect | null = null;\n private clearOnCopy = false;\n\n constructor(options: RefinerOptions = {}) {\n // Create shadow host\n this.host = document.createElement('div');\n this.host.id = 'refiner-host';\n this.shadow = this.host.attachShadow({ mode: 'open' });\n\n // Inject styles\n const style = document.createElement('style');\n style.textContent = STYLES;\n this.shadow.appendChild(style);\n\n // Initialize components\n this.store = new AnnotationStore();\n this.toolbar = new Toolbar(this.shadow);\n this.settings = new SettingsPanel(this.shadow);\n this.overlay = new Overlay(this.shadow);\n this.dialog = new AnnotationDialog(this.shadow);\n this.markers = new AnnotationMarkers(this.shadow, this.store);\n\n // Wire up toolbar\n this.toolbar.onCopy = () => this.copyAnnotations();\n this.toolbar.onClear = () => this.clearAnnotations();\n this.toolbar.onSettings = () => {\n this.settings.toggle();\n this.toolbar.setSettingsOpen(this.settings.isVisible());\n };\n\n this.toolbar.onCollapse = () => {\n this.settings.hide();\n this.toolbar.setSettingsOpen(false);\n };\n\n // Wire up settings\n this.settings.onChange = (s) => {\n this.clearOnCopy = s.clearOnCopy;\n this.overlay.setBlocking(s.blockInteractions);\n this.markers.setColor(s.markerColor);\n this.overlay.setHighlightColor(s.markerColor);\n };\n\n // Wire up overlay click\n this.overlay.onClick = (target, rect) => {\n if (this.settings.isVisible()) {\n this.settings.hide();\n return;\n }\n if (this.dialog.isVisible()) {\n this.dialog.hide();\n return;\n }\n this.currentTarget = target;\n this.currentRect = rect;\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n this.dialog.show(centerX, centerY);\n };\n\n // Wire up dialog submit\n this.dialog.onSubmit = (text) => {\n if (this.currentTarget && this.currentRect) {\n const selector = generateSelector(this.currentTarget);\n this.store.add(selector, this.currentRect, text);\n this.toolbar.updateCount(this.store.getCount());\n }\n this.currentTarget = null;\n this.currentRect = null;\n };\n\n this.dialog.onCancel = () => {\n this.currentTarget = null;\n this.currentRect = null;\n };\n\n // Update count on resolve/remove\n this.store.on('resolve', () => this.toolbar.updateCount(this.store.getCount()));\n this.store.on('remove', () => this.toolbar.updateCount(this.store.getCount()));\n\n // MCP bridge (auto-discover by default)\n if (options.mcpEnabled !== false) {\n this.mcpBridge = new McpBridge(this.store, options.mcpPort);\n this.mcpBridge.onChange = (connected) => {\n this.settings.setMcpStatus(connected);\n };\n }\n\n // Mount\n document.body.appendChild(this.host);\n\n if (options.enabled === false) {\n this.disable();\n }\n }\n\n enable(): void {\n this.host.style.display = '';\n this.overlay.setEnabled(true);\n }\n\n disable(): void {\n this.host.style.display = 'none';\n this.overlay.setEnabled(false);\n }\n\n destroy(): void {\n this.mcpBridge?.destroy();\n this.host.remove();\n }\n\n getAnnotations() {\n return this.store.getAll();\n }\n\n getAnnotationCount(): number {\n return this.store.getCount();\n }\n\n formatForAgent(): string {\n const annotations = this.store.getAll();\n if (annotations.length === 0) return 'No annotations.';\n\n const pageTitle = document.title || window.location.pathname;\n const lines: string[] = [`# Design Annotations — ${pageTitle}`, ''];\n\n for (let i = 0; i < annotations.length; i++) {\n const a = annotations[i];\n const status = a.resolved ? ' (resolved)' : '';\n lines.push(`## ${i + 1}.${status}`);\n lines.push(`**Element:** \\`${a.targetSelector}\\``);\n lines.push(`**Issue:** ${a.text}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n\n clearAnnotations(): void {\n const all = this.store.getAll();\n for (const a of all) {\n this.store.remove(a.id);\n }\n this.toolbar.updateCount(0);\n }\n\n copyAnnotations(): void {\n const text = this.formatForAgent();\n navigator.clipboard.writeText(text);\n\n if (this.clearOnCopy) {\n this.clearAnnotations();\n }\n }\n}\n","export const STYLES = `\n :host {\n all: initial;\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n color: #1a1a2e;\n }\n\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* ── Toolbar ── */\n\n .refiner-toolbar {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10;\n user-select: none;\n }\n\n .toolbar-pill {\n display: flex;\n align-items: center;\n position: relative;\n background: #1a1a2e;\n border-radius: 100px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15);\n padding: 6px;\n transform: scale(1);\n transform-origin: right center;\n transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n .refiner-toolbar[data-collapsed=\"true\"] .toolbar-pill {\n transform: scale(0.92);\n }\n\n .toolbar-inner {\n display: flex;\n align-items: center;\n gap: 2px;\n overflow: hidden;\n clip-path: inset(0);\n max-width: 300px;\n opacity: 1;\n padding-right: 2px;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s ease 0.1s,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .refiner-toolbar[data-collapsed=\"true\"] .toolbar-inner {\n max-width: 0;\n opacity: 0;\n padding-right: 0;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.15s ease,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .toolbar-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: #a0a0b8;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n\n .toolbar-btn:hover {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .toolbar-btn.active {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n }\n\n .toolbar-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .toolbar-count {\n font-size: 14px;\n font-weight: 700;\n min-width: 18px;\n text-align: center;\n }\n\n .toolbar-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n margin: 0 4px;\n flex-shrink: 0;\n }\n\n /* Tooltip */\n .toolbar-tooltip {\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 10px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n\n .toolbar-tooltip::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1a1a2e;\n }\n\n .toolbar-btn:hover .toolbar-tooltip {\n opacity: 1;\n }\n\n .tooltips-hidden .toolbar-tooltip {\n display: none;\n }\n\n .toolbar-btn.disabled {\n opacity: 0.3;\n cursor: default;\n }\n\n .toolbar-btn.disabled:hover {\n color: #a0a0b8;\n background: transparent;\n }\n\n /* Toggle button (always visible) */\n .toolbar-toggle-btn {\n flex-shrink: 0;\n }\n\n /* Badge for collapsed state */\n .toolbar-expand-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n border-radius: 10px;\n background: #DC2626;\n color: #ffffff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);\n }\n\n .toolbar-expand-badge.hidden {\n display: none;\n }\n\n /* ── Settings Panel ── */\n\n .settings-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 300px;\n z-index: 12;\n background: #1a1a2e;\n border-radius: 16px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 20px;\n color: #e8e8f0;\n transform-origin: bottom right;\n transition: transform 0.25s ease, opacity 0.1s ease;\n transform: scale(1);\n opacity: 1;\n }\n\n .settings-panel.hidden {\n transform: scale(0.4);\n opacity: 0;\n pointer-events: none;\n }\n\n .settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n }\n\n .settings-title {\n font-size: 16px;\n font-weight: 700;\n font-style: normal;\n color: #ffffff;\n }\n\n .settings-version {\n font-size: 12px;\n color: #6b6b80;\n font-weight: 500;\n }\n\n .settings-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.08);\n margin: 16px 0;\n }\n\n .settings-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .settings-label {\n font-size: 14px;\n font-weight: 500;\n color: #c0c0d0;\n }\n\n .settings-color-row {\n display: flex;\n gap: 8px;\n }\n\n .settings-swatch {\n width: 24px;\n height: 24px;\n border-radius: 4px;\n border: 2px solid transparent;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s;\n outline: none;\n }\n\n .settings-swatch:hover {\n transform: scale(1.1);\n }\n\n .settings-swatch.selected {\n border-color: #ffffff;\n transform: scale(1.1);\n }\n\n .settings-check-row {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n padding: 2px 0;\n }\n\n .settings-checkbox {\n appearance: none;\n -webkit-appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 5px;\n border: 2px solid #4a4a60;\n background: transparent;\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n transition: background 0.15s, border-color 0.15s;\n }\n\n .settings-checkbox:checked {\n background: #2563EB;\n border-color: #2563EB;\n }\n\n .settings-checkbox:checked::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 5px;\n width: 5px;\n height: 9px;\n border: solid #ffffff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .settings-check-label {\n font-size: 14px;\n font-weight: 500;\n color: #e8e8f0;\n }\n\n /* ── Overlay ── */\n\n .refiner-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n cursor: crosshair;\n z-index: 1;\n }\n\n .refiner-overlay[data-blocking=\"true\"] {\n pointer-events: all;\n }\n\n .refiner-overlay[data-blocking=\"false\"] {\n pointer-events: none;\n }\n\n .refiner-overlay.hidden {\n display: none;\n }\n\n /* ── Highlight ── */\n\n .refiner-highlight {\n position: fixed;\n pointer-events: none;\n border: 2px dashed;\n border-radius: 3px;\n z-index: 2;\n transition: all 0.1s ease;\n }\n\n /* ── Dialog ── */\n\n .refiner-dialog {\n position: fixed;\n width: 320px;\n background: #1a1a2e;\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 14px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 16px;\n z-index: 11;\n color: #e8e8f0;\n animation: dialog-in 0.2s ease;\n }\n\n @keyframes dialog-in {\n from { opacity: 0; transform: translateY(4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n\n .refiner-dialog.hidden {\n display: none;\n }\n\n .dialog-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .dialog-header span {\n font-size: 12px;\n font-weight: 600;\n color: #c0c0d0;\n }\n\n .dialog-textarea {\n width: 100%;\n min-height: 72px;\n padding: 10px 12px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: #e8e8f0;\n background: rgba(255, 255, 255, 0.06);\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .dialog-textarea:focus {\n border-color: rgba(255, 255, 255, 0.25);\n }\n\n .dialog-textarea::placeholder {\n color: #6b6b80;\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 12px;\n }\n\n .dialog-btn {\n height: 32px;\n padding: 0 14px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .dialog-btn-cancel {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: #a0a0b8;\n }\n\n .dialog-btn-cancel:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #e8e8f0;\n }\n\n .dialog-btn-add {\n background: #2563EB;\n border: none;\n color: #ffffff;\n }\n\n .dialog-btn-add:hover {\n background: #3B82F6;\n }\n\n .dialog-btn-add:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n\n /* ── Markers ── */\n\n .refiner-marker {\n position: fixed;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: transform 0.15s;\n pointer-events: all;\n }\n\n .refiner-marker:hover {\n transform: scale(1.2);\n }\n\n .refiner-marker[data-resolved=\"true\"] {\n opacity: 0.4;\n }\n\n .marker-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n width: 220px;\n padding: 10px 12px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n line-height: 1.4;\n border-radius: 10px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .refiner-marker:hover .marker-tooltip {\n opacity: 1;\n }\n\n .marker-tooltip-actions {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n border-top: 1px solid rgba(255,255,255,0.1);\n padding-top: 8px;\n }\n\n .marker-tooltip-btn {\n height: 22px;\n padding: 0 8px;\n border-radius: 5px;\n border: none;\n font-size: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .marker-tooltip-btn.resolve {\n background: #34D399;\n color: #0a2e1f;\n }\n\n .marker-tooltip-btn.resolve:hover {\n background: #4ade80;\n }\n\n .marker-tooltip-btn.delete {\n background: rgba(255,255,255,0.1);\n color: #e8e8f0;\n }\n\n .marker-tooltip-btn.delete:hover {\n background: #FF6B6B;\n color: #fff;\n }\n\n /* MCP status */\n .settings-mcp-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n\n .settings-mcp-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .settings-mcp-dot.connected {\n background: #34D399;\n box-shadow: 0 0 6px #34D39980;\n }\n\n .settings-mcp-dot.disconnected {\n background: #6B7280;\n }\n`;\n","/**\n * Generate a stable CSS selector for a DOM element.\n * Priority: #id > tag.class > nth-child path\n */\nexport function generateSelector(el: Element): string {\n if (el.id) {\n return `#${CSS.escape(el.id)}`;\n }\n\n // Try tag + distinctive class\n if (el.classList.length > 0) {\n const tag = el.tagName.toLowerCase();\n const classSelector = `${tag}.${Array.from(el.classList).map(CSS.escape).join('.')}`;\n if (document.querySelectorAll(classSelector).length === 1) {\n return classSelector;\n }\n }\n\n // Build nth-child path\n const parts: string[] = [];\n let current: Element | null = el;\n\n while (current && current !== document.documentElement) {\n const tag = current.tagName.toLowerCase();\n const parent: Element | null = current.parentElement;\n\n if (current.id) {\n parts.unshift(`#${CSS.escape(current.id)}`);\n break;\n }\n\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n (c: Element) => c.tagName === current!.tagName\n );\n if (siblings.length === 1) {\n parts.unshift(tag);\n } else {\n const index = siblings.indexOf(current) + 1;\n parts.unshift(`${tag}:nth-child(${index})`);\n }\n } else {\n parts.unshift(tag);\n }\n\n current = parent;\n }\n\n return parts.join(' > ');\n}\n","import { Refiner } from './refiner';\nimport type { Annotation, RefinerOptions } from './types';\n\nexport { Refiner };\nexport type { Annotation, RefinerOptions };\n\n// Auto-initialize when loaded via script tag\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const init = () => {\n // Skip if already initialized (e.g. bookmarklet + script tag both present)\n if ((window as any).__refiner) return;\n\n // Read config from script tag data attributes\n const script = document.currentScript as HTMLScriptElement | null;\n const position = (script?.dataset.refinerPosition as 'left' | 'right') ?? 'right';\n const enabled = script?.dataset.refinerEnabled !== 'false';\n const mcpPort = script?.dataset.refinerMcpPort ? parseInt(script.dataset.refinerMcpPort, 10) : undefined;\n const mcpEnabled = script?.dataset.refinerMcpEnabled !== 'false';\n\n const refiner = new Refiner({ position, enabled, mcpPort, mcpEnabled });\n (window as any).__refiner = refiner;\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init);\n } else {\n init();\n }\n}\n"],"names":["AnnotationStore","constructor","this","annotations","Map","listeners","add","targetSelector","targetRect","text","annotation","id","crypto","randomUUID","x","y","width","height","timestamp","Date","now","resolved","set","emit","resolve","get","remove","delete","getAll","Array","from","values","getPending","filter","a","getCount","size","exportJSON","JSON","stringify","on","event","listener","has","Set","off","forEach","fn","Toolbar","root","collapsed","settingsOpen","el","document","createElement","className","setAttribute","render","appendChild","requestAnimationFrame","updateBadgeVisibility","pill","innerEl","countBadge","textContent","createBtn","copyIcon","copyBtn","classList","contains","onCopy","querySelector","innerHTML","setTimeout","clearBtn","onClear","onSettings","divider","penIcon","toggleBtn","toggleCollapse","expandBadge","addEventListener","content","tooltip","onClick","btn","iconWrap","tip","String","onCollapse","setSettingsOpen","open","toggle","updateCount","count","empty","c","parseInt","Overlay","enabled","blocking","currentTarget","highlightColor","handleMouseMove","e","isOverOwnUI","clientX","clientY","hideHighlight","target","getElementAt","showHighlight","handleClick","preventDefault","stopPropagation","rect","getBoundingClientRect","highlight","style","display","shadowEl","elementFromPoint","pointerEvents","host","top","left","borderColor","setHighlightColor","color","setBlocking","setEnabled","AnnotationDialog","header","label","textarea","placeholder","addBtn","disabled","value","trim","length","key","metaKey","ctrlKey","submit","hide","onCancel","actions","cancelBtn","onSubmit","show","window","innerWidth","innerHeight","Math","max","focus","isVisible","AnnotationMarkers","store","markers","rafId","container","addMarker","updateMarker","removeMarker","reposition","repositionAll","passive","background","index","tooltipText","tooltipActions","resolveBtn","deleteBtn","positionMarker","marker","renumber","i","firstText","childNodes","nodeType","Node","TEXT_NODE","queryTarget","right","selector","setColor","clearAll","MARKER_COLORS","SettingsPanel","visible","settings","clearOnCopy","blockInteractions","markerColor","title","version","createDivider","colorSection","colorLabel","colorRow","mc","swatch","querySelectorAll","s","emitChange","createCheckbox","checked","mcpRow","mcpDot","mcpLabel","initial","onChange","row","checkbox","type","div","setMcpStatus","connected","getSettings","McpBridge","port","sessionId","retryTimer","baseUrl","discover","postAnnotation","patchAnnotation","res","fetch","data","json","status","createSession","stopRetry","startRetry","setInterval","clearInterval","method","headers","body","url","location","href","pathname","session","summary","isConnected","destroy","Refiner","options","mcpBridge","currentRect","shadow","attachShadow","mode","toolbar","overlay","dialog","copyAnnotations","clearAnnotations","centerX","centerY","CSS","escape","classSelector","tagName","toLowerCase","map","join","parts","current","documentElement","tag","parent","parentElement","unshift","siblings","children","indexOf","generateSelector","mcpEnabled","mcpPort","disable","enable","getAnnotations","getAnnotationCount","formatForAgent","lines","push","all","navigator","clipboard","writeText","init","__refiner","script","currentScript","position","dataset","refinerPosition","refinerEnabled","refinerMcpPort","undefined","refinerMcpEnabled","refiner","readyState"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generate a stable CSS selector for a DOM element.
3
+ * Priority: #id > tag.class > nth-child path
4
+ */
5
+ export declare function generateSelector(el: Element): string;
@@ -0,0 +1,24 @@
1
+ export interface Settings {
2
+ clearOnCopy: boolean;
3
+ blockInteractions: boolean;
4
+ markerColor: string;
5
+ }
6
+ export declare class SettingsPanel {
7
+ private root;
8
+ readonly el: HTMLElement;
9
+ private visible;
10
+ private mcpDot;
11
+ private mcpLabel;
12
+ private settings;
13
+ onChange?: (settings: Settings) => void;
14
+ constructor(root: ShadowRoot);
15
+ private render;
16
+ private createCheckbox;
17
+ private createDivider;
18
+ private emitChange;
19
+ toggle(): void;
20
+ hide(): void;
21
+ isVisible(): boolean;
22
+ setMcpStatus(connected: boolean): void;
23
+ getSettings(): Settings;
24
+ }
@@ -0,0 +1 @@
1
+ export declare const STYLES = "\n :host {\n all: initial;\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;\n font-size: 13px;\n line-height: 1.4;\n color: #1a1a2e;\n }\n\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* \u2500\u2500 Toolbar \u2500\u2500 */\n\n .refiner-toolbar {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10;\n user-select: none;\n }\n\n .toolbar-pill {\n display: flex;\n align-items: center;\n position: relative;\n background: #1a1a2e;\n border-radius: 100px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15);\n padding: 6px;\n transform: scale(1);\n transform-origin: right center;\n transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n\n .refiner-toolbar[data-collapsed=\"true\"] .toolbar-pill {\n transform: scale(0.92);\n }\n\n .toolbar-inner {\n display: flex;\n align-items: center;\n gap: 2px;\n overflow: hidden;\n clip-path: inset(0);\n max-width: 300px;\n opacity: 1;\n padding-right: 2px;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s ease 0.1s,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .refiner-toolbar[data-collapsed=\"true\"] .toolbar-inner {\n max-width: 0;\n opacity: 0;\n padding-right: 0;\n transition: max-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.15s ease,\n padding 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .toolbar-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: #a0a0b8;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n\n .toolbar-btn:hover {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .toolbar-btn.active {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.15);\n }\n\n .toolbar-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .toolbar-count {\n font-size: 14px;\n font-weight: 700;\n min-width: 18px;\n text-align: center;\n }\n\n .toolbar-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.15);\n margin: 0 4px;\n flex-shrink: 0;\n }\n\n /* Tooltip */\n .toolbar-tooltip {\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 10px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n font-weight: 500;\n white-space: nowrap;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n\n .toolbar-tooltip::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1a1a2e;\n }\n\n .toolbar-btn:hover .toolbar-tooltip {\n opacity: 1;\n }\n\n .tooltips-hidden .toolbar-tooltip {\n display: none;\n }\n\n .toolbar-btn.disabled {\n opacity: 0.3;\n cursor: default;\n }\n\n .toolbar-btn.disabled:hover {\n color: #a0a0b8;\n background: transparent;\n }\n\n /* Toggle button (always visible) */\n .toolbar-toggle-btn {\n flex-shrink: 0;\n }\n\n /* Badge for collapsed state */\n .toolbar-expand-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n border-radius: 10px;\n background: #DC2626;\n color: #ffffff;\n font-size: 11px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);\n }\n\n .toolbar-expand-badge.hidden {\n display: none;\n }\n\n /* \u2500\u2500 Settings Panel \u2500\u2500 */\n\n .settings-panel {\n position: fixed;\n bottom: 80px;\n right: 24px;\n width: 300px;\n z-index: 12;\n background: #1a1a2e;\n border-radius: 16px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 20px;\n color: #e8e8f0;\n transform-origin: bottom right;\n transition: transform 0.25s ease, opacity 0.1s ease;\n transform: scale(1);\n opacity: 1;\n }\n\n .settings-panel.hidden {\n transform: scale(0.4);\n opacity: 0;\n pointer-events: none;\n }\n\n .settings-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n }\n\n .settings-title {\n font-size: 16px;\n font-weight: 700;\n font-style: normal;\n color: #ffffff;\n }\n\n .settings-version {\n font-size: 12px;\n color: #6b6b80;\n font-weight: 500;\n }\n\n .settings-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.08);\n margin: 16px 0;\n }\n\n .settings-section {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .settings-label {\n font-size: 14px;\n font-weight: 500;\n color: #c0c0d0;\n }\n\n .settings-color-row {\n display: flex;\n gap: 8px;\n }\n\n .settings-swatch {\n width: 24px;\n height: 24px;\n border-radius: 4px;\n border: 2px solid transparent;\n cursor: pointer;\n transition: transform 0.15s, border-color 0.15s;\n outline: none;\n }\n\n .settings-swatch:hover {\n transform: scale(1.1);\n }\n\n .settings-swatch.selected {\n border-color: #ffffff;\n transform: scale(1.1);\n }\n\n .settings-check-row {\n display: flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n padding: 2px 0;\n }\n\n .settings-checkbox {\n appearance: none;\n -webkit-appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 5px;\n border: 2px solid #4a4a60;\n background: transparent;\n cursor: pointer;\n position: relative;\n flex-shrink: 0;\n transition: background 0.15s, border-color 0.15s;\n }\n\n .settings-checkbox:checked {\n background: #2563EB;\n border-color: #2563EB;\n }\n\n .settings-checkbox:checked::after {\n content: '';\n position: absolute;\n top: 2px;\n left: 5px;\n width: 5px;\n height: 9px;\n border: solid #ffffff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .settings-check-label {\n font-size: 14px;\n font-weight: 500;\n color: #e8e8f0;\n }\n\n /* \u2500\u2500 Overlay \u2500\u2500 */\n\n .refiner-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n cursor: crosshair;\n z-index: 1;\n }\n\n .refiner-overlay[data-blocking=\"true\"] {\n pointer-events: all;\n }\n\n .refiner-overlay[data-blocking=\"false\"] {\n pointer-events: none;\n }\n\n .refiner-overlay.hidden {\n display: none;\n }\n\n /* \u2500\u2500 Highlight \u2500\u2500 */\n\n .refiner-highlight {\n position: fixed;\n pointer-events: none;\n border: 2px dashed;\n border-radius: 3px;\n z-index: 2;\n transition: all 0.1s ease;\n }\n\n /* \u2500\u2500 Dialog \u2500\u2500 */\n\n .refiner-dialog {\n position: fixed;\n width: 320px;\n background: #1a1a2e;\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 14px;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3), 0 4px 12px rgba(0, 0, 0, 0.2);\n padding: 16px;\n z-index: 11;\n color: #e8e8f0;\n animation: dialog-in 0.2s ease;\n }\n\n @keyframes dialog-in {\n from { opacity: 0; transform: translateY(4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n\n .refiner-dialog.hidden {\n display: none;\n }\n\n .dialog-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .dialog-header span {\n font-size: 12px;\n font-weight: 600;\n color: #c0c0d0;\n }\n\n .dialog-textarea {\n width: 100%;\n min-height: 72px;\n padding: 10px 12px;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: #e8e8f0;\n background: rgba(255, 255, 255, 0.06);\n resize: vertical;\n outline: none;\n transition: border-color 0.15s;\n }\n\n .dialog-textarea:focus {\n border-color: rgba(255, 255, 255, 0.25);\n }\n\n .dialog-textarea::placeholder {\n color: #6b6b80;\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 12px;\n }\n\n .dialog-btn {\n height: 32px;\n padding: 0 14px;\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .dialog-btn-cancel {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: #a0a0b8;\n }\n\n .dialog-btn-cancel:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #e8e8f0;\n }\n\n .dialog-btn-add {\n background: #2563EB;\n border: none;\n color: #ffffff;\n }\n\n .dialog-btn-add:hover {\n background: #3B82F6;\n }\n\n .dialog-btn-add:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n\n /* \u2500\u2500 Markers \u2500\u2500 */\n\n .refiner-marker {\n position: fixed;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: transform 0.15s;\n pointer-events: all;\n }\n\n .refiner-marker:hover {\n transform: scale(1.2);\n }\n\n .refiner-marker[data-resolved=\"true\"] {\n opacity: 0.4;\n }\n\n .marker-tooltip {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n width: 220px;\n padding: 10px 12px;\n background: #1a1a2e;\n color: #e8e8f0;\n font-size: 12px;\n line-height: 1.4;\n border-radius: 10px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .refiner-marker:hover .marker-tooltip {\n opacity: 1;\n }\n\n .marker-tooltip-actions {\n display: flex;\n gap: 6px;\n margin-top: 8px;\n border-top: 1px solid rgba(255,255,255,0.1);\n padding-top: 8px;\n }\n\n .marker-tooltip-btn {\n height: 22px;\n padding: 0 8px;\n border-radius: 5px;\n border: none;\n font-size: 10px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .marker-tooltip-btn.resolve {\n background: #34D399;\n color: #0a2e1f;\n }\n\n .marker-tooltip-btn.resolve:hover {\n background: #4ade80;\n }\n\n .marker-tooltip-btn.delete {\n background: rgba(255,255,255,0.1);\n color: #e8e8f0;\n }\n\n .marker-tooltip-btn.delete:hover {\n background: #FF6B6B;\n color: #fff;\n }\n\n /* MCP status */\n .settings-mcp-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n\n .settings-mcp-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n .settings-mcp-dot.connected {\n background: #34D399;\n box-shadow: 0 0 6px #34D39980;\n }\n\n .settings-mcp-dot.disconnected {\n background: #6B7280;\n }\n";
@@ -0,0 +1,23 @@
1
+ export declare class Toolbar {
2
+ private root;
3
+ readonly el: HTMLElement;
4
+ private collapsed;
5
+ private countBadge;
6
+ private expandBadge;
7
+ private innerEl;
8
+ private copyBtn;
9
+ private clearBtn;
10
+ private toggleBtn;
11
+ private settingsOpen;
12
+ onCopy?: () => void;
13
+ onClear?: () => void;
14
+ onSettings?: () => void;
15
+ onCollapse?: () => void;
16
+ constructor(root: ShadowRoot);
17
+ private render;
18
+ private createBtn;
19
+ private toggleCollapse;
20
+ setSettingsOpen(open: boolean): void;
21
+ updateCount(count: number): void;
22
+ private updateBadgeVisibility;
23
+ }
@@ -0,0 +1,19 @@
1
+ export interface Annotation {
2
+ id: string;
3
+ targetSelector: string;
4
+ targetRect: {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ };
10
+ text: string;
11
+ timestamp: number;
12
+ resolved: boolean;
13
+ }
14
+ export interface RefinerOptions {
15
+ enabled?: boolean;
16
+ position?: 'left' | 'right';
17
+ mcpPort?: number;
18
+ mcpEnabled?: boolean;
19
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "refinekit",
3
+ "version": "0.1.0",
4
+ "description": "Visual annotation overlay for HTML/CSS design critique",
5
+ "main": "dist/refiner.js",
6
+ "module": "dist/refiner.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "rollup -c",
13
+ "watch": "rollup -c --watch",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "design",
18
+ "annotation",
19
+ "overlay",
20
+ "critique",
21
+ "html",
22
+ "css"
23
+ ],
24
+ "type": "module",
25
+ "license": "MIT",
26
+ "devDependencies": {
27
+ "@rollup/plugin-typescript": "^12.1.2",
28
+ "rollup": "^4.31.0",
29
+ "@rollup/plugin-terser": "^0.4.4",
30
+ "tslib": "^2.8.1",
31
+ "typescript": "^5.7.3"
32
+ }
33
+ }