vite-plugin-ai-annotator 1.1.9 → 1.1.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/dist/annotator-toolbar.js +59 -31
- package/dist/index.cjs +1 -1
- package/package.json +1 -1
|
@@ -6587,9 +6587,17 @@
|
|
|
6587
6587
|
deselectElement(element) {
|
|
6588
6588
|
const elementData = selectedElements.get(element);
|
|
6589
6589
|
if (elementData) {
|
|
6590
|
-
;
|
|
6591
|
-
|
|
6592
|
-
|
|
6590
|
+
const el = element;
|
|
6591
|
+
if (elementData.originalOutline) {
|
|
6592
|
+
el.style.outline = elementData.originalOutline;
|
|
6593
|
+
} else {
|
|
6594
|
+
el.style.removeProperty("outline");
|
|
6595
|
+
}
|
|
6596
|
+
if (elementData.originalOutlineOffset) {
|
|
6597
|
+
el.style.outlineOffset = elementData.originalOutlineOffset;
|
|
6598
|
+
} else {
|
|
6599
|
+
el.style.removeProperty("outline-offset");
|
|
6600
|
+
}
|
|
6593
6601
|
const badge = badges.get(element);
|
|
6594
6602
|
if (badge) {
|
|
6595
6603
|
badge._cleanup?.();
|
|
@@ -6602,9 +6610,17 @@
|
|
|
6602
6610
|
},
|
|
6603
6611
|
clearAllSelections() {
|
|
6604
6612
|
selectedElements.forEach((data, element) => {
|
|
6605
|
-
;
|
|
6606
|
-
|
|
6607
|
-
|
|
6613
|
+
const el = element;
|
|
6614
|
+
if (data.originalOutline) {
|
|
6615
|
+
el.style.outline = data.originalOutline;
|
|
6616
|
+
} else {
|
|
6617
|
+
el.style.removeProperty("outline");
|
|
6618
|
+
}
|
|
6619
|
+
if (data.originalOutlineOffset) {
|
|
6620
|
+
el.style.outlineOffset = data.originalOutlineOffset;
|
|
6621
|
+
} else {
|
|
6622
|
+
el.style.removeProperty("outline-offset");
|
|
6623
|
+
}
|
|
6608
6624
|
});
|
|
6609
6625
|
badges.forEach((badge) => {
|
|
6610
6626
|
badge._cleanup?.();
|
|
@@ -7674,9 +7690,13 @@
|
|
|
7674
7690
|
document.addEventListener("keydown", this.handlePopoverKeydown);
|
|
7675
7691
|
this.updateComplete.then(() => {
|
|
7676
7692
|
const popoverEl = this.shadowRoot?.querySelector(".popover");
|
|
7677
|
-
const
|
|
7693
|
+
const textareaEl = this.shadowRoot?.querySelector(".popover-input");
|
|
7678
7694
|
if (!popoverEl || !element) return;
|
|
7679
|
-
|
|
7695
|
+
if (textareaEl) {
|
|
7696
|
+
textareaEl.focus();
|
|
7697
|
+
textareaEl.style.height = "auto";
|
|
7698
|
+
textareaEl.style.height = Math.min(textareaEl.scrollHeight, 120) + "px";
|
|
7699
|
+
}
|
|
7680
7700
|
this.popoverCleanup = autoUpdate(element, popoverEl, () => {
|
|
7681
7701
|
computePosition2(element, popoverEl, {
|
|
7682
7702
|
strategy: "fixed",
|
|
@@ -7696,7 +7716,7 @@
|
|
|
7696
7716
|
});
|
|
7697
7717
|
}
|
|
7698
7718
|
handlePopoverInputKeydown(e5) {
|
|
7699
|
-
if (e5.key === "Enter") {
|
|
7719
|
+
if (e5.key === "Enter" && (e5.metaKey || e5.ctrlKey)) {
|
|
7700
7720
|
e5.preventDefault();
|
|
7701
7721
|
this.hideCommentPopover();
|
|
7702
7722
|
} else if (e5.key === "Escape") {
|
|
@@ -7717,6 +7737,8 @@
|
|
|
7717
7737
|
const target = e5.target;
|
|
7718
7738
|
const comment = target.value;
|
|
7719
7739
|
const element = this.commentPopover.element;
|
|
7740
|
+
target.style.height = "auto";
|
|
7741
|
+
target.style.height = Math.min(target.scrollHeight, 120) + "px";
|
|
7720
7742
|
this.commentPopover = { ...this.commentPopover, comment };
|
|
7721
7743
|
if (element) {
|
|
7722
7744
|
const hasComment = comment.trim().length > 0;
|
|
@@ -7777,7 +7799,7 @@
|
|
|
7777
7799
|
this.showToast("No elements selected");
|
|
7778
7800
|
return;
|
|
7779
7801
|
}
|
|
7780
|
-
const text = `I have selected ${elements.length}
|
|
7802
|
+
const text = `I have selected ${elements.length} feedback item(s) in the browser. Use the \`annotator_get_feedback\` tool to retrieve them and modify the code.`;
|
|
7781
7803
|
try {
|
|
7782
7804
|
await navigator.clipboard.writeText(text);
|
|
7783
7805
|
this.showToast(`Copied ${elements.length} element(s)`);
|
|
@@ -7845,7 +7867,7 @@
|
|
|
7845
7867
|
this.showToast("No session ID");
|
|
7846
7868
|
return;
|
|
7847
7869
|
}
|
|
7848
|
-
const text = `I have
|
|
7870
|
+
const text = `I have feedback in the browser (session: ${this.sessionId}). Use the \`annotator_get_feedback\` tool to retrieve them.`;
|
|
7849
7871
|
try {
|
|
7850
7872
|
await navigator.clipboard.writeText(text);
|
|
7851
7873
|
this.showToast("Copied!");
|
|
@@ -7920,14 +7942,14 @@
|
|
|
7920
7942
|
|
|
7921
7943
|
${this.commentPopover.visible ? x`
|
|
7922
7944
|
<div class="popover">
|
|
7923
|
-
<
|
|
7924
|
-
type="text"
|
|
7945
|
+
<textarea
|
|
7925
7946
|
class="popover-input"
|
|
7926
|
-
placeholder="Add a note..."
|
|
7947
|
+
placeholder="Add a note... (⌘↵ to close)"
|
|
7927
7948
|
.value=${this.commentPopover.comment}
|
|
7928
7949
|
@input=${this.handlePopoverInput}
|
|
7929
7950
|
@keydown=${this.handlePopoverInputKeydown}
|
|
7930
|
-
|
|
7951
|
+
rows="1"
|
|
7952
|
+
></textarea>
|
|
7931
7953
|
<div class="popover-actions">
|
|
7932
7954
|
<button class="popover-btn danger" @click=${this.removeSelectedElement} title="Remove selection">
|
|
7933
7955
|
${this.renderTrashIcon()}
|
|
@@ -8050,12 +8072,10 @@
|
|
|
8050
8072
|
top: 0;
|
|
8051
8073
|
left: 0;
|
|
8052
8074
|
z-index: 1000000;
|
|
8053
|
-
display: flex;
|
|
8054
|
-
align-items: stretch;
|
|
8055
8075
|
background: #1a1a1a;
|
|
8076
|
+
border: 1px solid rgba(99, 102, 241, 0.5);
|
|
8056
8077
|
border-radius: 8px;
|
|
8057
|
-
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.
|
|
8058
|
-
overflow: hidden;
|
|
8078
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5), 0 0 20px rgba(99, 102, 241, 0.3), 0 0 40px rgba(99, 102, 241, 0.1);
|
|
8059
8079
|
animation: popover-in 0.15s ease-out;
|
|
8060
8080
|
}
|
|
8061
8081
|
|
|
@@ -8071,16 +8091,20 @@
|
|
|
8071
8091
|
}
|
|
8072
8092
|
|
|
8073
8093
|
.popover-input {
|
|
8074
|
-
|
|
8075
|
-
min-
|
|
8076
|
-
max-
|
|
8094
|
+
width: 240px;
|
|
8095
|
+
min-height: 52px;
|
|
8096
|
+
max-height: 120px;
|
|
8077
8097
|
padding: 10px 12px;
|
|
8098
|
+
padding-bottom: 32px;
|
|
8078
8099
|
border: none;
|
|
8079
8100
|
background: transparent;
|
|
8080
8101
|
color: #fff;
|
|
8081
8102
|
font-size: 13px;
|
|
8082
8103
|
font-family: inherit;
|
|
8083
8104
|
outline: none;
|
|
8105
|
+
resize: none;
|
|
8106
|
+
overflow-y: auto;
|
|
8107
|
+
line-height: 1.4;
|
|
8084
8108
|
}
|
|
8085
8109
|
|
|
8086
8110
|
.popover-input::placeholder {
|
|
@@ -8088,37 +8112,41 @@
|
|
|
8088
8112
|
}
|
|
8089
8113
|
|
|
8090
8114
|
.popover-actions {
|
|
8115
|
+
position: absolute;
|
|
8116
|
+
bottom: 4px;
|
|
8117
|
+
right: 4px;
|
|
8091
8118
|
display: flex;
|
|
8092
8119
|
align-items: center;
|
|
8093
|
-
|
|
8120
|
+
gap: 2px;
|
|
8094
8121
|
}
|
|
8095
8122
|
|
|
8096
8123
|
.popover-btn {
|
|
8097
8124
|
display: flex;
|
|
8098
8125
|
align-items: center;
|
|
8099
8126
|
justify-content: center;
|
|
8100
|
-
width:
|
|
8101
|
-
height:
|
|
8127
|
+
width: 24px;
|
|
8128
|
+
height: 24px;
|
|
8102
8129
|
border: none;
|
|
8103
|
-
|
|
8104
|
-
|
|
8130
|
+
border-radius: 4px;
|
|
8131
|
+
background: rgba(255, 255, 255, 0.1);
|
|
8132
|
+
color: #888;
|
|
8105
8133
|
cursor: pointer;
|
|
8106
8134
|
transition: all 0.12s ease;
|
|
8107
8135
|
}
|
|
8108
8136
|
|
|
8109
8137
|
.popover-btn:hover {
|
|
8110
|
-
background: rgba(255, 255, 255, 0.
|
|
8138
|
+
background: rgba(255, 255, 255, 0.15);
|
|
8111
8139
|
color: #fff;
|
|
8112
8140
|
}
|
|
8113
8141
|
|
|
8114
8142
|
.popover-btn.danger:hover {
|
|
8115
|
-
background: rgba(239, 68, 68, 0.
|
|
8143
|
+
background: rgba(239, 68, 68, 0.2);
|
|
8116
8144
|
color: #f87171;
|
|
8117
8145
|
}
|
|
8118
8146
|
|
|
8119
8147
|
.popover-btn svg {
|
|
8120
|
-
width:
|
|
8121
|
-
height:
|
|
8148
|
+
width: 12px;
|
|
8149
|
+
height: 12px;
|
|
8122
8150
|
}
|
|
8123
8151
|
|
|
8124
8152
|
.hidden {
|
package/dist/index.cjs
CHANGED
|
@@ -111,7 +111,7 @@ const toolbar = document.createElement('annotator-toolbar');
|
|
|
111
111
|
toolbar.setAttribute('ws-endpoint', '${e.replace("http://","ws://").replace("https://","wss://")}');
|
|
112
112
|
toolbar.setAttribute('verbose', '${n}');
|
|
113
113
|
document.body.prepend(toolbar);
|
|
114
|
-
`;i.send(s+u)}catch(a){console.error("Error reading annotator-toolbar.js:",a),i.status(404).send("File not found")}}),t.get("/health",(r,i)=>{i.json({status:"ok",sessions:Hn.size})}),t.get("/api/sessions",(r,i)=>{i.json(Zp())})}function zce(t,e){t.on("connection",n=>{if(n.handshake.query.clientType==="mcp"){Rce(n,e);return}let i=Tce(),a={id:i,url:"",title:"",connectedAt:Date.now(),lastActivity:Date.now()},o=Qq(n);Hn.set(i,{socket:n,rpc:o,session:a}),e.log(`Browser connected: ${i} (total: ${Hn.size})`),o.handle.getSessions(async()=>Zp()),o.handle.ping(async()=>"pong"),o.handle.rpcError(s=>{e.error("RPC Error:",s)}),n.emit("connected",{sessionId:i}),n.on("pageContextChanged",s=>{a.url=s.url,a.title=s.title,a.lastActivity=Date.now()}),n.on("disconnect",()=>{o.dispose(),Hn.delete(i),e.log(`Browser disconnected: ${i} (total: ${Hn.size})`)})})}function Rce(t,e){e.log("MCP client connected"),t.on("mcp:listSessions",n=>{n({success:!0,data:Zp()})}),t.on("mcp:getPageContext",async(n,r)=>{let i=St(n);if("error"in i){r({success:!1,error:i.error});return}try{let a=await i.rpc.client.getPageContext(1e4);Ct(a)?r({success:!1,error:a.message}):r({success:!0,data:a})}catch(a){r({success:!1,error:a instanceof Error?a.message:String(a)})}}),t.on("mcp:triggerSelection",async(n,r,i,a,o)=>{let s=St(n);if("error"in s){o({success:!1,error:s.error});return}try{let c=await s.rpc.client.triggerSelection(r,i,a,1e4);Ct(c)?o({success:!1,error:c.message}):o({success:!0,data:c})}catch(c){o({success:!1,error:c instanceof Error?c.message:String(c)})}}),t.on("mcp:getSelectedElements",async(n,r)=>{let i=St(n);if("error"in i){r({success:!1,error:i.error});return}try{let a=await i.rpc.client.getSelectedElements(15e3);Ct(a)?r({success:!1,error:a.message}):r({success:!0,data:a})}catch(a){r({success:!1,error:a instanceof Error?a.message:String(a)})}}),t.on("mcp:captureScreenshot",async(n,r,i,a,o,s)=>{let c=St(n);if("error"in c){s({success:!1,error:c.error});return}try{let u=await c.rpc.client.captureScreenshot(r,i,a,o,3e4);Ct(u)?s({success:!1,error:u.message}):s({success:!0,data:u})}catch(u){s({success:!1,error:u instanceof Error?u.message:String(u)})}}),t.on("mcp:clearSelection",async(n,r)=>{let i=St(n);if("error"in i){r({success:!1,error:i.error});return}i.rpc.client.clearSelection(),r({success:!0})}),t.on("mcp:injectCSS",async(n,r,i)=>{let a=St(n);if("error"in a){i({success:!1,error:a.error});return}try{let o=await a.rpc.client.injectCSS(r,1e4);Ct(o)?i({success:!1,error:o.message}):i({success:!0,data:o})}catch(o){i({success:!1,error:o instanceof Error?o.message:String(o)})}}),t.on("mcp:injectJS",async(n,r,i)=>{let a=St(n);if("error"in a){i({success:!1,error:a.error});return}try{let o=await a.rpc.client.injectJS(r,15e3);Ct(o)?i({success:!1,error:o.message}):i({success:!0,data:o})}catch(o){i({success:!1,error:o instanceof Error?o.message:String(o)})}}),t.on("mcp:getConsole",async(n,r,i)=>{let a=St(n);if("error"in a){i({success:!1,error:a.error});return}try{let o=await a.rpc.client.getConsole(r,15e3);Ct(o)?i({success:!1,error:o.message}):i({success:!0,data:o})}catch(o){i({success:!1,error:o instanceof Error?o.message:String(o)})}}),t.on("disconnect",()=>{e.log("MCP client disconnected")})}function St(t){let e=jce(t);if(!e){let n=Zp();return n.length===0?{error:"No browser connected. Add the annotator script to your webpage."}:{error:`Multiple sessions available. Specify sessionId. Available: ${n.map(r=>r.id).join(", ")}`}}return{rpc:e.rpc,sessionId:e.sessionId}}function Cce(){let t=new As({name:"ai-annotator",version:"1.0.0"}),e=Pe.string().optional().describe("Browser session ID (optional if only one session)");function n(r){return{content:[{type:"text",text:r}]}}return t.tool("annotator_list_sessions","List all connected browser sessions",{},async()=>{let r=Zp();return n(r.length>0?JSON.stringify(r,null,2):"No browser sessions connected. Add the annotator script to your webpage.")}),t.tool("annotator_get_page_context","Get current page context from browser session (URL, title, selection count)",{sessionId:e},async({sessionId:r})=>{let i=St(r);if("error"in i)return n(i.error);let a=await i.rpc.client.getPageContext(1e4);return Ct(a)?n(`Error: ${a.message}`):n(JSON.stringify(a,null,2))}),t.tool("annotator_select_element","Enter element inspection mode or select element by CSS/XPath selector",{sessionId:e,mode:Pe.enum(["inspect","selector"]).default("inspect").describe("Selection mode"),selector:Pe.string().optional().describe('CSS or XPath selector (required when mode is "selector")'),selectorType:Pe.enum(["css","xpath"]).default("css").describe("Type of selector")},async({sessionId:r,mode:i,selector:a,selectorType:o})=>{let s=St(r);if("error"in s)return n(s.error);let c=await s.rpc.client.triggerSelection(i,a,o,1e4);return Ct(c)?n(`Error: ${c.message}`):n(c.success?`Selection triggered. ${c.count} element(s) selected.`:`Selection failed: ${c.error}`)}),t.tool("annotator_get_selected_elements","Get data about currently selected elements in the browser",{sessionId:e},async({sessionId:r})=>{let i=St(r);if("error"in i)return n(i.error);let a=await i.rpc.client.getSelectedElements(15e3);return Ct(a)?n(`Error: ${a.message}`):n(a.length>0?JSON.stringify(a,null,2):"No elements selected. Use annotator_select_element first.")}),t.tool("annotator_capture_screenshot","Capture a screenshot of the viewport or a specific element. Returns the file path where the screenshot is saved.",{sessionId:e,type:Pe.enum(["viewport","element"]).default("viewport").describe("Type of screenshot"),selector:Pe.string().optional().describe("CSS selector for element screenshot"),format:Pe.enum(["png","jpeg"]).default("png").describe("Image format"),quality:Pe.number().min(0).max(1).default(.8).describe("Image quality (0-1)")},async({sessionId:r,type:i,selector:a,format:o,quality:s})=>{let c=St(r);if("error"in c)return n(c.error);let u=await c.rpc.client.captureScreenshot(i,a,o,s,3e4);if(Ct(u))return n(`Error: ${u.message}`);if(u.success&&u.base64){let p=Oce(u.base64,o);return n(p)}return n(`Screenshot failed: ${u.error}`)}),t.tool("annotator_clear_selection","Clear all selected elements in the browser",{sessionId:e},async({sessionId:r})=>{let i=St(r);return"error"in i?n(i.error):(i.rpc.client.clearSelection(),n("Selection cleared."))}),t.tool("annotator_inject_css","Inject CSS styles into the page",{sessionId:e,css:Pe.string().describe("CSS code to inject into the page")},async({sessionId:r,css:i})=>{let a=St(r);if("error"in a)return n(a.error);let o=await a.rpc.client.injectCSS(i,1e4);return Ct(o)?n(`Error: ${o.message}`):n(o.success?"CSS injected successfully.":`CSS injection failed: ${o.error}`)}),t.tool("annotator_inject_js","Inject and execute JavaScript code in the page context",{sessionId:e,code:Pe.string().describe("JavaScript code to execute in the page")},async({sessionId:r,code:i})=>{let a=St(r);if("error"in a)return n(a.error);let o=await a.rpc.client.injectJS(i,15e3);return Ct(o)?n(`Error: ${o.message}`):o.success?n(o.result!==void 0?`Result: ${JSON.stringify(o.result,null,2)}`:"JavaScript executed successfully (no return value)."):n(`JavaScript execution failed: ${o.error}`)}),t.tool("annotator_get_console","Get console logs captured from the browser",{sessionId:e,clear:Pe.boolean().default(!1).describe("Clear the console buffer after reading")},async({sessionId:r,clear:i})=>{let a=St(r);if("error"in a)return n(a.error);let o=await a.rpc.client.getConsole(i,15e3);return Ct(o)?n(`Error: ${o.message}`):n(o.length>0?JSON.stringify(o,null,2):"No console logs captured.")}),t}function Ace(t,e){let n=Cce(),r=new Map;t.all("/mcp",async(i,a)=>{let o=i.headers["mcp-session-id"],s;o&&r.has(o)?s=r.get(o):(s=new Wv({sessionIdGenerator:()=>crypto.randomUUID()}),await n.connect(s),s.onclose=()=>{for(let[c,u]of r.entries())if(u===s){r.delete(c),e.log(`MCP session closed: ${c}`);break}});try{await s.handleRequest(i,a,i.body);let c=a.getHeader("mcp-session-id");c&&!r.has(c)&&(r.set(c,s),e.log(`MCP session created: ${c}`))}catch(c){e.error("MCP request error:",c),a.headersSent||a.status(500).json({error:"MCP request failed"})}}),t.get("/mcp/info",(i,a)=>{a.json({name:"ai-annotator",version:"1.0.0",capabilities:{tools:!0},endpoint:"/mcp"})})}async function r9(t,e,n,r=!1){let i=e9(r),a=(0,CS.default)();a.use((0,n9.default)({origin:"*",methods:["GET","POST","OPTIONS"],allowedHeaders:["Content-Type","Authorization"]})),a.use(CS.default.json({limit:"10mb"})),Ice(a,n,r),Ace(a,i);let o=await Nce(a,t,e),s=new zR(o,{cors:{origin:"*",methods:["GET","POST"]},path:"/socket.io"});return zce(s,i),{app:a,server:o,io:s,port:t,listenAddress:e,publicAddress:n,verbose:r}}async function i9(t){return new Promise((e,n)=>{let r=!1,i=!1,a=!1;function o(){r&&i&&!a&&e()}Hn.forEach(({rpc:s})=>{s.dispose()}),Hn.clear(),t.io.close(s=>{s&&!a&&t.verbose&&console.error("Error closing Socket.IO server:",s),r=!0,o()}),t.server.listening?t.server.close(s=>{s&&!a?(a=!0,n(s)):(i=!0,o())}):(i=!0,o())})}function Nce(t,e,n){return new Promise((r,i)=>{let a=t.listen(e,n,()=>r(a));a.on("error",o=>{i(o)})})}var pD=require("net"),pg=require("fs"),ug=require("path");function Sue(){let t=[(0,ug.join)(__dirname,"..","package.json"),(0,ug.join)(__dirname,"package.json"),(0,ug.join)(process.cwd(),"package.json")];for(let e of t)if((0,pg.existsSync)(e))try{let n=JSON.parse((0,pg.readFileSync)(e,"utf-8"));if(n.name==="vite-plugin-ai-annotator"&&n.version)return n.version}catch{continue}return"0.0.0"}var Eue=Sue(),Et=process.argv.slice(2),$ue=Et[0];$ue==="mcp"?Promise.resolve().then(()=>(uD(),kue)).catch(t=>{console.error("Failed to start MCP CLI:",t),process.exit(1)}):Tue();async function Tue(){let t=Et.includes("--help")||Et.includes("-h"),e=Et.includes("--version")||Et.includes("-v"),n=Et.includes("--verbose")||Et.includes("-V"),r=Et.findIndex(m=>m==="--port"||m==="-p"),i=Et.findIndex(m=>m==="--listen"||m==="-l"),a=Et.findIndex(m=>m==="--public-address"||m==="-a");t&&(console.log(`
|
|
114
|
+
`;i.send(s+u)}catch(a){console.error("Error reading annotator-toolbar.js:",a),i.status(404).send("File not found")}}),t.get("/health",(r,i)=>{i.json({status:"ok",sessions:Hn.size})}),t.get("/api/sessions",(r,i)=>{i.json(Zp())})}function zce(t,e){t.on("connection",n=>{if(n.handshake.query.clientType==="mcp"){Rce(n,e);return}let i=Tce(),a={id:i,url:"",title:"",connectedAt:Date.now(),lastActivity:Date.now()},o=Qq(n);Hn.set(i,{socket:n,rpc:o,session:a}),e.log(`Browser connected: ${i} (total: ${Hn.size})`),o.handle.getSessions(async()=>Zp()),o.handle.ping(async()=>"pong"),o.handle.rpcError(s=>{e.error("RPC Error:",s)}),n.emit("connected",{sessionId:i}),n.on("pageContextChanged",s=>{a.url=s.url,a.title=s.title,a.lastActivity=Date.now()}),n.on("disconnect",()=>{o.dispose(),Hn.delete(i),e.log(`Browser disconnected: ${i} (total: ${Hn.size})`)})})}function Rce(t,e){e.log("MCP client connected"),t.on("mcp:listSessions",n=>{n({success:!0,data:Zp()})}),t.on("mcp:getPageContext",async(n,r)=>{let i=St(n);if("error"in i){r({success:!1,error:i.error});return}try{let a=await i.rpc.client.getPageContext(1e4);Ct(a)?r({success:!1,error:a.message}):r({success:!0,data:a})}catch(a){r({success:!1,error:a instanceof Error?a.message:String(a)})}}),t.on("mcp:triggerSelection",async(n,r,i,a,o)=>{let s=St(n);if("error"in s){o({success:!1,error:s.error});return}try{let c=await s.rpc.client.triggerSelection(r,i,a,1e4);Ct(c)?o({success:!1,error:c.message}):o({success:!0,data:c})}catch(c){o({success:!1,error:c instanceof Error?c.message:String(c)})}}),t.on("mcp:getSelectedElements",async(n,r)=>{let i=St(n);if("error"in i){r({success:!1,error:i.error});return}try{let a=await i.rpc.client.getSelectedElements(15e3);Ct(a)?r({success:!1,error:a.message}):r({success:!0,data:a})}catch(a){r({success:!1,error:a instanceof Error?a.message:String(a)})}}),t.on("mcp:captureScreenshot",async(n,r,i,a,o,s)=>{let c=St(n);if("error"in c){s({success:!1,error:c.error});return}try{let u=await c.rpc.client.captureScreenshot(r,i,a,o,3e4);Ct(u)?s({success:!1,error:u.message}):s({success:!0,data:u})}catch(u){s({success:!1,error:u instanceof Error?u.message:String(u)})}}),t.on("mcp:clearSelection",async(n,r)=>{let i=St(n);if("error"in i){r({success:!1,error:i.error});return}i.rpc.client.clearSelection(),r({success:!0})}),t.on("mcp:injectCSS",async(n,r,i)=>{let a=St(n);if("error"in a){i({success:!1,error:a.error});return}try{let o=await a.rpc.client.injectCSS(r,1e4);Ct(o)?i({success:!1,error:o.message}):i({success:!0,data:o})}catch(o){i({success:!1,error:o instanceof Error?o.message:String(o)})}}),t.on("mcp:injectJS",async(n,r,i)=>{let a=St(n);if("error"in a){i({success:!1,error:a.error});return}try{let o=await a.rpc.client.injectJS(r,15e3);Ct(o)?i({success:!1,error:o.message}):i({success:!0,data:o})}catch(o){i({success:!1,error:o instanceof Error?o.message:String(o)})}}),t.on("mcp:getConsole",async(n,r,i)=>{let a=St(n);if("error"in a){i({success:!1,error:a.error});return}try{let o=await a.rpc.client.getConsole(r,15e3);Ct(o)?i({success:!1,error:o.message}):i({success:!0,data:o})}catch(o){i({success:!1,error:o instanceof Error?o.message:String(o)})}}),t.on("disconnect",()=>{e.log("MCP client disconnected")})}function St(t){let e=jce(t);if(!e){let n=Zp();return n.length===0?{error:"No browser connected. Add the annotator script to your webpage."}:{error:`Multiple sessions available. Specify sessionId. Available: ${n.map(r=>r.id).join(", ")}`}}return{rpc:e.rpc,sessionId:e.sessionId}}function Cce(){let t=new As({name:"ai-annotator",version:"1.0.0"}),e=Pe.string().optional().describe("Browser session ID (optional if only one session)");function n(r){return{content:[{type:"text",text:r}]}}return t.tool("annotator_list_sessions","List all connected browser sessions",{},async()=>{let r=Zp();return n(r.length>0?JSON.stringify(r,null,2):"No browser sessions connected. Add the annotator script to your webpage.")}),t.tool("annotator_get_page_context","Get current page context from browser session (URL, title, selection count)",{sessionId:e},async({sessionId:r})=>{let i=St(r);if("error"in i)return n(i.error);let a=await i.rpc.client.getPageContext(1e4);return Ct(a)?n(`Error: ${a.message}`):n(JSON.stringify(a,null,2))}),t.tool("annotator_select_feedback","Enter feedback inspection mode or select feedback by CSS/XPath selector. Use this to let users mark UI elements they want to provide feedback on.",{sessionId:e,mode:Pe.enum(["inspect","selector"]).default("inspect").describe("Feedback selection mode"),selector:Pe.string().optional().describe('CSS or XPath selector (required when mode is "selector")'),selectorType:Pe.enum(["css","xpath"]).default("css").describe("Type of selector")},async({sessionId:r,mode:i,selector:a,selectorType:o})=>{let s=St(r);if("error"in s)return n(s.error);let c=await s.rpc.client.triggerSelection(i,a,o,1e4);return Ct(c)?n(`Error: ${c.message}`):n(c.success?`Feedback selection triggered. ${c.count} feedback item(s) selected.`:`Feedback selection failed: ${c.error}`)}),t.tool("annotator_get_feedback","Get data about currently selected feedback items in the browser. Returns details of UI elements the user has marked for feedback.",{sessionId:e},async({sessionId:r})=>{let i=St(r);if("error"in i)return n(i.error);let a=await i.rpc.client.getSelectedElements(15e3);return Ct(a)?n(`Error: ${a.message}`):n(a.length>0?JSON.stringify(a,null,2):"No feedback selected. Use annotator_select_feedback first.")}),t.tool("annotator_capture_screenshot","Capture a screenshot of the viewport or a specific element. Returns the file path where the screenshot is saved.",{sessionId:e,type:Pe.enum(["viewport","element"]).default("viewport").describe("Type of screenshot"),selector:Pe.string().optional().describe("CSS selector for element screenshot"),format:Pe.enum(["png","jpeg"]).default("png").describe("Image format"),quality:Pe.number().min(0).max(1).default(.8).describe("Image quality (0-1)")},async({sessionId:r,type:i,selector:a,format:o,quality:s})=>{let c=St(r);if("error"in c)return n(c.error);let u=await c.rpc.client.captureScreenshot(i,a,o,s,3e4);if(Ct(u))return n(`Error: ${u.message}`);if(u.success&&u.base64){let p=Oce(u.base64,o);return n(p)}return n(`Screenshot failed: ${u.error}`)}),t.tool("annotator_clear_feedback","Clear all selected feedback items in the browser. Removes all UI element selections made for feedback.",{sessionId:e},async({sessionId:r})=>{let i=St(r);return"error"in i?n(i.error):(i.rpc.client.clearSelection(),n("Feedback cleared."))}),t.tool("annotator_inject_css","Inject CSS styles into the page",{sessionId:e,css:Pe.string().describe("CSS code to inject into the page")},async({sessionId:r,css:i})=>{let a=St(r);if("error"in a)return n(a.error);let o=await a.rpc.client.injectCSS(i,1e4);return Ct(o)?n(`Error: ${o.message}`):n(o.success?"CSS injected successfully.":`CSS injection failed: ${o.error}`)}),t.tool("annotator_inject_js","Inject and execute JavaScript code in the page context",{sessionId:e,code:Pe.string().describe("JavaScript code to execute in the page")},async({sessionId:r,code:i})=>{let a=St(r);if("error"in a)return n(a.error);let o=await a.rpc.client.injectJS(i,15e3);return Ct(o)?n(`Error: ${o.message}`):o.success?n(o.result!==void 0?`Result: ${JSON.stringify(o.result,null,2)}`:"JavaScript executed successfully (no return value)."):n(`JavaScript execution failed: ${o.error}`)}),t.tool("annotator_get_console","Get console logs captured from the browser",{sessionId:e,clear:Pe.boolean().default(!1).describe("Clear the console buffer after reading")},async({sessionId:r,clear:i})=>{let a=St(r);if("error"in a)return n(a.error);let o=await a.rpc.client.getConsole(i,15e3);return Ct(o)?n(`Error: ${o.message}`):n(o.length>0?JSON.stringify(o,null,2):"No console logs captured.")}),t}function Ace(t,e){let n=Cce(),r=new Map;t.all("/mcp",async(i,a)=>{let o=i.headers["mcp-session-id"],s;o&&r.has(o)?s=r.get(o):(s=new Wv({sessionIdGenerator:()=>crypto.randomUUID()}),await n.connect(s),s.onclose=()=>{for(let[c,u]of r.entries())if(u===s){r.delete(c),e.log(`MCP session closed: ${c}`);break}});try{await s.handleRequest(i,a,i.body);let c=a.getHeader("mcp-session-id");c&&!r.has(c)&&(r.set(c,s),e.log(`MCP session created: ${c}`))}catch(c){e.error("MCP request error:",c),a.headersSent||a.status(500).json({error:"MCP request failed"})}}),t.get("/mcp/info",(i,a)=>{a.json({name:"ai-annotator",version:"1.0.0",capabilities:{tools:!0},endpoint:"/mcp"})})}async function r9(t,e,n,r=!1){let i=e9(r),a=(0,CS.default)();a.use((0,n9.default)({origin:"*",methods:["GET","POST","OPTIONS"],allowedHeaders:["Content-Type","Authorization"]})),a.use(CS.default.json({limit:"10mb"})),Ice(a,n,r),Ace(a,i);let o=await Nce(a,t,e),s=new zR(o,{cors:{origin:"*",methods:["GET","POST"]},path:"/socket.io"});return zce(s,i),{app:a,server:o,io:s,port:t,listenAddress:e,publicAddress:n,verbose:r}}async function i9(t){return new Promise((e,n)=>{let r=!1,i=!1,a=!1;function o(){r&&i&&!a&&e()}Hn.forEach(({rpc:s})=>{s.dispose()}),Hn.clear(),t.io.close(s=>{s&&!a&&t.verbose&&console.error("Error closing Socket.IO server:",s),r=!0,o()}),t.server.listening?t.server.close(s=>{s&&!a?(a=!0,n(s)):(i=!0,o())}):(i=!0,o())})}function Nce(t,e,n){return new Promise((r,i)=>{let a=t.listen(e,n,()=>r(a));a.on("error",o=>{i(o)})})}var pD=require("net"),pg=require("fs"),ug=require("path");function Sue(){let t=[(0,ug.join)(__dirname,"..","package.json"),(0,ug.join)(__dirname,"package.json"),(0,ug.join)(process.cwd(),"package.json")];for(let e of t)if((0,pg.existsSync)(e))try{let n=JSON.parse((0,pg.readFileSync)(e,"utf-8"));if(n.name==="vite-plugin-ai-annotator"&&n.version)return n.version}catch{continue}return"0.0.0"}var Eue=Sue(),Et=process.argv.slice(2),$ue=Et[0];$ue==="mcp"?Promise.resolve().then(()=>(uD(),kue)).catch(t=>{console.error("Failed to start MCP CLI:",t),process.exit(1)}):Tue();async function Tue(){let t=Et.includes("--help")||Et.includes("-h"),e=Et.includes("--version")||Et.includes("-v"),n=Et.includes("--verbose")||Et.includes("-V"),r=Et.findIndex(m=>m==="--port"||m==="-p"),i=Et.findIndex(m=>m==="--listen"||m==="-l"),a=Et.findIndex(m=>m==="--public-address"||m==="-a");t&&(console.log(`
|
|
115
115
|
AI Annotator - AI-powered web inspection tool
|
|
116
116
|
|
|
117
117
|
Usage:
|
package/package.json
CHANGED