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