vite-plugin-ai-annotator 1.0.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.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Source Map utilities for mapping runtime elements back to source code
3
+ */
4
+ export interface SourceMapPosition {
5
+ line: number;
6
+ column: number;
7
+ source?: string;
8
+ name?: string;
9
+ }
10
+ export interface SourceMapInfo {
11
+ file: string;
12
+ line: number;
13
+ column: number;
14
+ endLine?: number;
15
+ endColumn?: number;
16
+ originalSource?: string;
17
+ sourcesContent?: string[];
18
+ }
19
+ /**
20
+ * Basic source map consumer for parsing VLQ-encoded mappings
21
+ * Note: This is a simplified implementation. For production use,
22
+ * consider using the 'source-map' library for full compatibility.
23
+ */
24
+ export declare class BasicSourceMapConsumer {
25
+ private sources;
26
+ private sourcesContent?;
27
+ constructor(sourceMap: any);
28
+ /**
29
+ * Find original position for generated position
30
+ * This is a simplified implementation that looks for approximate mappings
31
+ */
32
+ originalPositionFor(line: number, column: number): SourceMapPosition | null;
33
+ /**
34
+ * Get source content for a given source file
35
+ */
36
+ sourceContentFor(source: string): string | null;
37
+ /**
38
+ * Get all available sources
39
+ */
40
+ getSources(): string[];
41
+ }
42
+ /**
43
+ * Attempt to find and parse source maps from various sources
44
+ */
45
+ export declare class SourceMapResolver {
46
+ private sourceMapCache;
47
+ /**
48
+ * Try to find source map for a given file URL
49
+ */
50
+ findSourceMapForFile(fileUrl: string): Promise<BasicSourceMapConsumer | null>;
51
+ /**
52
+ * Resolve original position from generated position using source maps
53
+ */
54
+ resolvePosition(fileUrl: string, line: number, column: number): Promise<SourceMapPosition | null>;
55
+ /**
56
+ * Get enhanced location info by combining runtime data with source maps
57
+ */
58
+ getEnhancedLocationInfo(fileUrl: string, line: number, column: number): Promise<SourceMapInfo | null>;
59
+ /**
60
+ * Clear the source map cache
61
+ */
62
+ clearCache(): void;
63
+ }
64
+ export declare const sourceMapResolver: SourceMapResolver;
65
+ /**
66
+ * Helper function to extract source location from browser stack traces
67
+ */
68
+ export declare function extractLocationFromStackTrace(error: Error): {
69
+ file: string;
70
+ line: number;
71
+ column: number;
72
+ } | null;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Enhanced XPath and CSS selector utilities for browser environment
3
+ */
4
+ export interface ElementSelector {
5
+ xpath: string;
6
+ cssSelector: string;
7
+ uniqueId?: string;
8
+ position?: {
9
+ index: number;
10
+ total: number;
11
+ };
12
+ }
13
+ export declare class XPathUtils {
14
+ static generateXPath(element: Element): string;
15
+ private static getXPathStep;
16
+ private static getXPathIndex;
17
+ private static isValidId;
18
+ /**
19
+ * Generate optimized CSS selector using optimal-select library
20
+ */
21
+ static generateOptimalSelector(element: Element): string;
22
+ /**
23
+ * Generate enhanced CSS selector optimized for browser environment
24
+ */
25
+ static generateEnhancedCSSSelector(element: Element): string;
26
+ /**
27
+ * Validate XPath by testing if it uniquely identifies the element
28
+ */
29
+ static validateXPath(xpath: string, targetElement: Element): boolean;
30
+ /**
31
+ * Validate CSS selector by testing if it uniquely identifies the element
32
+ */
33
+ static validateCSSSelector(selector: string, targetElement: Element): boolean;
34
+ /**
35
+ * Find element using XPath
36
+ */
37
+ static findElementByXPath(xpath: string): Element | null;
38
+ /**
39
+ * Generate comprehensive selector information for an element
40
+ */
41
+ static generateElementSelector(element: Element): ElementSelector;
42
+ /**
43
+ * Check if an ID is unique in the document
44
+ */
45
+ private static isUniqueId;
46
+ /**
47
+ * Generate multiple selector strategies for robust element identification
48
+ */
49
+ static generateRobustSelectors(element: Element): {
50
+ primary: ElementSelector;
51
+ fallbacks: string[];
52
+ confidence: 'high' | 'medium' | 'low';
53
+ };
54
+ }
@@ -0,0 +1,25 @@
1
+ import type { Plugin } from 'vite';
2
+ export interface AiAnnotatorOptions {
3
+ /**
4
+ * Port to run the server on
5
+ * @default 7318
6
+ */
7
+ port?: number;
8
+ /**
9
+ * Address for the server to listen on
10
+ * @default 'localhost'
11
+ */
12
+ listenAddress?: string;
13
+ /**
14
+ * Public URL for reverse proxy scenarios
15
+ * @default Automatically determined from listenAddress and port
16
+ */
17
+ publicAddress?: string;
18
+ /**
19
+ * Verbose logging
20
+ * @default false
21
+ */
22
+ verbose?: boolean;
23
+ }
24
+ export declare function aiAnnotator(options?: AiAnnotatorOptions): Plugin;
25
+ export default aiAnnotator;
@@ -0,0 +1,219 @@
1
+ // src/vite-plugin.ts
2
+ import { spawn } from "node:child_process";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+ import { existsSync } from "node:fs";
6
+ var AiAnnotatorServer = class {
7
+ constructor(options = {}) {
8
+ this.serverProcess = null;
9
+ const port = options.port ?? 7318;
10
+ const listenAddress = options.listenAddress ?? "localhost";
11
+ this.options = {
12
+ port,
13
+ listenAddress,
14
+ publicAddress: options.publicAddress ?? `http://${listenAddress}:${port}`,
15
+ verbose: options.verbose ?? false
16
+ };
17
+ const currentFileDir = dirname(fileURLToPath(import.meta.url));
18
+ this.isDevelopment = currentFileDir.endsWith("/src") || currentFileDir.endsWith("\\src");
19
+ if (this.isDevelopment) {
20
+ this.packageDir = dirname(currentFileDir);
21
+ } else {
22
+ this.packageDir = dirname(currentFileDir);
23
+ }
24
+ this.log(`Package directory: ${this.packageDir}`);
25
+ this.log(`Running in ${this.isDevelopment ? "development" : "production"} mode`);
26
+ }
27
+ async start() {
28
+ if (this.serverProcess) {
29
+ return;
30
+ }
31
+ const isRunning = await this.isServerRunning();
32
+ if (isRunning) {
33
+ this.log(`Server already running on port ${this.options.port}, skipping spawn`);
34
+ return;
35
+ }
36
+ let serverFile;
37
+ let cmd;
38
+ let args;
39
+ if (this.isDevelopment) {
40
+ serverFile = join(this.packageDir, "src", "index.ts");
41
+ cmd = "bun";
42
+ args = [serverFile];
43
+ } else {
44
+ serverFile = join(this.packageDir, "dist", "index.cjs");
45
+ if (!existsSync(serverFile)) {
46
+ const fallbackFile = join(this.packageDir, "src", "index.ts");
47
+ if (existsSync(fallbackFile)) {
48
+ this.log("dist/index.cjs not found, falling back to src/index.ts");
49
+ serverFile = fallbackFile;
50
+ cmd = "bun";
51
+ args = [serverFile];
52
+ } else {
53
+ throw new Error(`Annotator server file not found at ${serverFile} or ${fallbackFile}`);
54
+ }
55
+ } else {
56
+ cmd = "node";
57
+ args = [serverFile];
58
+ }
59
+ }
60
+ args.push("--port", String(this.options.port));
61
+ args.push("--listen", this.options.listenAddress);
62
+ args.push("--public-address", this.options.publicAddress);
63
+ if (this.options.verbose) {
64
+ args.push("--verbose");
65
+ }
66
+ this.log(`Starting annotator server: ${cmd} ${args.join(" ")}`);
67
+ this.log(`Working directory: ${this.packageDir}`);
68
+ this.serverProcess = spawn(cmd, args, {
69
+ cwd: this.packageDir,
70
+ env: process.env,
71
+ stdio: this.options.verbose ? "inherit" : "pipe"
72
+ });
73
+ if (!this.options.verbose && this.serverProcess.stdout) {
74
+ this.serverProcess.stdout.on("data", (_data) => {
75
+ });
76
+ }
77
+ if (!this.options.verbose && this.serverProcess.stderr) {
78
+ this.serverProcess.stderr.on("data", (data) => {
79
+ console.error(`[ai-annotator-server] Error: ${data}`);
80
+ });
81
+ }
82
+ this.serverProcess.on("error", (error) => {
83
+ console.error("[ai-annotator-server] Failed to start:", error);
84
+ });
85
+ this.serverProcess.on("exit", (code) => {
86
+ if (code !== 0 && code !== null) {
87
+ console.error(`[ai-annotator-server] Process exited with code ${code}`);
88
+ }
89
+ this.serverProcess = null;
90
+ });
91
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
92
+ }
93
+ async stop() {
94
+ if (this.serverProcess) {
95
+ this.log("Stopping annotator server...");
96
+ this.serverProcess.kill("SIGTERM");
97
+ await new Promise((resolve) => {
98
+ if (!this.serverProcess) {
99
+ resolve();
100
+ return;
101
+ }
102
+ const timeout = setTimeout(() => {
103
+ if (this.serverProcess) {
104
+ this.log("Force killing annotator server...");
105
+ this.serverProcess.kill("SIGKILL");
106
+ }
107
+ resolve();
108
+ }, 5e3);
109
+ this.serverProcess.on("exit", () => {
110
+ clearTimeout(timeout);
111
+ resolve();
112
+ });
113
+ });
114
+ this.serverProcess = null;
115
+ }
116
+ }
117
+ async isServerRunning() {
118
+ try {
119
+ const response = await fetch(`http://${this.options.listenAddress}:${this.options.port}/health`, {
120
+ signal: AbortSignal.timeout(1e3)
121
+ });
122
+ return response.ok;
123
+ } catch {
124
+ return false;
125
+ }
126
+ }
127
+ log(message) {
128
+ if (this.options.verbose) {
129
+ console.log(`[ai-annotator] ${message}`);
130
+ }
131
+ }
132
+ getInjectScript() {
133
+ return `<script src="${this.options.publicAddress}/annotator-toolbar.js" type="module" async></script>`;
134
+ }
135
+ shouldInject() {
136
+ return true;
137
+ }
138
+ };
139
+ function injectScriptIntoHtml(html, scriptTag) {
140
+ if (html.includes("</body>")) {
141
+ return html.replace("</body>", `${scriptTag}
142
+ </body>`);
143
+ } else if (html.includes("</html>")) {
144
+ return html.replace("</html>", `${scriptTag}
145
+ </html>`);
146
+ }
147
+ return html + scriptTag;
148
+ }
149
+ function aiAnnotator(options = {}) {
150
+ let serverManager;
151
+ return {
152
+ name: "vite-plugin-ai-annotator",
153
+ // Only apply plugin during development (serve command)
154
+ apply: "serve",
155
+ configResolved() {
156
+ serverManager = new AiAnnotatorServer(options);
157
+ },
158
+ async buildStart() {
159
+ await serverManager.start();
160
+ },
161
+ // For regular Vite apps (SPA)
162
+ transformIndexHtml(html) {
163
+ if (!serverManager || !serverManager.shouldInject()) {
164
+ return html;
165
+ }
166
+ return injectScriptIntoHtml(html, serverManager.getInjectScript());
167
+ },
168
+ // For SSR frameworks like Nuxt - intercept HTML responses
169
+ configureServer(server) {
170
+ server.middlewares.use((_req, res, next) => {
171
+ if (!serverManager || !serverManager.shouldInject()) {
172
+ return next();
173
+ }
174
+ const originalWrite = res.write.bind(res);
175
+ const originalEnd = res.end.bind(res);
176
+ let chunks = [];
177
+ let isHtml = false;
178
+ res.write = function(chunk, ...args) {
179
+ const contentType = res.getHeader("content-type");
180
+ if (typeof contentType === "string" && contentType.includes("text/html")) {
181
+ isHtml = true;
182
+ }
183
+ if (isHtml && chunk) {
184
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
185
+ return true;
186
+ }
187
+ return originalWrite(chunk, ...args);
188
+ };
189
+ res.end = function(chunk, ...args) {
190
+ if (chunk) {
191
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
192
+ }
193
+ if (isHtml && chunks.length > 0) {
194
+ const html = Buffer.concat(chunks).toString("utf-8");
195
+ const injectedHtml = injectScriptIntoHtml(html, serverManager.getInjectScript());
196
+ res.setHeader("content-length", Buffer.byteLength(injectedHtml));
197
+ return originalEnd(injectedHtml, ...args);
198
+ }
199
+ return originalEnd(chunk, ...args);
200
+ };
201
+ next();
202
+ });
203
+ },
204
+ async closeBundle() {
205
+ await serverManager.stop();
206
+ },
207
+ async buildEnd() {
208
+ if (this.meta.watchMode === false) {
209
+ await serverManager.stop();
210
+ }
211
+ }
212
+ };
213
+ }
214
+ var vite_plugin_default = aiAnnotator;
215
+ export {
216
+ aiAnnotator,
217
+ vite_plugin_default as default
218
+ };
219
+ //# sourceMappingURL=vite-plugin.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/vite-plugin.ts"],
4
+ "sourcesContent": ["import type { Plugin, ViteDevServer } from 'vite';\nimport { spawn, ChildProcess } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { existsSync } from 'node:fs';\n\nexport interface AiAnnotatorOptions {\n /**\n * Port to run the server on\n * @default 7318\n */\n port?: number;\n /**\n * Address for the server to listen on\n * @default 'localhost'\n */\n listenAddress?: string;\n /**\n * Public URL for reverse proxy scenarios\n * @default Automatically determined from listenAddress and port\n */\n publicAddress?: string;\n /**\n * Verbose logging\n * @default false\n */\n verbose?: boolean;\n}\n\nclass AiAnnotatorServer {\n private serverProcess: ChildProcess | null = null;\n private options: Required<AiAnnotatorOptions>;\n private packageDir: string;\n private isDevelopment: boolean;\n\n constructor(options: AiAnnotatorOptions = {}) {\n const port = options.port ?? 7318;\n const listenAddress = options.listenAddress ?? 'localhost';\n \n this.options = {\n port,\n listenAddress,\n publicAddress: options.publicAddress ?? `http://${listenAddress}:${port}`,\n verbose: options.verbose ?? false,\n };\n \n\n // Detect if we're running from source or from installed package\n const currentFileDir = dirname(fileURLToPath(import.meta.url));\n\n // Check if we're in src directory (development) or dist directory (production)\n this.isDevelopment = currentFileDir.endsWith('/src') || currentFileDir.endsWith('\\\\src');\n\n // Get the package root directory\n if (this.isDevelopment) {\n // In development: current file is in src/, package root is one level up\n this.packageDir = dirname(currentFileDir);\n } else {\n // In production: current file is in dist/, package root is one level up\n this.packageDir = dirname(currentFileDir);\n }\n\n this.log(`Package directory: ${this.packageDir}`);\n this.log(`Running in ${this.isDevelopment ? 'development' : 'production'} mode`);\n }\n\n async start(): Promise<void> {\n if (this.serverProcess) {\n return;\n }\n\n // Check if server is already running on the port\n const isRunning = await this.isServerRunning();\n if (isRunning) {\n this.log(`Server already running on port ${this.options.port}, skipping spawn`);\n return;\n }\n\n // Determine the server file to run\n let serverFile: string;\n let cmd: string;\n let args: string[];\n\n if (this.isDevelopment) {\n // Development: run TypeScript file directly with bun\n serverFile = join(this.packageDir, 'src', 'index.ts');\n cmd = 'bun';\n args = [serverFile];\n } else {\n // Production: run compiled JavaScript file\n serverFile = join(this.packageDir, 'dist', 'index.cjs');\n\n // Check if dist/index.cjs exists, if not try to use bun with src/index.ts as fallback\n if (!existsSync(serverFile)) {\n const fallbackFile = join(this.packageDir, 'src', 'index.ts');\n if (existsSync(fallbackFile)) {\n this.log('dist/index.cjs not found, falling back to src/index.ts');\n serverFile = fallbackFile;\n cmd = 'bun';\n args = [serverFile];\n } else {\n throw new Error(`Annotator server file not found at ${serverFile} or ${fallbackFile}`);\n }\n } else {\n // Use node for compiled CJS in production\n cmd = 'node';\n args = [serverFile];\n }\n }\n\n // Add CLI arguments\n args.push('--port', String(this.options.port));\n args.push('--listen', this.options.listenAddress);\n args.push('--public-address', this.options.publicAddress);\n if (this.options.verbose) {\n args.push('--verbose');\n }\n\n this.log(`Starting annotator server: ${cmd} ${args.join(' ')}`);\n this.log(`Working directory: ${this.packageDir}`);\n\n // Start the server process\n this.serverProcess = spawn(cmd, args, {\n cwd: this.packageDir,\n env: process.env,\n stdio: this.options.verbose ? 'inherit' : 'pipe',\n });\n\n if (!this.options.verbose && this.serverProcess.stdout) {\n this.serverProcess.stdout.on('data', (_data) => {\n // Pipe output for debugging if needed\n });\n }\n\n if (!this.options.verbose && this.serverProcess.stderr) {\n this.serverProcess.stderr.on('data', (data) => {\n console.error(`[ai-annotator-server] Error: ${data}`);\n });\n }\n\n this.serverProcess.on('error', (error) => {\n console.error('[ai-annotator-server] Failed to start:', error);\n });\n\n this.serverProcess.on('exit', (code) => {\n if (code !== 0 && code !== null) {\n console.error(`[ai-annotator-server] Process exited with code ${code}`);\n }\n this.serverProcess = null;\n });\n\n // Give server a moment to start\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n\n async stop(): Promise<void> {\n if (this.serverProcess) {\n this.log('Stopping annotator server...');\n\n // Send SIGTERM for graceful shutdown\n this.serverProcess.kill('SIGTERM');\n\n // Wait for process to exit\n await new Promise<void>((resolve) => {\n if (!this.serverProcess) {\n resolve();\n return;\n }\n\n const timeout = setTimeout(() => {\n // Force kill if not exited after 5 seconds\n if (this.serverProcess) {\n this.log('Force killing annotator server...');\n this.serverProcess.kill('SIGKILL');\n }\n resolve();\n }, 5000);\n\n this.serverProcess.on('exit', () => {\n clearTimeout(timeout);\n resolve();\n });\n });\n\n this.serverProcess = null;\n }\n }\n\n\n private async isServerRunning(): Promise<boolean> {\n try {\n const response = await fetch(`http://${this.options.listenAddress}:${this.options.port}/health`, {\n signal: AbortSignal.timeout(1000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n private log(message: string): void {\n if (this.options.verbose) {\n console.log(`[ai-annotator] ${message}`);\n }\n }\n\n getInjectScript(): string {\n return `<script src=\"${this.options.publicAddress}/annotator-toolbar.js\" type=\"module\" async></script>`;\n }\n\n shouldInject(): boolean {\n return true;\n }\n\n}\n\nfunction injectScriptIntoHtml(html: string, scriptTag: string): string {\n if (html.includes('</body>')) {\n return html.replace('</body>', `${scriptTag}\\n</body>`);\n } else if (html.includes('</html>')) {\n return html.replace('</html>', `${scriptTag}\\n</html>`);\n }\n return html + scriptTag;\n}\n\nexport function aiAnnotator(options: AiAnnotatorOptions = {}): Plugin {\n let serverManager: AiAnnotatorServer;\n\n return {\n name: 'vite-plugin-ai-annotator',\n // Only apply plugin during development (serve command)\n apply: 'serve',\n\n configResolved() {\n serverManager = new AiAnnotatorServer(options);\n },\n\n async buildStart() {\n await serverManager.start();\n },\n\n // For regular Vite apps (SPA)\n transformIndexHtml(html: string) {\n if (!serverManager || !serverManager.shouldInject()) {\n return html;\n }\n return injectScriptIntoHtml(html, serverManager.getInjectScript());\n },\n\n // For SSR frameworks like Nuxt - intercept HTML responses\n configureServer(server: ViteDevServer) {\n server.middlewares.use((_req, res, next) => {\n if (!serverManager || !serverManager.shouldInject()) {\n return next();\n }\n\n // Only intercept HTML responses\n const originalWrite = res.write.bind(res);\n const originalEnd = res.end.bind(res);\n let chunks: Buffer[] = [];\n let isHtml = false;\n\n res.write = function(chunk: any, ...args: any[]) {\n // Check content-type on first write\n const contentType = res.getHeader('content-type');\n if (typeof contentType === 'string' && contentType.includes('text/html')) {\n isHtml = true;\n }\n\n if (isHtml && chunk) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return true;\n }\n return originalWrite(chunk, ...args);\n } as any;\n\n res.end = function(chunk?: any, ...args: any[]) {\n if (chunk) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n\n if (isHtml && chunks.length > 0) {\n const html = Buffer.concat(chunks).toString('utf-8');\n const injectedHtml = injectScriptIntoHtml(html, serverManager.getInjectScript());\n\n // Update content-length header\n res.setHeader('content-length', Buffer.byteLength(injectedHtml));\n return originalEnd(injectedHtml, ...args);\n }\n\n return originalEnd(chunk, ...args);\n } as any;\n\n next();\n });\n },\n\n async closeBundle() {\n await serverManager.stop();\n },\n\n async buildEnd() {\n // Stop server when build ends (in build mode)\n if (this.meta.watchMode === false) {\n await serverManager.stop();\n }\n },\n };\n}\n\n// Default export for convenience\nexport default aiAnnotator;"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,26 @@
1
+ import type { Express } from 'express';
2
+ import type { Server } from 'node:http';
3
+ import { Server as SocketIOServer, Socket } from 'socket.io';
4
+ import { type RpcServer } from './rpc/server.generated';
5
+ import type { BrowserSession } from './rpc/define';
6
+ export interface ServerInstance {
7
+ app: Express;
8
+ server: Server;
9
+ io: SocketIOServer;
10
+ port: number;
11
+ listenAddress: string;
12
+ publicAddress: string;
13
+ verbose: boolean;
14
+ }
15
+ export interface BrowserConnection {
16
+ socket: Socket;
17
+ rpc: RpcServer;
18
+ session: BrowserSession;
19
+ }
20
+ export declare function getAllSessions(): BrowserSession[];
21
+ export declare function getRpc(sessionId?: string): {
22
+ rpc: RpcServer;
23
+ sessionId: string;
24
+ } | null;
25
+ export declare function startServer(port: number, listenAddress: string, publicAddress: string, verbose?: boolean): Promise<ServerInstance>;
26
+ export declare function stopServer(serverInstance: ServerInstance): Promise<void>;
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "vite-plugin-ai-annotator",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered element annotator for Vite - Pick elements and get instant AI code modifications",
5
+ "type": "module",
6
+ "main": "dist/vite-plugin.js",
7
+ "types": "dist/vite-plugin.d.ts",
8
+ "bin": {
9
+ "ai-annotator": "./dist/index.cjs"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/vite-plugin.d.ts",
14
+ "import": "./dist/vite-plugin.js"
15
+ },
16
+ "./vite-plugin": {
17
+ "types": "./dist/vite-plugin.d.ts",
18
+ "import": "./dist/vite-plugin.js"
19
+ }
20
+ },
21
+ "scripts": {
22
+ "dev": "bun src/index.ts",
23
+ "build:server": "bun scripts/build-server.js",
24
+ "build:annotator": "bun scripts/build-annotator.js",
25
+ "build:vite-plugin": "bun scripts/build-vite-plugin.js",
26
+ "build:types": "bun scripts/build-types.js",
27
+ "build": "bun run build:server && bun run build:annotator && bun run build:vite-plugin && bun run build:types",
28
+ "typecheck": "tsc --noEmit",
29
+ "prepublishOnly": "bun run build"
30
+ },
31
+ "files": [
32
+ "dist/**/*",
33
+ "README.md"
34
+ ],
35
+ "keywords": [
36
+ "vite",
37
+ "vite-plugin",
38
+ "ai",
39
+ "annotator",
40
+ "element-picker",
41
+ "claude",
42
+ "inspector",
43
+ "web-development",
44
+ "frontend"
45
+ ],
46
+ "author": "Nguyen Van Duoc <nguyenvanduocit@gmail.com>",
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/nguyenvanduocit/vite-plugin-ai-annotator.git"
51
+ },
52
+ "homepage": "https://github.com/nguyenvanduocit/vite-plugin-ai-annotator#readme",
53
+ "bugs": {
54
+ "url": "https://github.com/nguyenvanduocit/vite-plugin-ai-annotator/issues"
55
+ },
56
+ "dependencies": {
57
+ "@floating-ui/dom": "^1.7.4",
58
+ "@modelcontextprotocol/sdk": "^1.0.0",
59
+ "@types/js-yaml": "^4.0.9",
60
+ "cors": "^2.8.5",
61
+ "express": "^5.1.0",
62
+ "html-to-image": "^1.11.13",
63
+ "js-yaml": "^4.1.0",
64
+ "lit": "^3.3.1",
65
+ "optimal-select": "^4.0.1",
66
+ "socket.io": "^4.8.1",
67
+ "socket.io-client": "^4.8.1",
68
+ "zod": "^4.0.17"
69
+ },
70
+ "devDependencies": {
71
+ "@types/bun": "^1.2.20",
72
+ "@types/cors": "^2.8.17",
73
+ "@types/express": "^5.0.2",
74
+ "@types/node": "^22.13.4",
75
+ "esbuild": "^0.25.9",
76
+ "tsx": "^4.7.0",
77
+ "typescript": "^5.7.3",
78
+ "vite": "^6.0.7"
79
+ },
80
+ "engines": {
81
+ "node": ">=18.0.0"
82
+ },
83
+ "peerDependencies": {
84
+ "vite": ">=2.0.0"
85
+ }
86
+ }