vite-plugin-ai-annotator 1.15.0 → 1.16.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 CHANGED
@@ -92,81 +92,54 @@ export default defineNuxtConfig({
92
92
 
93
93
  **That's it!** Nuxt handles the rest automatically.
94
94
 
95
- #### Configure MCP (Vite and Nuxt)
96
-
97
- **Option A: Auto Setup (Recommended)**
98
-
99
- Enable automatic MCP configuration in your Vite config:
95
+ #### Step 3: Start your dev server
100
96
 
101
- ```typescript
102
- annotator({
103
- autoSetupMcp: true,
104
- })
97
+ ```bash
98
+ bun dev
105
99
  ```
106
100
 
107
- For Nuxt, configure in `nuxt.config.ts`:
101
+ The annotator toolbar will automatically appear in your application. The plugin auto-writes a skill file (`.claude/skills/ai-annotator/SKILL.md`) so Claude Code knows how to read your feedback over the REST API on every restart.
108
102
 
109
- ```typescript
110
- export default defineNuxtConfig({
111
- modules: ['vite-plugin-ai-annotator/nuxt'],
112
- aiAnnotator: {
113
- autoSetupMcp: true,
114
- }
115
- })
116
- ```
103
+ ## Usage
117
104
 
118
- This automatically creates/updates `.mcp.json`, `.cursor/mcp.json`, and `.vscode/mcp.json` based on your project.
105
+ ### With the channel plugin (push, recommended)
119
106
 
120
- **Option B: Manual Setup**
107
+ The Vite plugin prints these install commands on dev-server start when the channel plugin isn't enabled — copy/paste once:
121
108
 
122
109
  ```bash
123
- claude mcp add annotator -- npx vite-plugin-ai-annotator mcp -s http://localhost:7318
110
+ /plugin marketplace add nguyenvanduocit/claude-annotator-plugin
111
+ /plugin install claude-annotator-plugin@claude-annotator-plugin
112
+ # Restart with the channel flag (Claude Code v2.1.80+; research preview)
113
+ claude --dangerously-load-development-channels plugin:claude-annotator-plugin@claude-annotator-plugin
124
114
  ```
125
115
 
126
- #### Step 3: Start your dev server
127
-
128
- ```bash
129
- bun dev
130
- ```
116
+ After that the hint stays silent (the Vite plugin reads `~/.claude/settings.json` to detect it; it never writes to that file). Set `autoSetupChannelPlugin: false` if you want to silence the hint without installing.
131
117
 
132
- The annotator toolbar will automatically appear in your application.
118
+ 1. Click the **inspect** button on the toolbar to enter feedback mode
119
+ 2. Click any element(s) you want to give feedback on, type a comment
120
+ 3. Click **send** — Claude Code's session immediately receives a `<channel source="ai-annotator">` event with your `session_id`, `page_url`, and `count`
121
+ 4. Claude fetches the details from the REST API, edits the source files, and pushes a toast back to your toolbar with progress
133
122
 
134
- ## Usage
123
+ ### Without the channel plugin (pull)
135
124
 
136
- 1. Click the **inspect button** on the toolbar to enter feedback mode
137
- 2. Click on any element(s) you want to provide feedback on
138
- 3. Ask Claude Code to modify them - it will use `annotator_get_feedback` to get the selected feedback with their source locations
139
- 4. Claude modifies the source code directly
125
+ Same first three steps. Then ask Claude Code to apply your feedback — it follows the auto-installed skill, calls `GET /api/sessions/<id>/feedback`, edits the files, and `DELETE`s the feedback when done.
140
126
 
141
- Example prompt: *"Make the selected button larger and change its color to blue"*
127
+ Example prompt: *"Apply the feedback I just left in the browser."*
142
128
 
143
129
  ## Configuration
144
130
 
145
131
  ```typescript
146
132
  annotator({
147
- port: 7318, // Server port (default: 7318)
148
- autoSetupMcp: true, // Auto-configure MCP files (default: false)
149
- autoSetupSkills: true, // Auto-write AI tool skill files (default: true)
150
- verbose: false, // Enable detailed logging (default: false)
133
+ port: 7318, // Server port (default: 7318)
134
+ autoSetupSkills: true, // Auto-write AI tool skill files (default: true)
135
+ autoSetupChannelPlugin: true, // Print one-time install hint for the Claude Code
136
+ // channel plugin if it isn't already enabled in
137
+ // ~/.claude/settings.json (default: true; read-only)
138
+ injectSourceLoc: true, // Inject data-source-loc attrs into HTML (default: true)
139
+ verbose: false, // Enable detailed logging (default: false)
151
140
  })
152
141
  ```
153
142
 
154
- ### Auto MCP Setup
155
-
156
- When `autoSetupMcp: true`, the plugin automatically:
157
-
158
- 1. **Detects your package manager** from lockfile:
159
- - `bun.lockb` / `bun.lock` → uses `bunx`
160
- - `pnpm-lock.yaml` → uses `pnpm dlx`
161
- - Otherwise → uses `npx`
162
-
163
- 2. **Creates/updates MCP config files**:
164
- - `.mcp.json` - Claude Code, Cline, Roo Code
165
- - `.cursor/mcp.json` - Cursor (only if `.cursor/` exists)
166
- - `.vscode/mcp.json` - VS Code (only if `.vscode/` exists)
167
-
168
- 3. **Preserves existing config** - merges with other MCP servers, doesn't overwrite
169
-
170
143
  ### Auto AI Skills Setup
171
144
 
172
145
  When `autoSetupSkills: true` (default), the plugin writes skill/instruction files on every dev server start with the correct server address baked in. This means AI tools automatically know how to call the REST API:
@@ -6238,14 +6238,14 @@
6238
6238
  while (currentElement && currentElement !== document.body) {
6239
6239
  let selector = currentElement.tagName.toLowerCase();
6240
6240
  if (currentElement.id && this.isUniqueId(currentElement.id)) {
6241
- selector += `#${currentElement.id}`;
6241
+ selector += `#${CSS.escape(currentElement.id)}`;
6242
6242
  parts2.unshift(selector);
6243
6243
  break;
6244
6244
  }
6245
6245
  if (currentElement.className && typeof currentElement.className === "string") {
6246
- const classes = currentElement.className.split(" ").filter((c4) => c4 && !c4.includes("css-") && !c4.includes("emotion-")).slice(0, 2);
6246
+ const classes = currentElement.className.split(/\s+/).filter((c4) => c4 && !c4.includes("css-") && !c4.includes("emotion-")).slice(0, 2);
6247
6247
  if (classes.length > 0) {
6248
- selector += "." + classes.join(".");
6248
+ selector += "." + classes.map((c4) => CSS.escape(c4)).join(".");
6249
6249
  }
6250
6250
  }
6251
6251
  const siblings = Array.from(currentElement.parentElement?.children || []).filter((sibling) => sibling.tagName === currentElement.tagName);
@@ -6344,7 +6344,7 @@
6344
6344
  const primary = this.generateElementSelector(element);
6345
6345
  const fallbacks = [];
6346
6346
  if (element.id && this.isUniqueId(element.id)) {
6347
- fallbacks.push(`#${element.id}`);
6347
+ fallbacks.push(`#${CSS.escape(element.id)}`);
6348
6348
  }
6349
6349
  if (element.getAttribute("data-testid")) {
6350
6350
  fallbacks.push(`[data-testid="${element.getAttribute("data-testid")}"]`);
@@ -5,7 +5,8 @@ import { defineNuxtModule, addVitePlugin } from "@nuxt/kit";
5
5
  import { spawn } from "node:child_process";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { dirname as dirname2, join as join2, relative } from "node:path";
8
- import { existsSync as existsSync2 } from "node:fs";
8
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
9
+ import { homedir } from "node:os";
9
10
 
10
11
  // node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
11
12
  var comma = ",".charCodeAt(0);
@@ -1221,6 +1222,27 @@ ${body}
1221
1222
  }
1222
1223
 
1223
1224
  // src/vite-plugin.ts
1225
+ var CHANNEL_PLUGIN_KEY = "claude-annotator-plugin@claude-annotator-plugin";
1226
+ var CHANNEL_PLUGIN_REPO = "nguyenvanduocit/claude-annotator-plugin";
1227
+ function isChannelPluginEnabled() {
1228
+ try {
1229
+ const settingsPath = join2(homedir(), ".claude", "settings.json");
1230
+ if (!existsSync2(settingsPath)) return false;
1231
+ const settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
1232
+ return Boolean(settings?.enabledPlugins?.[CHANNEL_PLUGIN_KEY]);
1233
+ } catch {
1234
+ return false;
1235
+ }
1236
+ }
1237
+ function printChannelPluginSuggestion() {
1238
+ console.log(
1239
+ `[ai-annotator] \u{1F4A1} Channel push plugin not detected. For instant push to Claude Code (instead of copy-paste), run once:
1240
+ /plugin marketplace add ${CHANNEL_PLUGIN_REPO}
1241
+ /plugin install ${CHANNEL_PLUGIN_KEY}
1242
+ claude --dangerously-load-development-channels plugin:${CHANNEL_PLUGIN_KEY}
1243
+ (Claude Code v2.1.80+; set autoSetupChannelPlugin: false in your vite.config to hide this.)`
1244
+ );
1245
+ }
1224
1246
  var SOURCE_LOC_ATTR = "data-source-loc";
1225
1247
  function injectSourceLocations(code, id, root) {
1226
1248
  if (!code.includes("<")) return null;
@@ -1304,7 +1326,8 @@ var AiAnnotatorServer = class {
1304
1326
  publicAddress: options.publicAddress ?? `http://${listenAddress}:${port}`,
1305
1327
  verbose: options.verbose ?? false,
1306
1328
  injectSourceLoc: options.injectSourceLoc ?? true,
1307
- autoSetupSkills: options.autoSetupSkills ?? true
1329
+ autoSetupSkills: options.autoSetupSkills ?? true,
1330
+ autoSetupChannelPlugin: options.autoSetupChannelPlugin ?? true
1308
1331
  };
1309
1332
  const currentFileDir = dirname2(fileURLToPath(import.meta.url));
1310
1333
  this.isRunningFromSource = currentFileDir.endsWith("/src") || currentFileDir.endsWith("\\src");
@@ -1454,6 +1477,9 @@ function aiAnnotator(options = {}) {
1454
1477
  console.log(`[ai-annotator] \u2705 AI skills updated: ${skillsResult.updated.map((f) => f.replace(root + "/", "")).join(", ")}`);
1455
1478
  }
1456
1479
  }
1480
+ if (options.autoSetupChannelPlugin !== false && !isChannelPluginEnabled()) {
1481
+ printChannelPluginSuggestion();
1482
+ }
1457
1483
  },
1458
1484
  async buildStart() {
1459
1485
  await serverManager.start();