vite-plugin-ai-annotator 1.14.9 → 1.14.11
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 +48 -3
- package/dist/auto-setup-skills.d.ts +24 -0
- package/dist/index.cjs +34 -107
- package/dist/nuxt-module.js +125 -103
- package/dist/nuxt-module.js.map +3 -3
- package/dist/vite-plugin.d.ts +4 -4
- package/dist/vite-plugin.js +124 -101
- package/dist/vite-plugin.js.map +3 -3
- package/package.json +1 -2
package/dist/nuxt-module.js
CHANGED
|
@@ -1080,114 +1080,142 @@ var MagicString = class _MagicString {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
};
|
|
1082
1082
|
|
|
1083
|
-
// src/auto-setup-
|
|
1083
|
+
// src/auto-setup-skills.ts
|
|
1084
1084
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
1085
1085
|
import { join, dirname } from "node:path";
|
|
1086
|
-
var
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
}
|
|
1086
|
+
var MARKER_START = "<!-- ai-annotator:start -->";
|
|
1087
|
+
var MARKER_END = "<!-- ai-annotator:end -->";
|
|
1088
|
+
function generateSkillBody(serverUrl) {
|
|
1089
|
+
return `AI Annotator provides access to the user's live browser session. Users select UI elements and add feedback comments. Use the REST API to read feedback, capture screenshots, inject CSS/JS, and read console logs.
|
|
1090
|
+
|
|
1091
|
+
Server: \`${serverUrl}\`
|
|
1092
|
+
|
|
1093
|
+
## REST API
|
|
1094
|
+
|
|
1095
|
+
All endpoints return JSON. Obtain session ID from \`GET /api/sessions\` first.
|
|
1096
|
+
|
|
1097
|
+
| Method | Endpoint | Body/Query | Description |
|
|
1098
|
+
|--------|----------|------------|-------------|
|
|
1099
|
+
| \`GET\` | \`${serverUrl}/api/sessions\` | \u2014 | List connected browser sessions |
|
|
1100
|
+
| \`GET\` | \`${serverUrl}/api/sessions/:id/page-context\` | \u2014 | Page URL, title, selection count |
|
|
1101
|
+
| \`POST\` | \`${serverUrl}/api/sessions/:id/select\` | \`{mode?, selector?, selectorType?}\` | Trigger feedback selection |
|
|
1102
|
+
| \`GET\` | \`${serverUrl}/api/sessions/:id/feedback\` | \`?fields=xpath,attributes,styles,children\` | Get selected feedback items |
|
|
1103
|
+
| \`DELETE\` | \`${serverUrl}/api/sessions/:id/feedback\` | \u2014 | Clear all selections |
|
|
1104
|
+
| \`POST\` | \`${serverUrl}/api/sessions/:id/screenshot\` | \`{type?, selector?, quality?}\` | Capture screenshot |
|
|
1105
|
+
| \`POST\` | \`${serverUrl}/api/sessions/:id/inject-css\` | \`{css}\` | Inject CSS into page |
|
|
1106
|
+
| \`POST\` | \`${serverUrl}/api/sessions/:id/inject-js\` | \`{code}\` | Execute JS in page context |
|
|
1107
|
+
| \`GET\` | \`${serverUrl}/api/sessions/:id/console\` | \`?clear=true\` | Get captured console logs |
|
|
1108
|
+
|
|
1109
|
+
## Workflow
|
|
1110
|
+
|
|
1111
|
+
1. \`GET ${serverUrl}/api/sessions\` \u2192 get session ID
|
|
1112
|
+
2. \`GET ${serverUrl}/api/sessions/{id}/feedback\` \u2192 read user feedback
|
|
1113
|
+
3. Make code changes based on feedback
|
|
1114
|
+
4. \`DELETE ${serverUrl}/api/sessions/{id}/feedback\` \u2192 clear feedback after addressing it`;
|
|
1116
1115
|
}
|
|
1117
|
-
function
|
|
1116
|
+
function writeIfChanged(filePath, content, verbose) {
|
|
1118
1117
|
const dir = dirname(filePath);
|
|
1119
1118
|
if (!existsSync(dir)) {
|
|
1120
1119
|
mkdirSync(dir, { recursive: true });
|
|
1121
1120
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
if (existingConfig) {
|
|
1127
|
-
const existing = existingConfig.mcpServers?.[MCP_SERVER_NAME];
|
|
1128
|
-
if (existing && existing.command === serverConfig.command && JSON.stringify(existing.args) === JSON.stringify(serverConfig.args)) {
|
|
1129
|
-
if (verbose) {
|
|
1130
|
-
console.log(`[ai-annotator] ${filePath} already configured`);
|
|
1131
|
-
}
|
|
1121
|
+
if (existsSync(filePath)) {
|
|
1122
|
+
const existing = readFileSync(filePath, "utf-8");
|
|
1123
|
+
if (existing === content) {
|
|
1124
|
+
if (verbose) console.log(`[ai-annotator] ${filePath} already up-to-date`);
|
|
1132
1125
|
return false;
|
|
1133
1126
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1127
|
+
}
|
|
1128
|
+
writeFileSync(filePath, content);
|
|
1129
|
+
if (verbose) console.log(`[ai-annotator] Updated ${filePath}`);
|
|
1130
|
+
return true;
|
|
1131
|
+
}
|
|
1132
|
+
function updateMarkerSection(filePath, content, verbose) {
|
|
1133
|
+
const section = `${MARKER_START}
|
|
1134
|
+
${content}
|
|
1135
|
+
${MARKER_END}`;
|
|
1136
|
+
if (existsSync(filePath)) {
|
|
1137
|
+
const existing = readFileSync(filePath, "utf-8");
|
|
1138
|
+
const startIdx = existing.indexOf(MARKER_START);
|
|
1139
|
+
const endIdx = existing.indexOf(MARKER_END);
|
|
1140
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
1141
|
+
const updated = existing.slice(0, startIdx) + section + existing.slice(endIdx + MARKER_END.length);
|
|
1142
|
+
if (updated === existing) {
|
|
1143
|
+
if (verbose) console.log(`[ai-annotator] ${filePath} already up-to-date`);
|
|
1144
|
+
return false;
|
|
1145
|
+
}
|
|
1146
|
+
writeFileSync(filePath, updated);
|
|
1147
|
+
if (verbose) console.log(`[ai-annotator] Updated ${filePath}`);
|
|
1148
|
+
return true;
|
|
1139
1149
|
}
|
|
1150
|
+
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
1151
|
+
writeFileSync(filePath, existing + separator + section + "\n");
|
|
1152
|
+
if (verbose) console.log(`[ai-annotator] Appended to ${filePath}`);
|
|
1140
1153
|
return true;
|
|
1141
1154
|
}
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
}
|
|
1146
|
-
};
|
|
1147
|
-
writeJsonFile(filePath, newConfig);
|
|
1148
|
-
if (verbose) {
|
|
1149
|
-
console.log(`[ai-annotator] Created ${filePath}`);
|
|
1155
|
+
const dir = dirname(filePath);
|
|
1156
|
+
if (!existsSync(dir)) {
|
|
1157
|
+
mkdirSync(dir, { recursive: true });
|
|
1150
1158
|
}
|
|
1159
|
+
writeFileSync(filePath, section + "\n");
|
|
1160
|
+
if (verbose) console.log(`[ai-annotator] Created ${filePath}`);
|
|
1151
1161
|
return true;
|
|
1152
1162
|
}
|
|
1153
|
-
function
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
return potentialConfigs.filter(existsSync);
|
|
1163
|
+
function track(result, filePath, updated) {
|
|
1164
|
+
if (updated) {
|
|
1165
|
+
result.updated.push(filePath);
|
|
1166
|
+
} else {
|
|
1167
|
+
result.alreadyConfigured.push(filePath);
|
|
1168
|
+
}
|
|
1160
1169
|
}
|
|
1161
|
-
function
|
|
1170
|
+
function autoSetupSkills(options) {
|
|
1162
1171
|
const { projectRoot, serverUrl, verbose = false } = options;
|
|
1163
|
-
const result = {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
if (
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1172
|
+
const result = { updated: [], alreadyConfigured: [] };
|
|
1173
|
+
const body = generateSkillBody(serverUrl);
|
|
1174
|
+
const claudeSkill = join(projectRoot, ".claude", "skills", "ai-annotator", "SKILL.md");
|
|
1175
|
+
track(result, claudeSkill, writeIfChanged(claudeSkill, `---
|
|
1176
|
+
name: ai-annotator
|
|
1177
|
+
description: This skill should be used when the user asks to "check browser feedback", "get user feedback", "capture screenshot", "inspect element", "inject CSS", "inject JS", "read console logs", or mentions AI Annotator, browser session, or UI feedback.
|
|
1178
|
+
---
|
|
1179
|
+
|
|
1180
|
+
${body}
|
|
1181
|
+
`, verbose));
|
|
1182
|
+
if (existsSync(join(projectRoot, ".cursor"))) {
|
|
1183
|
+
const cursorRule = join(projectRoot, ".cursor", "rules", "ai-annotator.mdc");
|
|
1184
|
+
track(result, cursorRule, writeIfChanged(cursorRule, `---
|
|
1185
|
+
description: AI Annotator - interact with user's live browser session for UI feedback
|
|
1186
|
+
globs:
|
|
1187
|
+
alwaysApply: true
|
|
1188
|
+
---
|
|
1189
|
+
|
|
1190
|
+
${body}
|
|
1191
|
+
`, verbose));
|
|
1192
|
+
}
|
|
1193
|
+
if (existsSync(join(projectRoot, ".windsurf"))) {
|
|
1194
|
+
const windsurfRule = join(projectRoot, ".windsurf", "rules", "ai-annotator.md");
|
|
1195
|
+
track(result, windsurfRule, writeIfChanged(windsurfRule, `---
|
|
1196
|
+
trigger: always_on
|
|
1197
|
+
---
|
|
1198
|
+
|
|
1199
|
+
${body}
|
|
1200
|
+
`, verbose));
|
|
1201
|
+
}
|
|
1202
|
+
const agentsMd = join(projectRoot, "AGENTS.md");
|
|
1203
|
+
if (existsSync(agentsMd)) {
|
|
1204
|
+
track(result, agentsMd, updateMarkerSection(agentsMd, body, verbose));
|
|
1205
|
+
}
|
|
1206
|
+
if (existsSync(join(projectRoot, ".github"))) {
|
|
1207
|
+
const copilotInstructions = join(projectRoot, ".github", "instructions", "ai-annotator.instructions.md");
|
|
1208
|
+
track(result, copilotInstructions, writeIfChanged(copilotInstructions, `---
|
|
1209
|
+
applyTo: "**"
|
|
1210
|
+
---
|
|
1211
|
+
|
|
1212
|
+
${body}
|
|
1213
|
+
`, verbose));
|
|
1183
1214
|
}
|
|
1184
|
-
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
} else {
|
|
1189
|
-
result.alreadyConfigured.push(configFile);
|
|
1190
|
-
}
|
|
1215
|
+
if (existsSync(join(projectRoot, ".clinerules"))) {
|
|
1216
|
+
const clineRule = join(projectRoot, ".clinerules", "ai-annotator.md");
|
|
1217
|
+
track(result, clineRule, writeIfChanged(clineRule, `${body}
|
|
1218
|
+
`, verbose));
|
|
1191
1219
|
}
|
|
1192
1220
|
return result;
|
|
1193
1221
|
}
|
|
@@ -1276,7 +1304,7 @@ var AiAnnotatorServer = class {
|
|
|
1276
1304
|
publicAddress: options.publicAddress ?? `http://${listenAddress}:${port}`,
|
|
1277
1305
|
verbose: options.verbose ?? false,
|
|
1278
1306
|
injectSourceLoc: options.injectSourceLoc ?? true,
|
|
1279
|
-
|
|
1307
|
+
autoSetupSkills: options.autoSetupSkills ?? true
|
|
1280
1308
|
};
|
|
1281
1309
|
const currentFileDir = dirname2(fileURLToPath(import.meta.url));
|
|
1282
1310
|
this.isRunningFromSource = currentFileDir.endsWith("/src") || currentFileDir.endsWith("\\src");
|
|
@@ -1323,9 +1351,6 @@ var AiAnnotatorServer = class {
|
|
|
1323
1351
|
if (this.options.verbose) {
|
|
1324
1352
|
args.push("--verbose");
|
|
1325
1353
|
}
|
|
1326
|
-
if (this.options.autoSetupMcp) {
|
|
1327
|
-
args.push("--skip-mcp-instructions");
|
|
1328
|
-
}
|
|
1329
1354
|
this.log(`Starting annotator server: ${cmd} ${args.join(" ")}`);
|
|
1330
1355
|
this.log(`Working directory: ${this.packageDir}`);
|
|
1331
1356
|
this.serverProcess = spawn(cmd, args, {
|
|
@@ -1418,17 +1443,15 @@ function aiAnnotator(options = {}) {
|
|
|
1418
1443
|
configResolved(config) {
|
|
1419
1444
|
serverManager = new AiAnnotatorServer(options);
|
|
1420
1445
|
root = config.root;
|
|
1421
|
-
if (options.
|
|
1422
|
-
const serverUrl = `http://${options.listenAddress ?? "127.0.0.1"}:${options.port ?? 7318}`;
|
|
1423
|
-
const
|
|
1446
|
+
if (options.autoSetupSkills !== false) {
|
|
1447
|
+
const serverUrl = options.publicAddress ?? `http://${options.listenAddress ?? "127.0.0.1"}:${options.port ?? 7318}`;
|
|
1448
|
+
const skillsResult = autoSetupSkills({
|
|
1424
1449
|
projectRoot: root,
|
|
1425
1450
|
serverUrl,
|
|
1426
1451
|
verbose: options.verbose
|
|
1427
1452
|
});
|
|
1428
|
-
if (
|
|
1429
|
-
console.log(`[ai-annotator] \u2705
|
|
1430
|
-
} else if (result.alreadyConfigured.length > 0) {
|
|
1431
|
-
console.log(`[ai-annotator] \u2705 MCP config already up-to-date`);
|
|
1453
|
+
if (skillsResult.updated.length > 0) {
|
|
1454
|
+
console.log(`[ai-annotator] \u2705 AI skills updated: ${skillsResult.updated.map((f) => f.replace(root + "/", "")).join(", ")}`);
|
|
1432
1455
|
}
|
|
1433
1456
|
}
|
|
1434
1457
|
},
|
|
@@ -1513,8 +1536,7 @@ var nuxt_module_default = defineNuxtModule({
|
|
|
1513
1536
|
port: 7318,
|
|
1514
1537
|
listenAddress: "127.0.0.1",
|
|
1515
1538
|
verbose: false,
|
|
1516
|
-
injectSourceLoc: true
|
|
1517
|
-
autoSetupMcp: false
|
|
1539
|
+
injectSourceLoc: true
|
|
1518
1540
|
},
|
|
1519
1541
|
setup(options, nuxt) {
|
|
1520
1542
|
if (!nuxt.options.dev) {
|