vite-plugin-ai-annotator 1.14.16 → 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 +26 -53
- package/dist/annotator-toolbar.js +22 -10
- package/dist/index.cjs +22 -22
- package/dist/nuxt-module.js +28 -2
- package/dist/nuxt-module.js.map +3 -3
- package/dist/vite-plugin.d.ts +8 -0
- package/dist/vite-plugin.js +28 -2
- package/dist/vite-plugin.js.map +3 -3
- package/package.json +1 -1
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
|
-
####
|
|
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
|
-
```
|
|
102
|
-
|
|
103
|
-
autoSetupMcp: true,
|
|
104
|
-
})
|
|
97
|
+
```bash
|
|
98
|
+
bun dev
|
|
105
99
|
```
|
|
106
100
|
|
|
107
|
-
|
|
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
|
-
|
|
110
|
-
export default defineNuxtConfig({
|
|
111
|
-
modules: ['vite-plugin-ai-annotator/nuxt'],
|
|
112
|
-
aiAnnotator: {
|
|
113
|
-
autoSetupMcp: true,
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
```
|
|
103
|
+
## Usage
|
|
117
104
|
|
|
118
|
-
|
|
105
|
+
### With the channel plugin (push, recommended)
|
|
119
106
|
|
|
120
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
123
|
+
### Without the channel plugin (pull)
|
|
135
124
|
|
|
136
|
-
|
|
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: *"
|
|
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,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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(
|
|
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")}"]`);
|
|
@@ -7665,6 +7665,11 @@
|
|
|
7665
7665
|
this.socket.on("connect_error", (error) => {
|
|
7666
7666
|
this.log("Connection error:", error.message);
|
|
7667
7667
|
});
|
|
7668
|
+
this.socket.on("channel:notify", (data) => {
|
|
7669
|
+
if (typeof data?.message !== "string") return;
|
|
7670
|
+
const prefix = data.status === "done" ? "\u2713 " : data.status === "error" ? "\u2717 " : data.status === "progress" ? "\u2026 " : "";
|
|
7671
|
+
this.showToast(prefix + data.message);
|
|
7672
|
+
});
|
|
7668
7673
|
}
|
|
7669
7674
|
wrapRpcHandler(name, handler) {
|
|
7670
7675
|
return (async (...args) => {
|
|
@@ -8062,13 +8067,17 @@
|
|
|
8062
8067
|
return;
|
|
8063
8068
|
}
|
|
8064
8069
|
const text = `I have selected ${elements.length} feedback item(s) in the browser (session: ${this.sessionId}). Fetch them via GET ${this.wsEndpoint}/api/sessions/${this.sessionId}/feedback and modify the code accordingly.`;
|
|
8070
|
+
if (this.socket?.connected) {
|
|
8071
|
+
this.socket.emit("feedback:submitted", { count: elements.length });
|
|
8072
|
+
}
|
|
8065
8073
|
try {
|
|
8066
8074
|
await navigator.clipboard.writeText(text);
|
|
8067
|
-
this.showToast(`
|
|
8075
|
+
this.showToast(`Sent ${elements.length} element(s) to Claude`);
|
|
8068
8076
|
this.exitInspectingMode();
|
|
8069
8077
|
} catch (error) {
|
|
8070
|
-
this.showToast(
|
|
8071
|
-
this.log("
|
|
8078
|
+
this.showToast(`Sent ${elements.length} element(s) to Claude`);
|
|
8079
|
+
this.log("Clipboard copy failed (channel push still sent):", error);
|
|
8080
|
+
this.exitInspectingMode();
|
|
8072
8081
|
}
|
|
8073
8082
|
}
|
|
8074
8083
|
toggleInspect() {
|
|
@@ -8169,13 +8178,16 @@
|
|
|
8169
8178
|
return;
|
|
8170
8179
|
}
|
|
8171
8180
|
const text = `I have feedback in the browser (session: ${this.sessionId}). Fetch them via GET ${this.wsEndpoint}/api/sessions/${this.sessionId}/feedback`;
|
|
8181
|
+
if (this.socket?.connected) {
|
|
8182
|
+
this.socket.emit("feedback:submitted", { count: 0 });
|
|
8183
|
+
}
|
|
8172
8184
|
try {
|
|
8173
8185
|
await navigator.clipboard.writeText(text);
|
|
8174
|
-
this.showToast("
|
|
8186
|
+
this.showToast("Sent to Claude");
|
|
8175
8187
|
this.log("Copied to clipboard:", text);
|
|
8176
8188
|
} catch (error) {
|
|
8177
|
-
this.showToast("
|
|
8178
|
-
this.log("
|
|
8189
|
+
this.showToast("Sent to Claude");
|
|
8190
|
+
this.log("Clipboard copy failed (channel push still sent):", error);
|
|
8179
8191
|
}
|
|
8180
8192
|
}
|
|
8181
8193
|
renderErrorIcon() {
|