vite-plugin-ai-annotator 1.16.0 → 1.16.2
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.d.ts +5 -1
- package/dist/annotator-toolbar.js +68 -16
- package/dist/index.cjs +1 -1
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ export declare class AnnotatorToolbar extends LitElement {
|
|
|
19
19
|
private commentPopover;
|
|
20
20
|
private tooltip;
|
|
21
21
|
private toastMessage;
|
|
22
|
+
private channelListenerCount;
|
|
22
23
|
private popoverCleanup;
|
|
23
24
|
private tooltipCleanup;
|
|
24
25
|
private toastTimeout;
|
|
@@ -72,11 +73,14 @@ export declare class AnnotatorToolbar extends LitElement {
|
|
|
72
73
|
private renderTrashIcon;
|
|
73
74
|
private renderCloseIcon;
|
|
74
75
|
private renderHelpIcon;
|
|
76
|
+
private renderSendIcon;
|
|
75
77
|
private renderClipboardIcon;
|
|
76
78
|
private showToast;
|
|
77
79
|
private showTooltip;
|
|
78
80
|
private hideTooltip;
|
|
79
|
-
private
|
|
81
|
+
private buildFeedbackPrompt;
|
|
82
|
+
private copyFeedbackToClipboard;
|
|
83
|
+
private sendFeedbackToClaude;
|
|
80
84
|
private renderErrorIcon;
|
|
81
85
|
private openHelpPage;
|
|
82
86
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -7528,6 +7528,7 @@
|
|
|
7528
7528
|
this.commentPopover = { visible: false, element: null, comment: "" };
|
|
7529
7529
|
this.tooltip = { visible: false, text: "", x: 0, y: 0 };
|
|
7530
7530
|
this.toastMessage = "";
|
|
7531
|
+
this.channelListenerCount = 0;
|
|
7531
7532
|
this.popoverCleanup = null;
|
|
7532
7533
|
this.tooltipCleanup = null;
|
|
7533
7534
|
this.toastTimeout = null;
|
|
@@ -7670,6 +7671,9 @@
|
|
|
7670
7671
|
const prefix = data.status === "done" ? "\u2713 " : data.status === "error" ? "\u2717 " : data.status === "progress" ? "\u2026 " : "";
|
|
7671
7672
|
this.showToast(prefix + data.message);
|
|
7672
7673
|
});
|
|
7674
|
+
this.socket.on("channel:status", (data) => {
|
|
7675
|
+
this.channelListenerCount = typeof data?.listenerCount === "number" ? data.listenerCount : 0;
|
|
7676
|
+
});
|
|
7673
7677
|
}
|
|
7674
7678
|
wrapRpcHandler(name, handler) {
|
|
7675
7679
|
return (async (...args) => {
|
|
@@ -8067,16 +8071,18 @@
|
|
|
8067
8071
|
return;
|
|
8068
8072
|
}
|
|
8069
8073
|
const text = `I have selected ${elements.length} feedback item(s) in the browser (session: ${this.sessionId}). Fetch them via GET ${this.wsEndpoint}/api/sessions/${this.sessionId}/feedback and modify the code accordingly.`;
|
|
8070
|
-
|
|
8074
|
+
const willSend = this.socket?.connected && this.channelListenerCount > 0;
|
|
8075
|
+
if (willSend) {
|
|
8071
8076
|
this.socket.emit("feedback:submitted", { count: elements.length });
|
|
8072
8077
|
}
|
|
8078
|
+
const successToast = willSend ? `Sent ${elements.length} element(s) to Claude` : `Copied ${elements.length} element(s)`;
|
|
8073
8079
|
try {
|
|
8074
8080
|
await navigator.clipboard.writeText(text);
|
|
8075
|
-
this.showToast(
|
|
8081
|
+
this.showToast(successToast);
|
|
8076
8082
|
this.exitInspectingMode();
|
|
8077
8083
|
} catch (error) {
|
|
8078
|
-
this.showToast(
|
|
8079
|
-
this.log("Clipboard copy failed
|
|
8084
|
+
this.showToast(willSend ? successToast : "Failed to copy");
|
|
8085
|
+
this.log("Clipboard copy failed:", error);
|
|
8080
8086
|
this.exitInspectingMode();
|
|
8081
8087
|
}
|
|
8082
8088
|
}
|
|
@@ -8119,6 +8125,11 @@
|
|
|
8119
8125
|
<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
8126
|
</svg>`;
|
|
8121
8127
|
}
|
|
8128
|
+
renderSendIcon() {
|
|
8129
|
+
return x`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
8130
|
+
<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" />
|
|
8131
|
+
</svg>`;
|
|
8132
|
+
}
|
|
8122
8133
|
renderClipboardIcon() {
|
|
8123
8134
|
return x`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
8124
8135
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9.75a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
|
|
@@ -8167,7 +8178,14 @@
|
|
|
8167
8178
|
}
|
|
8168
8179
|
this.tooltip = { visible: false, text: "", x: 0, y: 0 };
|
|
8169
8180
|
}
|
|
8170
|
-
|
|
8181
|
+
// Builds the paste-prompt text that lets a Claude session fetch feedback
|
|
8182
|
+
// via REST. Used by both the Copy button (clipboard) and is conceptually
|
|
8183
|
+
// what the Send button replaces (channel push -> Claude already knows the
|
|
8184
|
+
// session, no text needed).
|
|
8185
|
+
buildFeedbackPrompt() {
|
|
8186
|
+
return `I have feedback in the browser (session: ${this.sessionId}). Fetch them via GET ${this.wsEndpoint}/api/sessions/${this.sessionId}/feedback`;
|
|
8187
|
+
}
|
|
8188
|
+
async copyFeedbackToClipboard() {
|
|
8171
8189
|
this.exitInspectingMode();
|
|
8172
8190
|
if (this.demo) {
|
|
8173
8191
|
this.showToast("Demo mode \u2014 no server");
|
|
@@ -8177,18 +8195,36 @@
|
|
|
8177
8195
|
this.showToast("No session ID");
|
|
8178
8196
|
return;
|
|
8179
8197
|
}
|
|
8180
|
-
const text =
|
|
8181
|
-
if (this.socket?.connected) {
|
|
8182
|
-
this.socket.emit("feedback:submitted", { count: 0 });
|
|
8183
|
-
}
|
|
8198
|
+
const text = this.buildFeedbackPrompt();
|
|
8184
8199
|
try {
|
|
8185
8200
|
await navigator.clipboard.writeText(text);
|
|
8186
|
-
this.showToast("
|
|
8201
|
+
this.showToast("Copied!");
|
|
8187
8202
|
this.log("Copied to clipboard:", text);
|
|
8188
8203
|
} catch (error) {
|
|
8189
|
-
this.showToast("
|
|
8190
|
-
this.log("
|
|
8204
|
+
this.showToast("Failed to copy");
|
|
8205
|
+
this.log("Failed to copy:", error);
|
|
8206
|
+
}
|
|
8207
|
+
}
|
|
8208
|
+
sendFeedbackToClaude() {
|
|
8209
|
+
this.exitInspectingMode();
|
|
8210
|
+
if (this.demo) {
|
|
8211
|
+
this.showToast("Demo mode \u2014 no server");
|
|
8212
|
+
return;
|
|
8213
|
+
}
|
|
8214
|
+
if (!this.sessionId) {
|
|
8215
|
+
this.showToast("No session ID");
|
|
8216
|
+
return;
|
|
8217
|
+
}
|
|
8218
|
+
if (!this.socket?.connected) {
|
|
8219
|
+
this.showToast("Not connected");
|
|
8220
|
+
return;
|
|
8221
|
+
}
|
|
8222
|
+
if (this.channelListenerCount === 0) {
|
|
8223
|
+
this.showToast("No Claude listening");
|
|
8224
|
+
return;
|
|
8191
8225
|
}
|
|
8226
|
+
this.socket.emit("feedback:submitted", { count: 0 });
|
|
8227
|
+
this.showToast("Sent to Claude");
|
|
8192
8228
|
}
|
|
8193
8229
|
renderErrorIcon() {
|
|
8194
8230
|
return x`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
@@ -8244,15 +8280,28 @@
|
|
|
8244
8280
|
|
|
8245
8281
|
<button
|
|
8246
8282
|
class="toolbar-btn"
|
|
8247
|
-
@click=${this.
|
|
8248
|
-
@mouseenter=${(e5) => this.showTooltip("Copy
|
|
8283
|
+
@click=${this.copyFeedbackToClipboard}
|
|
8284
|
+
@mouseenter=${(e5) => this.showTooltip("Copy prompt for Claude", e5.currentTarget)}
|
|
8249
8285
|
@mouseleave=${() => this.hideTooltip()}
|
|
8250
|
-
aria-label="Copy
|
|
8251
|
-
title="Copy
|
|
8286
|
+
aria-label="Copy feedback prompt to clipboard"
|
|
8287
|
+
title="Copy"
|
|
8252
8288
|
>
|
|
8253
8289
|
${this.renderClipboardIcon()}
|
|
8254
8290
|
</button>
|
|
8255
8291
|
|
|
8292
|
+
<button
|
|
8293
|
+
class="toolbar-btn"
|
|
8294
|
+
@click=${this.sendFeedbackToClaude}
|
|
8295
|
+
@mouseenter=${(e5) => this.showTooltip(this.channelListenerCount > 0 ? "Send to Claude" : "No Claude listening \u2014 install the channel plugin", e5.currentTarget)}
|
|
8296
|
+
@mouseleave=${() => this.hideTooltip()}
|
|
8297
|
+
?disabled=${this.channelListenerCount === 0}
|
|
8298
|
+
aria-label="${this.channelListenerCount > 0 ? "Send selections to Claude Code" : "Send to Claude (no listener connected)"}"
|
|
8299
|
+
aria-disabled="${this.channelListenerCount === 0}"
|
|
8300
|
+
title="${this.channelListenerCount > 0 ? "Send to Claude" : "No Claude listening"}"
|
|
8301
|
+
>
|
|
8302
|
+
${this.renderSendIcon()}
|
|
8303
|
+
</button>
|
|
8304
|
+
|
|
8256
8305
|
<button
|
|
8257
8306
|
class="toolbar-btn"
|
|
8258
8307
|
@click=${this.openHelpPage}
|
|
@@ -8586,6 +8635,9 @@
|
|
|
8586
8635
|
__decorateClass([
|
|
8587
8636
|
r5()
|
|
8588
8637
|
], AnnotatorToolbar.prototype, "toastMessage", 2);
|
|
8638
|
+
__decorateClass([
|
|
8639
|
+
r5()
|
|
8640
|
+
], AnnotatorToolbar.prototype, "channelListenerCount", 2);
|
|
8589
8641
|
if (!customElements.get("annotator-toolbar")) {
|
|
8590
8642
|
customElements.define("annotator-toolbar", AnnotatorToolbar);
|
|
8591
8643
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -66,7 +66,7 @@ const toolbar = document.createElement('annotator-toolbar');
|
|
|
66
66
|
toolbar.setAttribute('ws-endpoint', '${e.replace("http://","ws://").replace("https://","wss://")}');
|
|
67
67
|
toolbar.setAttribute('verbose', '${i}');
|
|
68
68
|
document.body.prepend(toolbar);
|
|
69
|
-
`;s.send(c+l)}catch(o){console.error("Error reading annotator-toolbar.js:",o),s.status(404).send("File not found")}}),a.get("/health",(t,s)=>{s.json({status:"ok",sessions:n.size})}),a.get("/api/sessions",(t,s)=>{s.json(kn(n))})}function kn(a){return Array.from(a.values()).map(e=>e.session)}function i0(a,e){if(e){let i=a.get(e);return i?{rpc:i.rpc,sessionId:e}:null}if(a.size===1){let i=a.entries().next().value;if(i){let[n,t]=i;return{rpc:t.rpc,sessionId:n}}}return null}var Jb="channels";function i5(a,e,i){a.on("connection",
|
|
69
|
+
`;s.send(c+l)}catch(o){console.error("Error reading annotator-toolbar.js:",o),s.status(404).send("File not found")}}),a.get("/health",(t,s)=>{s.json({status:"ok",sessions:n.size})}),a.get("/api/sessions",(t,s)=>{s.json(kn(n))})}function kn(a){return Array.from(a.values()).map(e=>e.session)}function i0(a,e){if(e){let i=a.get(e);return i?{rpc:i.rpc,sessionId:e}:null}if(a.size===1){let i=a.entries().next().value;if(i){let[n,t]=i;return{rpc:t.rpc,sessionId:n}}}return null}var Jb="channels";function i5(a,e,i){let n=0,t=()=>{for(let s of i.values())s.socket.emit("channel:status",{listenerCount:n})};a.on("connection",s=>{if(s.handshake.query.role==="channel"){s.join(Jb),n++,t(),e.log(`Channel client connected (sid: ${s.id}, total: ${n})`),s.on("channel:notify",l=>{if(!l?.sessionId||typeof l.message!="string")return;let u=i.get(l.sessionId);u&&u.socket.emit("channel:notify",{message:l.message,status:l.status??"info"})}),s.on("disconnect",()=>{n=Math.max(0,n-1),t(),e.log(`Channel client disconnected (sid: ${s.id}, total: ${n})`)});return}let r=e5(),c={id:r,url:"",title:"",connectedAt:Date.now(),lastActivity:Date.now()},p=Gb(s);i.set(r,{socket:s,rpc:p,session:c}),e.log(`Browser connected: ${r} (total: ${i.size})`),p.handle.getSessions(async()=>kn(i)),p.handle.ping(async()=>"pong"),p.handle.rpcError(l=>{e.error("RPC Error:",l)}),s.emit("connected",{sessionId:r}),s.emit("channel:status",{listenerCount:n}),s.on("pageContextChanged",l=>{c.url=l.url,c.title=l.title,c.lastActivity=Date.now()}),s.on("feedback:submitted",l=>{let u=typeof l?.count=="number"?l.count:0;c.lastActivity=Date.now(),a.to(Jb).emit("feedback:submitted",{sessionId:r,pageUrl:c.url,pageTitle:c.title,count:u})}),s.on("disconnect",()=>{p.dispose(),i.delete(r),e.log(`Browser disconnected: ${r} (total: ${i.size})`)})})}function n5(a,e){let i=i0(a,e);if(!i){let n=kn(a);return n.length===0?{error:"No browser connected. Add the annotator script to your webpage."}:{error:`Multiple sessions available. Specify sessionId. Available: ${n.map(t=>t.id).join(", ")}`}}return{rpc:i.rpc,sessionId:i.sessionId}}function t5(a,e,i){function n(t,s){let o=n5(i,s);return"error"in o?(t.status(400).json({error:o.error}),null):o.rpc}a.get("/api/sessions",(t,s)=>{s.json(kn(i))}),a.get("/api/sessions/:id/page-context",async(t,s)=>{let o=n(s,t.params.id);if(o)try{let r=await o.client.getPageContext(1e4);s.json(r)}catch(r){s.status(500).json({error:r instanceof Error?r.message:String(r)})}}),a.post("/api/sessions/:id/select",async(t,s)=>{let o=n(s,t.params.id);if(!o)return;let{mode:r="inspect",selector:c,selectorType:p="css"}=t.body||{};try{let l=await o.client.triggerSelection(r,c,p,1e4);s.json(l)}catch(l){s.status(500).json({error:l instanceof Error?l.message:String(l)})}}),a.get("/api/sessions/:id/feedback",async(t,s)=>{let o=n(s,t.params.id);if(o)try{let r=await o.client.getSelectedElements(15e3);if(Array.isArray(r)&&r.length===0){s.json([]);return}let p=t.query.fields?.split(",").filter(Boolean),l=Qb(r,p);s.json(l)}catch(r){s.status(500).json({error:r instanceof Error?r.message:String(r)})}}),a.delete("/api/sessions/:id/feedback",(t,s)=>{let o=n(s,t.params.id);o&&(o.client.clearSelection(),s.json({success:!0}))}),a.post("/api/sessions/:id/screenshot",async(t,s)=>{let o=n(s,t.params.id);if(!o)return;let{type:r="viewport",selector:c,quality:p=.7}=t.body||{};try{let l=await o.client.captureScreenshot(r,c,p,3e4);if("success"in l&&l.success&&"base64"in l&&l.base64){let u=Yb(l.base64);s.json({success:!0,filePath:u})}else s.json(l)}catch(l){s.status(500).json({error:l instanceof Error?l.message:String(l)})}}),a.post("/api/sessions/:id/inject-css",async(t,s)=>{let o=n(s,t.params.id);if(!o)return;let{css:r}=t.body||{};if(!r){s.status(400).json({error:"css field is required"});return}try{let c=await o.client.injectCSS(r,1e4);s.json(c)}catch(c){s.status(500).json({error:c instanceof Error?c.message:String(c)})}}),a.post("/api/sessions/:id/inject-js",async(t,s)=>{let o=n(s,t.params.id);if(!o)return;let{code:r}=t.body||{};if(!r){s.status(400).json({error:"code field is required"});return}try{let c=await o.client.injectJS(r,15e3);s.json(c)}catch(c){s.status(500).json({error:c instanceof Error?c.message:String(c)})}}),a.get("/api/sessions/:id/console",async(t,s)=>{let o=n(s,t.params.id);if(!o)return;let r=t.query.clear==="true";try{let c=await o.client.getConsole(r,15e3);s.json(c)}catch(c){s.status(500).json({error:c instanceof Error?c.message:String(c)})}}),e.log("REST API routes registered at /api/*")}async function n0(a,e,i,n=!1){let t=Kb(n),s=(0,yp.default)(),o=new Map;s.use((0,a0.default)({origin:"*",methods:["GET","POST","OPTIONS"],allowedHeaders:["Content-Type","Authorization"]})),s.use(yp.default.json({limit:"10mb"})),a5(s,i,n,o),t5(s,t,o);let r=await s5(s,a,e),c=new Vb(r,{cors:{origin:"*",methods:["GET","POST"]},path:"/socket.io",maxHttpBufferSize:5e7});return i5(c,t,o),{app:s,server:r,io:c,port:a,listenAddress:e,publicAddress:i,verbose:n,getAllSessions:()=>kn(o),getRpc:p=>i0(o,p)}}async function t0(a){return new Promise(e=>{a.io.close(()=>{e()})})}function s5(a,e,i){return new Promise((n,t)=>{let s=a.listen(e,i,()=>n(s));s.on("error",o=>{t(o)})})}var o0=require("net");var Ss=require("node:fs"),_s=require("node:path");function s0(){let a=[(0,_s.join)(__dirname,"..","package.json"),(0,_s.join)(__dirname,"package.json"),(0,_s.join)(process.cwd(),"package.json")];for(let e of a)if((0,Ss.existsSync)(e))try{let i=JSON.parse((0,Ss.readFileSync)(e,"utf-8"));if(i.name==="vite-plugin-ai-annotator"&&i.version)return i.version}catch{continue}return"0.0.0"}var o5=s0(),te=process.argv.slice(2);r5();async function r5(){let a=te.includes("--help")||te.includes("-h"),e=te.includes("--version")||te.includes("-v"),i=te.includes("--verbose")||te.includes("-V"),n=te.findIndex(x=>x==="--port"||x==="-p"),t=te.findIndex(x=>x==="--listen"||x==="-l"),s=te.findIndex(x=>x==="--public-address"||x==="-a");a&&(console.log(`
|
|
70
70
|
AI Annotator - AI-powered web inspection tool
|
|
71
71
|
|
|
72
72
|
Usage:
|
package/package.json
CHANGED