vite-plugin-ai-annotator 1.15.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -53
- package/dist/annotator-toolbar.d.ts +1 -1
- package/dist/annotator-toolbar.js +10 -10
- 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:
|
|
@@ -72,7 +72,7 @@ export declare class AnnotatorToolbar extends LitElement {
|
|
|
72
72
|
private renderTrashIcon;
|
|
73
73
|
private renderCloseIcon;
|
|
74
74
|
private renderHelpIcon;
|
|
75
|
-
private
|
|
75
|
+
private renderSendIcon;
|
|
76
76
|
private showToast;
|
|
77
77
|
private showTooltip;
|
|
78
78
|
private hideTooltip;
|
|
@@ -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")}"]`);
|
|
@@ -8119,9 +8119,9 @@
|
|
|
8119
8119
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
|
|
8120
8120
|
</svg>`;
|
|
8121
8121
|
}
|
|
8122
|
-
|
|
8122
|
+
renderSendIcon() {
|
|
8123
8123
|
return x`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
8124
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="
|
|
8124
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" />
|
|
8125
8125
|
</svg>`;
|
|
8126
8126
|
}
|
|
8127
8127
|
showToast(message) {
|
|
@@ -8245,12 +8245,12 @@
|
|
|
8245
8245
|
<button
|
|
8246
8246
|
class="toolbar-btn"
|
|
8247
8247
|
@click=${this.copySessionId}
|
|
8248
|
-
@mouseenter=${(e5) => this.showTooltip("
|
|
8248
|
+
@mouseenter=${(e5) => this.showTooltip("Send to Claude", e5.currentTarget)}
|
|
8249
8249
|
@mouseleave=${() => this.hideTooltip()}
|
|
8250
|
-
aria-label="
|
|
8251
|
-
title="
|
|
8250
|
+
aria-label="Send selections to Claude Code"
|
|
8251
|
+
title="Send to Claude"
|
|
8252
8252
|
>
|
|
8253
|
-
${this.
|
|
8253
|
+
${this.renderSendIcon()}
|
|
8254
8254
|
</button>
|
|
8255
8255
|
|
|
8256
8256
|
<button
|
package/dist/nuxt-module.js
CHANGED
|
@@ -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();
|