Examples/Cursor Local

Cursor Local Workflow

Integrate anyclick with Cursor's local CLI for instant AI-powered code fixes during development.

How It Works

  1. 1Right-click an element and select "Fix with Cursor"
  2. 2Feedback is sent to a local server running on your machine
  3. 3Server saves feedback to a file and invokes cursor-agent
  4. 4Cursor AI analyzes the context and proposes a fix

Installation

Terminal
npm install @ewjdev/anyclick-cursor-local

1. Start the Local Server

The local adapter requires a server to receive feedback. Add a script to your package.json:

package.json
{
"scripts": {
"feedback-server": "anyclick-local-server",
"dev": "concurrently \"npm run feedback-server\" \"next dev\""
}
}

Start the server:

Terminal
npm run feedback-server
# Output:
# 🚀 anyclick local server running on http://localhost:3847
# 📁 Feedback files will be saved to: .feedback/
# 🔧 Cursor integration: enabled

2. Configure the Provider

Set up the local adapter for development mode:

app/providers.tsx
'use client';
import { FeedbackProvider, filterMenuItemsByRole } from '@ewjdev/anyclick-react';
import type { FeedbackMenuItem } from '@ewjdev/anyclick-react';
import { createHttpAdapter } from '@ewjdev/anyclick-github';
import { createLocalAdapter } from '@ewjdev/anyclick-cursor-local';
import { Monitor, Cloud, Bug, Lightbulb } from 'lucide-react';
// Production adapter (GitHub)
const githubAdapter = createHttpAdapter({
endpoint: '/api/feedback',
});
// Development adapter (local Cursor)
const localAdapter = createLocalAdapter({
serverUrl: 'http://localhost:3847',
// Path to your project (for Cursor to open)
projectPath: process.cwd(),
});
// Choose adapter based on environment
const isDev = process.env.NODE_ENV === 'development';
// Menu items with Cursor options
const menuItems: FeedbackMenuItem[] = [
{ type: 'bug', label: 'Report Bug', icon: <Bug className="w-4 h-4" />, showComment: true },
{ type: 'feature', label: 'Suggest Feature', icon: <Lightbulb className="w-4 h-4" />, showComment: true },
// Cursor options (dev only)
...(isDev ? [{
type: 'cursor_menu' as const,
label: 'Fix with Cursor',
children: [
{
type: 'cursor_local' as const,
label: 'Fix Locally',
icon: <Monitor className="w-4 h-4" />,
showComment: true,
},
{
type: 'cursor_cloud' as const,
label: 'Fix with Cloud Agent',
icon: <Cloud className="w-4 h-4" />,
showComment: true,
},
],
}] : []),
];
export function Providers({ children }: { children: React.ReactNode }) {
return (
<FeedbackProvider
adapter={isDev ? localAdapter : githubAdapter}
menuItems={menuItems}
>
{children}
</FeedbackProvider>
);
}

3. Multi-Adapter Setup (Optional)

Route different feedback types to different adapters:

app/providers.tsx
import type { FeedbackAdapter, FeedbackPayload } from '@ewjdev/anyclick-core';
// Create a router adapter
function createRoutingAdapter(config: {
local: FeedbackAdapter;
github: FeedbackAdapter;
}): FeedbackAdapter {
return {
async submit(payload: FeedbackPayload) {
// Route Cursor types to local adapter
if (payload.type === 'cursor_local' || payload.type === 'cursor_cloud') {
return config.local.submit(payload);
}
// Route everything else to GitHub
return config.github.submit(payload);
},
};
}
const adapter = createRoutingAdapter({
local: localAdapter,
github: githubAdapter,
});
<FeedbackProvider adapter={adapter} menuItems={menuItems}>
{children}
</FeedbackProvider>

Server Configuration

Customize the local server behavior:

anyclick.config.js
module.exports = {
// Server port (default: 3847)
port: 3847,
// Directory to save feedback files
outputDir: '.feedback',
// Cursor CLI command (if not in PATH)
cursorPath: '/Applications/Cursor.app/Contents/MacOS/Cursor',
// Custom handler when feedback is received
onFeedback: async (payload, filePath) => {
console.log(`Feedback saved to: ${filePath}`);
// Optional: trigger custom actions
// await sendSlackNotification(payload);
},
// Format the AI prompt
formatPrompt: (payload) => {
return `
Fix the following issue in the codebase:
## Problem
${payload.comment || 'User reported an issue with this element'}
## Element
- Selector: ${payload.element.selector}
- Text: ${payload.element.innerText}
## Location
- URL: ${payload.page.url}
Please analyze the code and propose a fix.
`;
},
// CORS configuration
cors: {
origin: ['http://localhost:3000', 'http://localhost:3001'],
},
};

Generated Feedback Files

The server saves feedback as JSON files that can be processed by Cursor:

.feedback/feedback-2024-01-15T10-30-00Z.json
{
"type": "cursor_local",
"timestamp": "2024-01-15T10:30:00.000Z",
"comment": "This button should be disabled when form is invalid",
"page": {
"url": "http://localhost:3000/checkout",
"title": "Checkout - My App",
"viewportWidth": 1920,
"viewportHeight": 1080
},
"element": {
"selector": "button[data-testid='submit-btn']",
"tagName": "button",
"innerText": "Submit Order",
"dataAttributes": {
"testid": "submit-btn"
}
},
"prompt": "Fix the following issue..."
}

Cursor Rules Integration

Add a Cursor rule to help the AI understand feedback files:

.cursor/rules/feedback.mdc
---
description: Handle anyclick feedback files
globs:
- .feedback/*.json
---
# Feedback File Processing
When processing anyclick feedback files:
1. Read the feedback JSON to understand the issue
2. Use the `selector` to locate the relevant component
3. Consider the `comment` as the primary issue description
4. Reference the `page.url` for context about where the issue occurs
5. Look at `element.innerText` and `element.dataAttributes` for identification
Always:
- Keep changes minimal and focused on the reported issue
- Preserve existing functionality
- Add appropriate error handling if relevant
- Update tests if the component has them

Tips for Best Results

  • • Add .feedback/ to your .gitignore
  • • Use descriptive comments when submitting feedback
  • • Add data-testid attributes for reliable element identification
  • • Configure Cursor rules for your project's conventions
  • • Run the feedback server in a separate terminal for better visibility

Security Reminder

The local server is designed for development only. Never expose it to the internet. The server only accepts connections from localhost by default.

Explore More

Check out the documentation for advanced configuration options and integrations.