vite-plugin-ai-annotator 1.14.3 → 1.14.4

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 CHANGED
@@ -28,6 +28,7 @@ Works with all Vite-supported frameworks:
28
28
  - 🅰️ **Angular** - Recognizes components and directives
29
29
  - 🟠 **Svelte** - Identifies components and stores
30
30
  - 📄 **Vanilla JS** - Works with plain HTML/CSS/JS
31
+ - 🟦 **Nuxt.js** - Full support via Nuxt module (Nuxt 3+)
31
32
 
32
33
  ## Installation
33
34
 
@@ -44,13 +45,15 @@ Then ask Claude: *"Set up ai-annotator for my project"* - it handles the rest!
44
45
 
45
46
  ### Option 2: Manual Setup
46
47
 
47
- #### Step 1: Install the package
48
+ #### For Vite Projects
49
+
50
+ ##### Step 1: Install the package
48
51
 
49
52
  ```bash
50
53
  bun add -d vite-plugin-ai-annotator
51
54
  ```
52
55
 
53
- #### Step 2: Add to your Vite config
56
+ ##### Step 2: Add to your Vite config
54
57
 
55
58
  ```typescript
56
59
  import { defineConfig } from 'vite';
@@ -63,7 +66,33 @@ export default defineConfig({
63
66
  });
64
67
  ```
65
68
 
66
- #### Step 3: Configure MCP
69
+ #### For Nuxt.js Projects (Nuxt 3+)
70
+
71
+ ##### Step 1: Install the package
72
+
73
+ ```bash
74
+ bun add -d vite-plugin-ai-annotator
75
+ ```
76
+
77
+ ##### Step 2: Add to your `nuxt.config.ts`
78
+
79
+ ```typescript
80
+ export default defineNuxtConfig({
81
+ modules: [
82
+ 'vite-plugin-ai-annotator/nuxt'
83
+ ],
84
+ // Optional: Configure the annotator
85
+ aiAnnotator: {
86
+ port: 7318,
87
+ autoSetupMcp: true,
88
+ verbose: false,
89
+ }
90
+ })
91
+ ```
92
+
93
+ **That's it!** Nuxt handles the rest automatically.
94
+
95
+ #### Configure MCP (Vite and Nuxt)
67
96
 
68
97
  **Option A: Auto Setup (Recommended)**
69
98
 
@@ -75,6 +104,17 @@ annotator({
75
104
  })
76
105
  ```
77
106
 
107
+ For Nuxt, configure in `nuxt.config.ts`:
108
+
109
+ ```typescript
110
+ export default defineNuxtConfig({
111
+ modules: ['vite-plugin-ai-annotator/nuxt'],
112
+ aiAnnotator: {
113
+ autoSetupMcp: true,
114
+ }
115
+ })
116
+ ```
117
+
78
118
  This automatically creates/updates `.mcp.json`, `.cursor/mcp.json`, and `.vscode/mcp.json` based on your project.
79
119
 
80
120
  **Option B: Manual Setup**
@@ -83,7 +123,7 @@ This automatically creates/updates `.mcp.json`, `.cursor/mcp.json`, and `.vscode
83
123
  claude mcp add annotator -- npx vite-plugin-ai-annotator mcp -s http://localhost:7318
84
124
  ```
85
125
 
86
- #### Step 4: Start your dev server
126
+ #### Step 3: Start your dev server
87
127
 
88
128
  ```bash
89
129
  bun dev
@@ -22,6 +22,7 @@ export declare class AnnotatorToolbar extends LitElement {
22
22
  private tooltipCleanup;
23
23
  private toastTimeout;
24
24
  private clickListenerTimeout;
25
+ private skipNextClickOutside;
25
26
  private socket;
26
27
  private rpc;
27
28
  private selectionManager;
@@ -6389,10 +6389,15 @@
6389
6389
  // src/annotator/constants.ts
6390
6390
  var Z_INDEX = {
6391
6391
  INSPECTION_OVERLAY: 999995,
6392
+ // Mouse inspection hover highlight
6392
6393
  HIGHLIGHT_OVERLAY: 999996,
6394
+ // Selected element marching ants border
6393
6395
  HOVER_OVERLAY: 999997,
6396
+ // Element hover during inspection mode
6394
6397
  BADGE: 999998,
6398
+ // Selection badge with index number
6395
6399
  TOOLBAR: 999999
6400
+ // Bottom-right toolbar UI
6396
6401
  };
6397
6402
  var CONSOLE_LIMITS = {
6398
6403
  MAX_ARG_LENGTH: 1e4,
@@ -7216,14 +7221,17 @@
7216
7221
  let vnode = null;
7217
7222
  if (!codeLocation) {
7218
7223
  const ctxVNode = el.__vnode?.ctx?.vnode;
7219
- if (ctxVNode?.el === el) {
7220
- codeLocation = ctxVNode?.props?.__v_inspector;
7224
+ if (ctxVNode && ctxVNode.el === element) {
7225
+ codeLocation = ctxVNode.props?.__v_inspector;
7221
7226
  }
7222
7227
  }
7223
7228
  if (!codeLocation) {
7224
- codeLocation = el.__vueParentComponent?.vnode?.props?.__v_inspector;
7225
- vueInstance = el.__vueParentComponent ?? null;
7226
- vnode = el.__vueParentComponent?.vnode ?? null;
7229
+ const parentComponent = el.__vueParentComponent;
7230
+ if (parentComponent?.vnode) {
7231
+ codeLocation = parentComponent.vnode.props?.__v_inspector;
7232
+ vueInstance = parentComponent;
7233
+ vnode = parentComponent.vnode;
7234
+ }
7227
7235
  }
7228
7236
  if (!codeLocation) {
7229
7237
  codeLocation = el.__v_inspector;
@@ -7516,6 +7524,7 @@
7516
7524
  this.tooltipCleanup = null;
7517
7525
  this.toastTimeout = null;
7518
7526
  this.clickListenerTimeout = null;
7527
+ this.skipNextClickOutside = false;
7519
7528
  this.socket = null;
7520
7529
  this.rpc = null;
7521
7530
  this.selectionManager = null;
@@ -7533,6 +7542,10 @@
7533
7542
  };
7534
7543
  this.handleClickOutside = (e5) => {
7535
7544
  if (!this.commentPopover.visible) return;
7545
+ if (this.skipNextClickOutside) {
7546
+ this.skipNextClickOutside = false;
7547
+ return;
7548
+ }
7536
7549
  const popoverEl = this.shadowRoot?.querySelector(".popover");
7537
7550
  if (!popoverEl) return;
7538
7551
  const path = e5.composedPath();
@@ -7566,29 +7579,36 @@
7566
7579
  }
7567
7580
  initializeConsoleCapture() {
7568
7581
  try {
7582
+ const originals = {};
7569
7583
  CONSOLE_METHODS.forEach((method) => {
7570
- this.originalConsoleMethods[method] = console[method].bind(console);
7584
+ originals[method] = console[method].bind(console);
7571
7585
  });
7572
7586
  CONSOLE_METHODS.forEach((method) => {
7573
7587
  console[method] = (...args) => {
7574
- this.consoleBuffer.push({
7575
- type: method,
7576
- args: args.map((arg) => {
7588
+ try {
7589
+ const serializedArgs = args.map((arg) => {
7577
7590
  try {
7578
7591
  const str = typeof arg === "object" ? JSON.stringify(arg) : String(arg);
7579
7592
  return str.length > CONSOLE_LIMITS.MAX_ARG_LENGTH ? str.slice(0, CONSOLE_LIMITS.MAX_ARG_LENGTH) + "...[truncated]" : str;
7580
7593
  } catch {
7581
7594
  return "[circular or unserializable]";
7582
7595
  }
7583
- }),
7584
- timestamp: Date.now()
7585
- });
7586
- if (this.consoleBuffer.length > CONSOLE_LIMITS.BUFFER_MAX) {
7587
- this.consoleBuffer = this.consoleBuffer.slice(-CONSOLE_LIMITS.BUFFER_TRIM_TO);
7596
+ });
7597
+ this.consoleBuffer.push({
7598
+ type: method,
7599
+ args: serializedArgs,
7600
+ timestamp: Date.now()
7601
+ });
7602
+ if (this.consoleBuffer.length > CONSOLE_LIMITS.BUFFER_MAX) {
7603
+ this.consoleBuffer = this.consoleBuffer.slice(-CONSOLE_LIMITS.BUFFER_TRIM_TO);
7604
+ }
7605
+ originals[method]?.(...args);
7606
+ } catch (captureError) {
7607
+ originals[method]?.(...args);
7588
7608
  }
7589
- this.originalConsoleMethods[method]?.(...args);
7590
7609
  };
7591
7610
  });
7611
+ this.originalConsoleMethods = originals;
7592
7612
  } catch (error) {
7593
7613
  this.restoreConsoleMethods();
7594
7614
  throw error;
@@ -7630,19 +7650,71 @@
7630
7650
  }
7631
7651
  registerRpcHandlers() {
7632
7652
  if (!this.rpc) return;
7633
- this.rpc.handle.getPageContext(async () => this.getPageContext());
7634
- this.rpc.handle.getSelectedElements(async () => this.getSelectedElements());
7635
- this.rpc.handle.triggerSelection(
7636
- async (mode, selector, selectorType) => this.triggerSelection(mode, selector, selectorType)
7637
- );
7638
- this.rpc.handle.captureScreenshot(
7639
- async (type, selector, quality) => this.captureScreenshot(type, selector, quality)
7640
- );
7641
- this.rpc.handle.clearSelection(async () => this.clearSelection());
7653
+ this.rpc.handle.getPageContext(async () => {
7654
+ try {
7655
+ return await this.getPageContext();
7656
+ } catch (error) {
7657
+ this.log("[getPageContext] Handler error:", error);
7658
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7659
+ }
7660
+ });
7661
+ this.rpc.handle.getSelectedElements(async () => {
7662
+ try {
7663
+ return await this.getSelectedElements();
7664
+ } catch (error) {
7665
+ this.log("[getSelectedElements] Handler error:", error);
7666
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7667
+ }
7668
+ });
7669
+ this.rpc.handle.triggerSelection(async (mode, selector, selectorType) => {
7670
+ try {
7671
+ return await this.triggerSelection(mode, selector, selectorType);
7672
+ } catch (error) {
7673
+ this.log("[triggerSelection] Handler error:", error);
7674
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7675
+ }
7676
+ });
7677
+ this.rpc.handle.captureScreenshot(async (type, selector, quality) => {
7678
+ try {
7679
+ return await this.captureScreenshot(type, selector, quality);
7680
+ } catch (error) {
7681
+ this.log("[captureScreenshot] Handler error:", error);
7682
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7683
+ }
7684
+ });
7685
+ this.rpc.handle.clearSelection(async () => {
7686
+ try {
7687
+ return await this.clearSelection();
7688
+ } catch (error) {
7689
+ this.log("[clearSelection] Handler error:", error);
7690
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7691
+ }
7692
+ });
7642
7693
  this.rpc.handle.ping(async () => "pong");
7643
- this.rpc.handle.injectCSS(async (css) => this.injectCSS(css));
7644
- this.rpc.handle.injectJS(async (code) => this.injectJS(code));
7645
- this.rpc.handle.getConsole(async (clear) => this.getConsoleLogs(clear));
7694
+ this.rpc.handle.injectCSS(async (css) => {
7695
+ try {
7696
+ return await this.injectCSS(css);
7697
+ } catch (error) {
7698
+ this.log("[injectCSS] Handler error:", error);
7699
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7700
+ }
7701
+ });
7702
+ this.rpc.handle.injectJS(async (code) => {
7703
+ try {
7704
+ return await this.injectJS(code);
7705
+ } catch (error) {
7706
+ this.log("[injectJS] Handler error:", error);
7707
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7708
+ }
7709
+ });
7710
+ this.rpc.handle.getConsole(async (clear) => {
7711
+ try {
7712
+ return await this.getConsoleLogs(clear);
7713
+ } catch (error) {
7714
+ this.log("[getConsole] Handler error:", error);
7715
+ throw { message: error instanceof Error ? error.message : String(error), code: "INTERNAL_ERROR", data: void 0 };
7716
+ }
7717
+ });
7646
7718
  }
7647
7719
  reportPageContext() {
7648
7720
  if (!this.socket?.connected) return;
@@ -7744,10 +7816,12 @@
7744
7816
  cacheBust: true,
7745
7817
  pixelRatio: 1,
7746
7818
  includeQueryParams: true,
7747
- // Filter out elements that cause issues
7819
+ // Filter out all annotator UI elements
7748
7820
  filter: (node) => {
7749
7821
  if (node instanceof Element) {
7750
- if (node.classList?.contains("annotator-badge") || node.classList?.contains("annotator-highlight-overlay") || node.tagName?.toLowerCase() === "annotator-toolbar") {
7822
+ const className = node.className || "";
7823
+ const tagName = node.tagName?.toLowerCase() || "";
7824
+ if (className.includes("annotator-") || tagName === "annotator-toolbar") {
7751
7825
  return false;
7752
7826
  }
7753
7827
  }
@@ -7878,6 +7952,7 @@
7878
7952
  if (this.clickListenerTimeout) {
7879
7953
  clearTimeout(this.clickListenerTimeout);
7880
7954
  }
7955
+ this.skipNextClickOutside = true;
7881
7956
  this.clickListenerTimeout = setTimeout(() => {
7882
7957
  document.addEventListener("click", this.handleClickOutside, true);
7883
7958
  this.clickListenerTimeout = null;
@@ -7931,6 +8006,9 @@
7931
8006
  this.popoverCleanup();
7932
8007
  this.popoverCleanup = null;
7933
8008
  }
8009
+ const popoverEl = this.shadowRoot?.querySelector(".popover");
8010
+ if (popoverEl) {
8011
+ }
7934
8012
  this.commentPopover = { visible: false, element: null, comment: "" };
7935
8013
  }
7936
8014
  handlePopoverInput(e5) {
@@ -8136,7 +8214,7 @@
8136
8214
  render() {
8137
8215
  if (!this.connected) {
8138
8216
  return x`
8139
- <div class="toolbar">
8217
+ <div class="toolbar" role="alert" aria-live="polite">
8140
8218
  <div class="error-message">
8141
8219
  ${this.renderErrorIcon()}
8142
8220
  <span>Cannot connect to AI Annotator server</span>
@@ -8145,12 +8223,15 @@
8145
8223
  `;
8146
8224
  }
8147
8225
  return x`
8148
- <div class="toolbar">
8226
+ <div class="toolbar" role="toolbar" aria-label="AI Annotator tools">
8149
8227
  <button
8150
8228
  class="toolbar-btn ${this.isInspecting ? "active" : ""}"
8151
8229
  @click=${this.toggleInspect}
8152
8230
  @mouseenter=${(e5) => this.showTooltip(this.isInspecting ? "Press ESC to exit" : "Inspect elements", e5.currentTarget)}
8153
8231
  @mouseleave=${() => this.hideTooltip()}
8232
+ aria-label="${this.isInspecting ? "Exit inspection mode" : "Inspect elements"}"
8233
+ aria-pressed="${this.isInspecting}"
8234
+ title="${this.isInspecting ? "Press ESC to exit" : "Inspect elements"}"
8154
8235
  >
8155
8236
  ${this.renderCursorIcon()}
8156
8237
  </button>
@@ -8162,19 +8243,24 @@
8162
8243
  @mouseenter=${(e5) => this.showTooltip("Clear selections", e5.currentTarget)}
8163
8244
  @mouseleave=${() => this.hideTooltip()}
8164
8245
  ?disabled=${this.selectionCount === 0}
8246
+ aria-label="Clear all selections"
8247
+ aria-disabled="${this.selectionCount === 0}"
8248
+ title="Clear selections"
8165
8249
  >
8166
8250
  ${this.renderTrashIcon()}
8167
8251
  </button>
8168
- ${this.selectionCount > 0 ? x`<span class="badge">${this.selectionCount}</span>` : ""}
8252
+ ${this.selectionCount > 0 ? x`<span class="badge" aria-label="${this.selectionCount} selections">${this.selectionCount}</span>` : ""}
8169
8253
  </div>
8170
8254
 
8171
- <div class="divider"></div>
8255
+ <div class="divider" role="separator" aria-orientation="vertical"></div>
8172
8256
 
8173
8257
  <button
8174
8258
  class="toolbar-btn"
8175
8259
  @click=${this.copySessionId}
8176
8260
  @mouseenter=${(e5) => this.showTooltip("Copy session", e5.currentTarget)}
8177
8261
  @mouseleave=${() => this.hideTooltip()}
8262
+ aria-label="Copy session ID to clipboard"
8263
+ title="Copy session"
8178
8264
  >
8179
8265
  ${this.renderClipboardIcon()}
8180
8266
  </button>
@@ -8184,17 +8270,19 @@
8184
8270
  @click=${this.openHelpPage}
8185
8271
  @mouseenter=${(e5) => this.showTooltip("Help", e5.currentTarget)}
8186
8272
  @mouseleave=${() => this.hideTooltip()}
8273
+ aria-label="Open help documentation"
8274
+ title="Help"
8187
8275
  >
8188
8276
  ${this.renderHelpIcon()}
8189
8277
  </button>
8190
8278
 
8191
- ${this.toastMessage ? x`<div class="toast">${this.toastMessage}</div>` : ""}
8279
+ ${this.toastMessage ? x`<div class="toast" role="status" aria-live="polite">${this.toastMessage}</div>` : ""}
8192
8280
  </div>
8193
8281
 
8194
- ${this.tooltip.visible ? x`<div class="tooltip">${this.tooltip.text}</div>` : ""}
8282
+ ${this.tooltip.visible ? x`<div class="tooltip" role="tooltip">${this.tooltip.text}</div>` : ""}
8195
8283
 
8196
8284
  ${this.commentPopover.visible ? x`
8197
- <div class="popover">
8285
+ <div class="popover" role="dialog" aria-label="Element comment" aria-modal="false">
8198
8286
  <textarea
8199
8287
  class="popover-input"
8200
8288
  placeholder="Add a note... (↵ to close)"
@@ -8202,12 +8290,13 @@
8202
8290
  @input=${this.handlePopoverInput}
8203
8291
  @keydown=${this.handlePopoverInputKeydown}
8204
8292
  rows="1"
8293
+ aria-label="Add a comment for the selected element"
8205
8294
  ></textarea>
8206
- <div class="popover-actions">
8207
- <button class="popover-btn danger" @click=${this.removeSelectedElement} title="Remove selection">
8295
+ <div class="popover-actions" role="group" aria-label="Comment actions">
8296
+ <button class="popover-btn danger" @click=${this.removeSelectedElement} title="Remove selection" aria-label="Remove this selection">
8208
8297
  ${this.renderTrashIcon()}
8209
8298
  </button>
8210
- <button class="popover-btn" @click=${this.hideCommentPopover} title="Close (Esc)">
8299
+ <button class="popover-btn" @click=${this.hideCommentPopover} title="Close (Esc)" aria-label="Close comment">
8211
8300
  ${this.renderCloseIcon()}
8212
8301
  </button>
8213
8302
  </div>
@@ -0,0 +1,5 @@
1
+ import { type AiAnnotatorOptions } from './vite-plugin';
2
+ export interface NuxtAiAnnotatorOptions extends AiAnnotatorOptions {
3
+ }
4
+ declare const _default: import("@nuxt/schema").NuxtModule<NuxtAiAnnotatorOptions, NuxtAiAnnotatorOptions, false>;
5
+ export default _default;