ghostfill 0.1.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 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/detector.ts","../src/ai.ts","../src/faker.ts","../src/filler.ts","../src/selector.ts","../src/overlay.ts","../src/index.ts"],"sourcesContent":["/** Configuration options for GhostFill */\nexport interface GhostFillOptions {\n /** API key (optional — can be set via settings UI) */\n apiKey?: string;\n /** Keyboard shortcut to toggle GhostFill (default: \"Alt+G\") */\n shortcut?: string;\n /** Custom system prompt to prepend */\n systemPrompt?: string;\n}\n\nexport type Provider = \"openai\" | \"xai\" | \"moonshot\";\n\nexport const PROVIDERS: Record<Provider, { label: string; model: string; baseURL: string; helpText: string }> = {\n openai: { label: \"OpenAI\", model: \"gpt-4o-mini\", baseURL: \"https://api.openai.com/v1\", helpText: \"Uses gpt-4o-mini — fast & cheap\" },\n xai: { label: \"xAI\", model: \"grok-4-fast\", baseURL: \"https://api.x.ai/v1\", helpText: \"Uses Grok 4 Fast\" },\n moonshot: { label: \"Moonshot\", model: \"kimi-k2\", baseURL: \"https://api.moonshot.ai/v1\", helpText: \"Uses Kimi K2 — fast & cheap\" },\n};\n\n/** A saved prompt preset */\nexport interface Preset {\n id: string;\n name: string;\n prompt: string;\n}\n\n/** Persisted settings (localStorage) */\nexport interface GhostFillSettings {\n apiKey: string;\n provider: Provider;\n highlightColor: string;\n theme: \"dark\" | \"light\";\n useAI: boolean;\n presets: Preset[];\n activePresetId: string | null;\n}\n\n/** A detected form field */\nexport interface DetectedField {\n /** The DOM element */\n element: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n /** Field type: text, email, number, select, textarea, checkbox, radio, date, etc. */\n type: string;\n /** Field name attribute */\n name: string;\n /** Field label (from <label>, aria-label, or placeholder) */\n label: string;\n /** For <select>, the available options */\n options?: string[];\n /** Whether the field is required */\n required: boolean;\n /** Current value */\n currentValue: string;\n /** Min/max for number/date fields */\n min?: string;\n max?: string;\n /** Pattern attribute */\n pattern?: string;\n}\n\n/** Field data returned by the AI */\nexport interface FieldFillData {\n /** Index matching the DetectedField array */\n index: number;\n /** Value to fill */\n value: string;\n /** For checkboxes: whether to check */\n checked?: boolean;\n}\n\n/** Internal state */\nexport interface GhostFillState {\n active: boolean;\n selecting: boolean;\n selectedBlock: HTMLElement | null;\n fields: DetectedField[];\n overlay: HTMLElement | null;\n shadowRoot: ShadowRoot | null;\n}\n","import type { DetectedField } from \"./types\";\n\nconst INPUT_SELECTORS = [\n \"input:not([type=hidden]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image])\",\n \"textarea\",\n \"select\",\n // Custom dropdown triggers (Headless UI Listbox, Radix, etc.)\n \"button[role=combobox]\",\n \"[role=combobox]:not(input)\",\n \"button[aria-haspopup=listbox]\",\n].join(\", \");\n\n/** Find the label text for a form field */\nfunction findLabel(el: HTMLElement): string {\n // 1. Explicit <label for=\"id\">\n if (el.id) {\n const label = document.querySelector<HTMLLabelElement>(\n `label[for=\"${CSS.escape(el.id)}\"]`\n );\n if (label?.textContent?.trim()) return label.textContent.trim();\n }\n\n // 2. Wrapping <label>\n const parentLabel = el.closest(\"label\");\n if (parentLabel) {\n // Get text content excluding the input itself\n const clone = parentLabel.cloneNode(true) as HTMLElement;\n clone.querySelectorAll(\"input, textarea, select\").forEach((c) => c.remove());\n const text = clone.textContent?.trim();\n if (text) return text;\n }\n\n // 3. aria-label\n const ariaLabel = el.getAttribute(\"aria-label\");\n if (ariaLabel?.trim()) return ariaLabel.trim();\n\n // 4. aria-labelledby\n const labelledBy = el.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const parts = labelledBy\n .split(/\\s+/)\n .map((id) => document.getElementById(id)?.textContent?.trim())\n .filter(Boolean);\n if (parts.length) return parts.join(\" \");\n }\n\n // 5. placeholder\n if (\"placeholder\" in el) {\n const ph = (el as HTMLInputElement).placeholder;\n if (ph?.trim()) return ph.trim();\n }\n\n // 6. title\n const title = el.getAttribute(\"title\");\n if (title?.trim()) return title.trim();\n\n // 7. Preceding sibling text (common pattern: <span>Label</span><input>)\n const prev = el.previousElementSibling;\n if (prev && ![\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(prev.tagName)) {\n const prevText = prev.textContent?.trim();\n if (prevText && prevText.length < 60) return prevText;\n }\n\n // 8. Parent's first text node or heading\n const parent = el.parentElement;\n if (parent) {\n // Look for a heading or label-like element before this input in the parent\n for (const child of Array.from(parent.children)) {\n if (child === el) break;\n if ([\"LABEL\", \"SPAN\", \"P\", \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"LEGEND\", \"DIV\"].includes(child.tagName)) {\n const text = child.textContent?.trim();\n if (text && text.length < 60 && !child.querySelector(\"input, textarea, select\")) {\n return text;\n }\n }\n }\n }\n\n // 9. id attribute humanized\n if (el.id) return el.id.replace(/[_\\-]/g, \" \").replace(/([a-z])([A-Z])/g, \"$1 $2\").trim();\n\n // 10. name attribute as fallback\n const name = el.getAttribute(\"name\");\n if (name) return name.replace(/[_\\-[\\]]/g, \" \").replace(/([a-z])([A-Z])/g, \"$1 $2\").trim();\n\n return \"unknown\";\n}\n\n/** Detect all fillable fields within a container element */\nexport function detectFields(container: HTMLElement): DetectedField[] {\n const elements = container.querySelectorAll<\n HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement\n >(INPUT_SELECTORS);\n\n const fields: DetectedField[] = [];\n\n elements.forEach((el) => {\n // Skip disabled fields\n if ((el as HTMLInputElement).disabled) return;\n if ((el as HTMLInputElement).readOnly) return;\n // Skip hidden elements\n if (el.offsetParent === null && (el as HTMLInputElement).type !== \"hidden\") return;\n\n // Custom combobox / listbox (Headless UI, Radix, etc.)\n const isCustomDropdown =\n (el.getAttribute(\"role\") === \"combobox\" && !(el instanceof HTMLInputElement)) ||\n el.getAttribute(\"aria-haspopup\") === \"listbox\";\n if (isCustomDropdown) {\n // Find listbox options: aria-controls, sibling [role=listbox], or Headless UI pattern\n const listboxId = el.getAttribute(\"aria-controls\");\n let listbox: Element | null = listboxId ? document.getElementById(listboxId) : null;\n if (!listbox) {\n // Headless UI puts the listbox as a sibling inside the same relative container\n listbox = el.parentElement?.querySelector(\"[role=listbox]\") || null;\n }\n\n const options: string[] = [];\n if (listbox) {\n listbox.querySelectorAll(\"[role=option]\").forEach((opt) => {\n const text = opt.textContent?.trim();\n if (text) options.push(text);\n });\n }\n\n // Get current display value from button text\n const buttonText = el.textContent?.trim() || \"\";\n // Check if it looks like a placeholder\n const looksLikePlaceholder = buttonText.toLowerCase().startsWith(\"select\") || buttonText === \"\";\n\n const field: DetectedField = {\n element: el as any,\n type: \"select\",\n name: el.id || el.getAttribute(\"name\") || \"\",\n label: findLabel(el),\n required: el.getAttribute(\"aria-required\") === \"true\",\n currentValue: looksLikePlaceholder ? \"\" : buttonText,\n options: options.length > 0 ? options : undefined,\n };\n fields.push(field);\n return;\n }\n\n const field: DetectedField = {\n element: el as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n type: el instanceof HTMLSelectElement ? \"select\" : (el as HTMLInputElement).type || \"text\",\n name: (el as HTMLInputElement).name || el.id || \"\",\n label: findLabel(el),\n required: (el as HTMLInputElement).required || el.getAttribute(\"aria-required\") === \"true\",\n currentValue: (el as HTMLInputElement).value,\n };\n\n // Collect select options\n if (el instanceof HTMLSelectElement) {\n field.options = Array.from(el.options)\n .filter((opt) => opt.value && !opt.disabled)\n .map((opt) => opt.textContent?.trim() || opt.value);\n }\n\n // Collect constraints\n if (\"min\" in el && (el as HTMLInputElement).min) {\n field.min = (el as HTMLInputElement).min;\n }\n if (\"max\" in el && (el as HTMLInputElement).max) {\n field.max = (el as HTMLInputElement).max;\n }\n if (\"pattern\" in el && (el as HTMLInputElement).pattern) {\n field.pattern = (el as HTMLInputElement).pattern;\n }\n\n fields.push(field);\n });\n\n return fields;\n}\n\n/** Build a description of fields for the AI prompt */\nexport function describeFields(fields: DetectedField[]): string {\n return fields\n .map((f, i) => {\n let desc = `[${i}] \"${f.label}\" (type: ${f.type}`;\n if (f.required) desc += \", required\";\n if (f.options?.length) desc += `, options: [${f.options.join(\", \")}]`;\n if (f.min) desc += `, min: ${f.min}`;\n if (f.max) desc += `, max: ${f.max}`;\n if (f.pattern) desc += `, pattern: ${f.pattern}`;\n if (f.currentValue) desc += `, current: \"${f.currentValue}\"`;\n desc += \")\";\n return desc;\n })\n .join(\"\\n\");\n}\n\n/** Extract visible text context from the selected block (headings, labels, paragraphs) */\nexport function extractBlockContext(container: HTMLElement): string {\n const parts: string[] = [];\n\n // Page title\n const pageTitle = document.title;\n if (pageTitle) parts.push(`Page: ${pageTitle}`);\n\n // Headings in/above the block\n const headings = container.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n headings.forEach((h) => {\n const text = h.textContent?.trim();\n if (text) parts.push(`Heading: ${text}`);\n });\n\n // If no headings in container, look for the nearest heading above\n if (headings.length === 0) {\n let prev: Element | null = container;\n while (prev) {\n prev = prev.previousElementSibling;\n if (prev && /^H[1-6]$/.test(prev.tagName)) {\n const text = prev.textContent?.trim();\n if (text) parts.push(`Section: ${text}`);\n break;\n }\n }\n // Also check parent headings\n const parent = container.closest(\"section, article, form, div[class]\");\n if (parent) {\n const parentH = parent.querySelector(\"h1, h2, h3, h4, h5, h6\");\n if (parentH?.textContent?.trim()) {\n parts.push(`Section: ${parentH.textContent.trim()}`);\n }\n }\n }\n\n // Labels and visible text (capped)\n const labels = container.querySelectorAll(\"label, legend, .label, p, span\");\n const seen = new Set<string>();\n labels.forEach((el) => {\n const text = el.textContent?.trim();\n if (text && text.length > 2 && text.length < 100 && !seen.has(text)) {\n seen.add(text);\n parts.push(text);\n }\n });\n\n return parts.slice(0, 20).join(\"\\n\");\n}\n","import type { DetectedField, FieldFillData, GhostFillSettings, Provider, GhostFillOptions } from \"./types\";\nimport { PROVIDERS } from \"./types\";\nimport { describeFields } from \"./detector\";\n\nconst SYSTEM_PROMPT = `You are a form-filling assistant. Given a list of form fields, page context, and an optional user prompt, generate realistic fake data to fill ALL fields.\n\nRules:\n- Return ONLY a JSON object with a \"fields\" array of objects, each with \"index\" and \"value\" keys\n- You MUST fill EVERY field — do not skip any\n- Match the field type (email → valid email, phone → valid phone with country code, date → YYYY-MM-DD, datetime-local → YYYY-MM-DDTHH:MM, etc.)\n- For select/dropdown fields: you MUST pick one of the listed options EXACTLY as written\n- For checkboxes: add a \"checked\" boolean (true or false)\n- For radio buttons: only fill one per group, use the option value\n- Respect min/max constraints and patterns\n- Generate contextually coherent data (same person's name, matching city/state/zip, etc.)\n- Use the page context to infer what kind of data makes sense (e.g. a \"Create Project\" form → project-related data)\n- If no user prompt is given, infer appropriate data from the field labels and page context\n- Do NOT wrap the JSON in markdown code blocks — return raw JSON only`;\n\n/** Call LLM API to generate fill data */\nexport async function generateFillData(\n fields: DetectedField[],\n userPrompt: string,\n settings: GhostFillSettings,\n systemPrompt?: string,\n blockContext?: string\n): Promise<FieldFillData[]> {\n const fieldDescription = describeFields(fields);\n const provider = PROVIDERS[settings.provider] || PROVIDERS.openai;\n\n let userContent = `Form fields:\\n${fieldDescription}`;\n\n if (blockContext) {\n userContent += `\\n\\nPage context:\\n${blockContext}`;\n }\n\n if (userPrompt) {\n userContent += `\\n\\nUser instructions: ${userPrompt}`;\n } else {\n userContent += `\\n\\nNo specific instructions — generate realistic, contextually appropriate data for all fields.`;\n }\n\n const messages = [\n {\n role: \"system\" as const,\n content: systemPrompt\n ? `${systemPrompt}\\n\\n${SYSTEM_PROMPT}`\n : SYSTEM_PROMPT,\n },\n {\n role: \"user\" as const,\n content: userContent,\n },\n ];\n\n const body: Record<string, unknown> = {\n model: provider.model,\n messages,\n temperature: 0.7,\n };\n\n // json_object response format not supported by all providers\n if (settings.provider === \"openai\") {\n body.response_format = { type: \"json_object\" };\n }\n\n const response = await fetch(`${provider.baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${settings.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`API error (${response.status}): ${error}`);\n }\n\n const data = await response.json();\n const content = data.choices?.[0]?.message?.content;\n\n if (!content) {\n throw new Error(\"No content in API response\");\n }\n\n // Extract JSON from possible markdown code blocks\n const jsonMatch = content.match(/```(?:json)?\\s*([\\s\\S]*?)```/) || [null, content];\n const jsonStr = jsonMatch[1]!.trim();\n const parsed = JSON.parse(jsonStr);\n\n const arr = Array.isArray(parsed)\n ? parsed\n : parsed.fields || parsed.data || parsed.items || [];\n\n if (!Array.isArray(arr)) {\n throw new Error(\"AI response is not an array of field fills\");\n }\n\n return arr as FieldFillData[];\n}\n","import type { DetectedField, FieldFillData } from \"./types\";\n\nconst FIRST_NAMES = [\"James\", \"Sarah\", \"Michael\", \"Emma\", \"Robert\", \"Olivia\", \"David\", \"Sophia\", \"Daniel\", \"Isabella\", \"Ahmed\", \"Fatima\", \"Carlos\", \"Yuki\", \"Priya\"];\nconst LAST_NAMES = [\"Smith\", \"Johnson\", \"Williams\", \"Brown\", \"Jones\", \"Garcia\", \"Miller\", \"Davis\", \"Wilson\", \"Anderson\", \"Taylor\", \"Thomas\", \"Moore\", \"Martin\", \"Lee\"];\nconst COMPANIES = [\"Acme Corp\", \"TechVault Inc\", \"Nexus Solutions\", \"Blue Ridge Systems\", \"Summit Digital\", \"CloudPeak Ltd\", \"DataForge Labs\", \"Apex Industries\"];\nconst CITIES = [\"New York\", \"San Francisco\", \"Chicago\", \"Austin\", \"Seattle\", \"Boston\", \"Denver\", \"Portland\"];\nconst STREETS = [\"123 Oak Street\", \"456 Maple Ave\", \"789 Pine Road\", \"321 Elm Blvd\", \"654 Cedar Lane\", \"987 Birch Drive\"];\nconst DOMAINS = [\"gmail.com\", \"outlook.com\", \"yahoo.com\", \"company.com\", \"example.com\"];\nconst LOREM = [\"Project planning and requirements gathering\", \"Implementation of core features\", \"Stakeholder review session\", \"Technical design workshop\", \"Sprint retrospective and planning\", \"Customer onboarding process\", \"Data migration strategy\", \"Integration testing phase\"];\nconst TITLES = [\"Discovery Workshop\", \"Requirements Review\", \"Design Sprint\", \"Technical Assessment\", \"Strategy Session\", \"Kick-off Meeting\", \"UAT Planning\", \"Go-Live Preparation\"];\n\nfunction pick<T>(arr: T[]): T {\n return arr[Math.floor(Math.random() * arr.length)]!;\n}\n\nfunction randInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\nfunction randDate(futureMonths = 6): string {\n const now = new Date();\n const future = new Date(now.getTime() + randInt(1, futureMonths * 30) * 86400000);\n return future.toISOString().slice(0, 10);\n}\n\nfunction randDateTime(futureMonths = 6): string {\n const now = new Date();\n const future = new Date(now.getTime() + randInt(1, futureMonths * 30) * 86400000);\n future.setHours(randInt(8, 18), randInt(0, 3) * 15, 0);\n return future.toISOString().slice(0, 16);\n}\n\nfunction generateForField(field: DetectedField, context: { firstName: string; lastName: string; email: string; company: string }): string {\n const label = field.label.toLowerCase();\n\n // Select — pick a random option, or signal \"pick first\" if no options known\n if (field.type === \"select\") {\n if (field.options?.length) return pick(field.options);\n return \"__FIRST__\";\n }\n\n // Dates\n if (field.type === \"date\") return randDate();\n if (field.type === \"datetime-local\") return randDateTime();\n if (field.type === \"time\") return `${String(randInt(8, 18)).padStart(2, \"0\")}:${String(randInt(0, 3) * 15).padStart(2, \"0\")}`;\n if (field.type === \"month\") {\n const d = new Date();\n d.setMonth(d.getMonth() + randInt(0, 6));\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}`;\n }\n\n // Email\n if (field.type === \"email\" || label.includes(\"email\")) {\n return context.email;\n }\n\n // Phone\n if (field.type === \"tel\" || label.includes(\"phone\") || label.includes(\"mobile\")) {\n return `+1${randInt(200, 999)}${randInt(100, 999)}${randInt(1000, 9999)}`;\n }\n\n // URL\n if (field.type === \"url\" || label.includes(\"website\") || label.includes(\"url\")) {\n return `https://www.${context.company.toLowerCase().replace(/\\s+/g, \"\")}.com`;\n }\n\n // Number\n if (field.type === \"number\" || field.type === \"range\") {\n const min = field.min ? parseInt(field.min) : 1;\n const max = field.max ? parseInt(field.max) : 100;\n return String(randInt(min, max));\n }\n\n // Name fields\n if (label.includes(\"first name\") || label.includes(\"firstname\")) return context.firstName;\n if (label.includes(\"last name\") || label.includes(\"lastname\") || label.includes(\"surname\")) return context.lastName;\n if (label.includes(\"full name\") || label === \"name\") return `${context.firstName} ${context.lastName}`;\n\n // Company\n if (label.includes(\"company\") || label.includes(\"organization\") || label.includes(\"business\")) return context.company;\n\n // Address\n if (label.includes(\"address\") || label.includes(\"street\")) return pick(STREETS);\n if (label.includes(\"city\")) return pick(CITIES);\n if (label.includes(\"state\")) return pick([\"California\", \"New York\", \"Texas\", \"Florida\", \"Washington\"]);\n if (label.includes(\"zip\") || label.includes(\"postal\")) return String(randInt(10000, 99999));\n if (label.includes(\"country\")) return \"United States\";\n\n // Title-like\n if (label.includes(\"title\") || label.includes(\"subject\") || label.includes(\"name\")) {\n return pick(TITLES);\n }\n\n // Job\n if (label.includes(\"job\") || label.includes(\"role\") || label.includes(\"position\")) {\n return pick([\"Software Engineer\", \"Product Manager\", \"Business Analyst\", \"Solution Architect\", \"Project Manager\"]);\n }\n\n // Location / Channel\n if (label.includes(\"location\") || label.includes(\"channel\") || label.includes(\"venue\")) {\n return pick([\"Microsoft Teams\", \"Zoom\", \"Google Meet\", \"On-site\", \"Conference Room A\"]);\n }\n\n // Description / Notes / Objective / Goal\n if (field.type === \"textarea\" || label.includes(\"description\") || label.includes(\"note\") || label.includes(\"comment\") || label.includes(\"objective\") || label.includes(\"goal\")) {\n return pick(LOREM);\n }\n\n // Password\n if (field.type === \"password\") return \"P@ssw0rd123!\";\n\n // Generic text fallback\n return pick([context.firstName, context.company, pick(TITLES)]);\n}\n\n/** Generate fake data for all fields without calling an API */\nexport function generateFakeData(fields: DetectedField[]): FieldFillData[] {\n // Create a coherent identity for this fill\n const firstName = pick(FIRST_NAMES);\n const lastName = pick(LAST_NAMES);\n const company = pick(COMPANIES);\n const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@${pick(DOMAINS)}`;\n const context = { firstName, lastName, email, company };\n\n return fields.map((field, index) => {\n if (field.type === \"checkbox\") {\n return { index, value: \"true\", checked: Math.random() > 0.5 };\n }\n\n const value = generateForField(field, context);\n return { index, value };\n });\n}\n","import type { DetectedField, FieldFillData } from \"./types\";\n\n/**\n * Set value on an input/textarea/select and dispatch events that React,\n * Vue, and Angular controlled components will pick up.\n */\nfunction setNativeValue(el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, value: string) {\n // For React: we must use the native setter so React's internal tracking\n // sees it as a new value and fires onChange handlers.\n const proto =\n el instanceof HTMLSelectElement\n ? HTMLSelectElement.prototype\n : el instanceof HTMLTextAreaElement\n ? HTMLTextAreaElement.prototype\n : HTMLInputElement.prototype;\n\n const nativeSetter = Object.getOwnPropertyDescriptor(proto, \"value\")?.set;\n\n if (nativeSetter) {\n nativeSetter.call(el, value);\n } else {\n el.value = value;\n }\n\n // Dispatch events in the order React/browsers expect\n el.dispatchEvent(new Event(\"input\", { bubbles: true }));\n el.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\n/** Focus then blur to trigger validation */\nfunction focusBlur(el: HTMLElement) {\n el.focus();\n el.dispatchEvent(new Event(\"blur\", { bubbles: true }));\n}\n\n/** Click a custom dropdown button, wait for listbox, click the matching option */\nasync function fillCustomSelect(button: HTMLElement, value: string): Promise<void> {\n // Click the button to open the dropdown\n button.click();\n\n // Wait for the listbox to appear (Headless UI renders it after a tick)\n await new Promise((r) => setTimeout(r, 200));\n\n // Find the listbox — could be a sibling, or anywhere in the document\n const listboxId = button.getAttribute(\"aria-controls\");\n let listbox: Element | null = listboxId ? document.getElementById(listboxId) : null;\n if (!listbox) {\n listbox = button.parentElement?.querySelector(\"[role=listbox]\") || document.querySelector(\"[role=listbox]\");\n }\n\n if (listbox) {\n const options = listbox.querySelectorAll(\"[role=option]\");\n\n // Try exact match\n for (const opt of options) {\n const text = opt.textContent?.trim();\n if (text === value || text?.toLowerCase() === value.toLowerCase()) {\n (opt as HTMLElement).click();\n await new Promise((r) => setTimeout(r, 50));\n return;\n }\n }\n\n // Try partial match\n for (const opt of options) {\n const text = opt.textContent?.trim()?.toLowerCase() || \"\";\n if (text.includes(value.toLowerCase()) || value.toLowerCase().includes(text)) {\n (opt as HTMLElement).click();\n await new Promise((r) => setTimeout(r, 50));\n return;\n }\n }\n\n // No match — pick the first real option (skip placeholders)\n for (const opt of options) {\n const text = (opt.textContent?.trim() || \"\").toLowerCase();\n const isPlaceholder = text.startsWith(\"select\") || text === \"\" || text === \"---\" || text === \"choose\" || text.startsWith(\"choose\");\n if (!isPlaceholder) {\n (opt as HTMLElement).click();\n await new Promise((r) => setTimeout(r, 50));\n return;\n }\n }\n // If all look like placeholders, just pick the last one\n if (options.length > 1) {\n (options[options.length - 1] as HTMLElement).click();\n await new Promise((r) => setTimeout(r, 50));\n return;\n }\n }\n\n // Close dropdown if nothing worked\n button.click();\n}\n\n/** Fill detected fields with AI-generated data */\nexport async function fillFields(\n fields: DetectedField[],\n fillData: FieldFillData[]\n): Promise<{ filled: number; errors: string[] }> {\n let filled = 0;\n const errors: string[] = [];\n\n const filledRadioGroups = new Set<string>();\n\n for (const item of fillData) {\n const field = fields[item.index];\n if (!field) {\n errors.push(`Field index ${item.index} out of range`);\n continue;\n }\n\n const el = field.element;\n\n try {\n if (field.type === \"checkbox\") {\n const checkbox = el as HTMLInputElement;\n const shouldCheck = item.checked ?? item.value === \"true\";\n if (checkbox.checked !== shouldCheck) {\n // For React checkboxes, we need to use Object.getOwnPropertyDescriptor\n const nativeCheckedSetter = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype, \"checked\"\n )?.set;\n if (nativeCheckedSetter) {\n nativeCheckedSetter.call(checkbox, shouldCheck);\n } else {\n checkbox.checked = shouldCheck;\n }\n checkbox.dispatchEvent(new Event(\"click\", { bubbles: true }));\n checkbox.dispatchEvent(new Event(\"input\", { bubbles: true }));\n checkbox.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n filled++;\n } else if (field.type === \"radio\") {\n const radio = el as HTMLInputElement;\n if (radio.name && filledRadioGroups.has(radio.name)) continue;\n\n if (radio.name) {\n const group = document.querySelectorAll<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${CSS.escape(radio.name)}\"]`\n );\n for (const r of group) {\n if (r.value === item.value || findLabel(r) === item.value) {\n const nativeCheckedSetter = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype, \"checked\"\n )?.set;\n if (nativeCheckedSetter) {\n nativeCheckedSetter.call(r, true);\n } else {\n r.checked = true;\n }\n r.dispatchEvent(new Event(\"click\", { bubbles: true }));\n r.dispatchEvent(new Event(\"input\", { bubbles: true }));\n r.dispatchEvent(new Event(\"change\", { bubbles: true }));\n break;\n }\n }\n filledRadioGroups.add(radio.name);\n } else {\n radio.checked = true;\n radio.dispatchEvent(new Event(\"click\", { bubbles: true }));\n radio.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n filled++;\n } else if (field.type === \"select\") {\n if (el instanceof HTMLSelectElement) {\n // Native <select>\n const pickFirst = () => {\n const real = Array.from(el.options).find((o) => {\n if (!o.value || o.disabled) return false;\n const t = (o.textContent?.trim() || \"\").toLowerCase();\n return !t.startsWith(\"select\") && t !== \"\" && !t.startsWith(\"choose\") && t !== \"---\";\n });\n if (real) setNativeValue(el, real.value);\n };\n if (item.value === \"__FIRST__\") {\n pickFirst();\n } else {\n const option = Array.from(el.options).find(\n (opt) =>\n opt.textContent?.trim() === item.value || opt.value === item.value\n );\n if (option) {\n setNativeValue(el, option.value);\n } else {\n pickFirst();\n }\n }\n focusBlur(el);\n } else {\n // Custom dropdown (Headless UI Listbox, Radix, etc.)\n await fillCustomSelect(el, item.value);\n }\n filled++;\n } else {\n // text, email, number, date, datetime-local, tel, url, textarea\n setNativeValue(el, item.value);\n focusBlur(el);\n filled++;\n }\n\n // Brief subtle flash to show which fields were filled\n const origBg = el.style.backgroundColor;\n el.style.transition = \"background-color 0.3s\";\n el.style.backgroundColor = \"rgba(99, 102, 241, 0.12)\";\n setTimeout(() => {\n el.style.backgroundColor = origBg;\n }, 800);\n } catch (err) {\n errors.push(\n `Failed to fill \"${field.label}\": ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n return { filled, errors };\n}\n\nfunction findLabel(el: HTMLElement): string {\n if (el.id) {\n const label = document.querySelector<HTMLLabelElement>(\n `label[for=\"${CSS.escape(el.id)}\"]`\n );\n if (label?.textContent?.trim()) return label.textContent.trim();\n }\n const parent = el.closest(\"label\");\n if (parent) {\n const clone = parent.cloneNode(true) as HTMLElement;\n clone.querySelectorAll(\"input\").forEach((c) => c.remove());\n return clone.textContent?.trim() || \"\";\n }\n return \"\";\n}\n","/** Block selection mode — user hovers over elements and clicks to select a container */\n\ntype SelectCallback = (element: HTMLElement) => void;\ntype CancelCallback = () => void;\n\nlet currentHighlight: HTMLElement | null = null;\nlet overlay: HTMLDivElement | null = null;\n\nfunction createOverlay(color: string): HTMLDivElement {\n const div = document.createElement(\"div\");\n div.id = \"ghostfill-selector-overlay\";\n // Convert hex to rgba for background\n const r = parseInt(color.slice(1, 3), 16);\n const g = parseInt(color.slice(3, 5), 16);\n const b = parseInt(color.slice(5, 7), 16);\n Object.assign(div.style, {\n position: \"fixed\",\n pointerEvents: \"none\",\n border: `2px dashed ${color}`,\n borderRadius: \"4px\",\n backgroundColor: `rgba(${r}, ${g}, ${b}, 0.08)`,\n zIndex: \"2147483645\",\n transition: \"all 0.15s ease\",\n });\n document.body.appendChild(div);\n return div;\n}\n\nfunction positionOverlay(el: HTMLElement, color: string) {\n if (!overlay) overlay = createOverlay(color);\n const rect = el.getBoundingClientRect();\n Object.assign(overlay.style, {\n top: `${rect.top}px`,\n left: `${rect.left}px`,\n width: `${rect.width}px`,\n height: `${rect.height}px`,\n display: \"block\",\n });\n}\n\nfunction hideOverlay() {\n if (overlay) overlay.style.display = \"none\";\n}\n\nfunction removeOverlay() {\n overlay?.remove();\n overlay = null;\n}\n\n/** Find the best container element (prefer forms, fieldsets, or sizeable containers) */\nfunction findBestContainer(target: HTMLElement): HTMLElement {\n if (target.tagName === \"FORM\" || target.tagName === \"FIELDSET\") return target;\n\n let el: HTMLElement | null = target;\n while (el) {\n if (el.tagName === \"FORM\" || el.tagName === \"FIELDSET\") return el;\n\n const inputs = el.querySelectorAll(\n \"input:not([type=hidden]):not([type=submit]):not([type=button]), textarea, select\"\n );\n if (inputs.length >= 2) return el;\n\n el = el.parentElement;\n }\n\n return target;\n}\n\n/** Start block selection mode */\nexport function startSelection(\n onSelect: SelectCallback,\n onCancel: CancelCallback,\n ghostfillRoot?: HTMLElement,\n highlightColor = \"#6366f1\"\n): () => void {\n document.body.style.cursor = \"crosshair\";\n\n function handleMouseMove(e: MouseEvent) {\n const target = e.target as HTMLElement;\n if (ghostfillRoot?.contains(target)) return;\n if (target.id === \"ghostfill-selector-overlay\") return;\n\n const container = findBestContainer(target);\n if (container !== currentHighlight) {\n currentHighlight = container;\n positionOverlay(container, highlightColor);\n }\n }\n\n function handleClick(e: MouseEvent) {\n const target = e.target as HTMLElement;\n if (ghostfillRoot?.contains(target)) return;\n\n e.preventDefault();\n e.stopPropagation();\n cleanup();\n\n const container = findBestContainer(target);\n onSelect(container);\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n cleanup();\n onCancel();\n }\n }\n\n function cleanup() {\n document.body.style.cursor = \"\";\n document.removeEventListener(\"mousemove\", handleMouseMove, true);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\"keydown\", handleKeyDown, true);\n hideOverlay();\n removeOverlay();\n currentHighlight = null;\n }\n\n document.addEventListener(\"mousemove\", handleMouseMove, true);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"keydown\", handleKeyDown, true);\n\n return cleanup;\n}\n","import type { GhostFillOptions, GhostFillState, GhostFillSettings, DetectedField, Provider, Preset } from \"./types\";\nimport { PROVIDERS } from \"./types\";\nimport { detectFields, extractBlockContext } from \"./detector\";\nimport { generateFillData } from \"./ai\";\nimport { generateFakeData } from \"./faker\";\nimport { fillFields } from \"./filler\";\nimport { startSelection } from \"./selector\";\n\nconst STORAGE_KEY = \"ghostfill_settings\";\nconst POS_KEY = \"ghostfill_pos\";\nconst FAB_POS_KEY = \"ghostfill_fab_pos\";\n\nfunction loadSettings(): GhostFillSettings {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (raw) return JSON.parse(raw);\n } catch {}\n return { apiKey: \"\", provider: \"openai\" as const, highlightColor: \"#6366f1\", theme: \"dark\" as const, useAI: false, presets: [], activePresetId: null };\n}\n\nfunction saveSettings(s: GhostFillSettings) {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(s));\n}\n\nfunction loadPosition(): { x: number; y: number } | null {\n try {\n const raw = localStorage.getItem(POS_KEY);\n if (raw) return JSON.parse(raw);\n } catch {}\n return null;\n}\n\nfunction savePosition(x: number, y: number) {\n localStorage.setItem(POS_KEY, JSON.stringify({ x, y }));\n}\n\n/** Extract a clean error message from OpenAI API errors */\nfunction cleanError(err: unknown): string {\n const raw = err instanceof Error ? err.message : String(err);\n // Try to extract the \"message\" field from JSON error bodies\n const match = raw.match(/\"message\"\\s*:\\s*\"([^\"]+)\"/);\n if (match) return match[1];\n // Strip \"OpenAI API error (NNN): \" prefix noise\n const stripped = raw.replace(/^OpenAI API error \\(\\d+\\):\\s*/, \"\");\n // If it's JSON, try to parse\n try {\n const parsed = JSON.parse(stripped);\n if (parsed?.error?.message) return parsed.error.message;\n } catch {}\n return stripped.length > 80 ? stripped.slice(0, 80) + \"...\" : stripped;\n}\n\n// ─── Icons ──────────────────────────────────────────────────────────────────\n\nconst ICONS = {\n select: `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 2v4M12 18v4M2 12h4M18 12h4\"/>\n <circle cx=\"12\" cy=\"12\" r=\"4\"/>\n </svg>`,\n sparkles: `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"/>\n <path d=\"M20 3v4M22 5h-4\"/>\n </svg>`,\n settings: `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"/>\n <path d=\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z\"/>\n </svg>`,\n close: `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>`,\n ghost: `<svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 2C7.58 2 4 5.58 4 10v10l2-2 2 2 2-2 2 2 2-2 2 2 2-2 2 2V10c0-4.42-3.58-8-8-8z\"/>\n <circle cx=\"9\" cy=\"10\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"15\" cy=\"10\" r=\"1.5\" fill=\"currentColor\"/>\n </svg>`,\n spinner: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\">\n <path d=\"M12 2a10 10 0 0 1 10 10\"/>\n </svg>`,\n // Field type icons (14x14)\n ftText: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M4 7V4h16v3M9 20h6M12 4v16\"/></svg>`,\n ftEmail: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z\"/><polyline points=\"22,6 12,13 2,6\"/></svg>`,\n ftPhone: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z\"/></svg>`,\n ftNumber: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M4 9h16M4 15h16M10 3L8 21M16 3l-2 18\"/></svg>`,\n ftDate: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"/><path d=\"M16 2v4M8 2v4M3 10h18\"/></svg>`,\n ftSelect: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>`,\n ftTextarea: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M17 10H3M21 6H3M21 14H3M17 18H3\"/></svg>`,\n ftCheckbox: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><path d=\"M9 12l2 2 4-4\"/></svg>`,\n ftRadio: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"4\" fill=\"currentColor\"/></svg>`,\n ftUrl: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71\"/></svg>`,\n ftPassword: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\"/><path d=\"M7 11V7a5 5 0 0110 0v4\"/></svg>`,\n ftFile: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48\"/></svg>`,\n sun: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"5\"/><path d=\"M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42\"/></svg>`,\n moon: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z\"/></svg>`,\n};\n\n// ─── Styles ─────────────────────────────────────────────────────────────────\n\nconst CSS = `\n :host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", sans-serif;\n font-size: 13px;\n color: #e4e4e7;\n line-height: 1.4;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n .gf-bar {\n position: fixed;\n z-index: 2147483646;\n display: flex;\n align-items: center;\n gap: 2px;\n background: #18181b;\n border-radius: 14px;\n padding: 5px 6px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.35), 0 0 0 1px rgba(255,255,255,0.06);\n user-select: none;\n cursor: grab;\n pointer-events: auto;\n }\n .gf-bar.dragging { cursor: grabbing; opacity: 0.9; }\n\n .gf-bar-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 10px;\n background: transparent;\n color: #a1a1aa;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, color 0.15s;\n }\n .gf-bar-btn:hover { background: #27272a; color: #fafafa; }\n .gf-bar-btn.active { background: #3f3f46; color: #fafafa; }\n .gf-bar-btn:disabled { opacity: 0.35; cursor: not-allowed; }\n .gf-bar-btn:disabled:hover { background: transparent; color: #a1a1aa; }\n\n .gf-divider {\n width: 1px; height: 20px; background: #3f3f46; margin: 0 4px; flex-shrink: 0;\n }\n\n\n .gf-fab {\n position: fixed; z-index: 2147483646;\n width: 44px; height: 44px; border-radius: 50%; border: none;\n background: #18181b; color: #a1a1aa; cursor: grab;\n display: none; align-items: center; justify-content: center;\n pointer-events: auto;\n box-shadow: 0 4px 16px rgba(0,0,0,0.35), 0 0 0 1px rgba(255,255,255,0.06);\n transition: transform 0.15s, color 0.15s;\n }\n .gf-fab:hover { color: #a78bfa; }\n .gf-fab:hover > svg { animation: gf-float 1.2s ease-in-out infinite; }\n .gf-fab.visible { display: flex; }\n @keyframes gf-float {\n 0%, 100% { transform: translateY(0) rotate(0deg); }\n 25% { transform: translateY(-2px) rotate(-5deg); }\n 75% { transform: translateY(1px) rotate(5deg); }\n }\n\n .gf-popover {\n position: fixed; z-index: 2147483646;\n background: #1a1a1a; border-radius: 16px; pointer-events: auto;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.08);\n display: none; flex-direction: column; overflow: hidden;\n min-width: 280px;\n }\n .gf-popover.open { display: flex; }\n\n .gf-pop-header {\n display: flex; align-items: center; justify-content: space-between;\n min-height: 24px; padding: 13px 16px 0;\n margin-bottom: 8px; padding-bottom: 9px;\n border-bottom: 1px solid rgba(255,255,255,0.07);\n }\n .gf-pop-header h3 {\n font-size: 13px; font-weight: 600; color: #fff;\n letter-spacing: -0.0094em;\n }\n .gf-pop-header .gf-slash { color: rgba(255,255,255,0.5); }\n .gf-pop-header .gf-header-right {\n display: flex; align-items: center; gap: 6px;\n }\n .gf-pop-header .gf-version {\n font-size: 11px; font-weight: 400; color: rgba(255,255,255,0.4);\n letter-spacing: -0.0094em;\n }\n .gf-theme-btn {\n width: 20px; height: 20px; border: none; border-radius: 4px;\n background: transparent; color: rgba(255,255,255,0.4); cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n transition: color 0.15s;\n }\n .gf-theme-btn:hover { color: rgba(255,255,255,0.7); }\n .gf-theme-btn svg { width: 14px; height: 14px; }\n\n .gf-sep {\n height: 1px; background: rgba(255,255,255,0.07);\n margin: 8px 0 10px;\n }\n\n /* Highlight color picker */\n .gf-colors {\n display: flex; gap: 6px; flex-wrap: wrap;\n }\n .gf-color-dot {\n width: 24px; height: 24px; border-radius: 50%; border: 2px solid transparent;\n cursor: pointer; transition: border-color 0.15s, transform 0.1s;\n }\n .gf-color-dot:hover { transform: scale(1.1); }\n .gf-color-dot.selected { border-color: #fafafa; }\n\n .gf-pop-body {\n padding: 0 16px 16px; display: flex; flex-direction: column; gap: 10px;\n max-height: 400px; overflow-y: auto;\n }\n\n .gf-field { display: flex; flex-direction: column; gap: 4px; }\n .gf-label {\n font-size: 13px; font-weight: 400; color: rgba(255,255,255,0.5);\n letter-spacing: -0.0094em; display: flex; align-items: center; gap: 2px;\n }\n .gf-input {\n width: 100%; padding: 6px 8px; background: rgba(255,255,255,0.06);\n border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; color: #fff;\n font-family: inherit; font-size: 13px; outline: none; transition: border-color 0.15s;\n }\n .gf-input:focus { border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99,102,241,0.15); }\n .gf-input::placeholder { color: rgba(255,255,255,0.25); }\n .gf-input-mono { font-family: \"SF Mono\", \"Fira Code\", monospace; font-size: 12px; }\n\n textarea.gf-input { min-height: 56px; resize: vertical; line-height: 1.5; }\n\n .gf-save-btn, .gf-fill-btn {\n width: 100%; padding: 7px; border: none; border-radius: 8px;\n background: #6366f1; color: white; font-family: inherit;\n font-size: 13px; font-weight: 500; cursor: pointer; transition: background 0.15s;\n display: flex; align-items: center; justify-content: center; gap: 5px;\n }\n .gf-save-btn:hover, .gf-fill-btn:hover { background: #4f46e5; }\n .gf-fill-btn:disabled { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.25); cursor: not-allowed; }\n\n .gf-pop-body::-webkit-scrollbar { width: 6px; }\n .gf-pop-body::-webkit-scrollbar-track { background: transparent; }\n .gf-pop-body::-webkit-scrollbar-thumb { background: #3f3f46; border-radius: 3px; }\n\n .gf-field-count { font-size: 11px; color: #71717a; }\n\n /* ── Field cards grid ── */\n .gf-fields-grid {\n display: flex; flex-wrap: wrap; gap: 6px;\n max-height: 140px; overflow-y: auto; padding: 2px;\n scrollbar-color: #3f3f46 transparent;\n }\n .gf-fields-grid::-webkit-scrollbar { width: 5px; }\n .gf-fields-grid::-webkit-scrollbar-track { background: transparent; }\n .gf-fields-grid::-webkit-scrollbar-thumb { background: #3f3f46; border-radius: 3px; }\n\n .gf-field-card {\n display: flex; align-items: center; gap: 5px;\n padding: 4px 8px; border-radius: 8px;\n background: #27272a; border: 1px solid #3f3f46;\n cursor: default; transition: border-color 0.15s, background 0.15s;\n max-width: 100%;\n }\n .gf-field-card:hover {\n border-color: #6366f1; background: #2e2442;\n }\n .gf-field-card .gf-fc-icon {\n flex-shrink: 0; width: 16px; height: 16px; color: #6366f1;\n display: flex; align-items: center; justify-content: center;\n }\n .gf-field-card .gf-fc-icon svg { width: 14px; height: 14px; }\n .gf-field-card .gf-fc-label {\n font-size: 11px; color: #d4d4d8; white-space: nowrap;\n overflow: hidden; text-overflow: ellipsis;\n }\n .gf-field-card .gf-fc-req {\n color: #f87171; font-size: 11px; flex-shrink: 0;\n }\n\n /* Inline status text inside prompt popover */\n .gf-status {\n font-size: 11px; padding: 4px 0; text-align: center; min-height: 18px;\n transition: color 0.15s;\n }\n .gf-status.error { color: #f87171; }\n .gf-status.success { color: #4ade80; }\n .gf-status.info { color: #71717a; }\n\n .gf-spin { animation: gf-spin 0.7s linear infinite; }\n @keyframes gf-spin { to { transform: rotate(360deg); } }\n\n .gf-badge {\n position: absolute; top: 2px; right: 2px; width: 14px; height: 14px;\n border-radius: 7px; background: #6366f1; color: white;\n font-size: 9px; font-weight: 700; display: flex; align-items: center;\n justify-content: center; line-height: 1;\n }\n\n .gf-dot-warn {\n position: absolute; top: 4px; right: 4px; width: 6px; height: 6px;\n border-radius: 3px; background: #f59e0b;\n }\n\n /* Toggle switch */\n .gf-toggle {\n position: relative; display: inline-block; width: 32px; height: 18px; cursor: pointer;\n }\n .gf-toggle input { opacity: 0; width: 0; height: 0; }\n .gf-toggle-slider {\n position: absolute; inset: 0; background: #3f3f46; border-radius: 9px;\n transition: background 0.2s;\n }\n .gf-toggle-slider::before {\n content: \"\"; position: absolute; left: 2px; top: 2px;\n width: 14px; height: 14px; border-radius: 50%; background: #fafafa;\n transition: transform 0.2s;\n }\n .gf-toggle input:checked + .gf-toggle-slider { background: #6366f1; }\n .gf-toggle input:checked + .gf-toggle-slider::before { transform: translateX(14px); }\n\n /* Custom inline picker (like Agentation's \"Standard\") */\n .gf-picker {\n position: relative; display: flex; align-items: center; gap: 4px;\n cursor: pointer; user-select: none;\n }\n .gf-picker-value {\n font-size: 13px; font-weight: 400; color: rgba(255,255,255,0.85);\n letter-spacing: -0.0094em;\n }\n .gf-picker-dots {\n font-size: 14px; color: #52525b; line-height: 1;\n }\n .gf-picker-menu {\n display: none; position: absolute; right: 0; top: calc(100% + 6px);\n background: #09090b; border: 1px solid #27272a; border-radius: 8px;\n padding: 4px 0; min-width: 140px; z-index: 10;\n box-shadow: 0 8px 24px rgba(0,0,0,0.4);\n }\n .gf-picker-menu.open { display: block; }\n .gf-picker-option {\n padding: 6px 12px; font-size: 12px; color: #a1a1aa; cursor: pointer;\n transition: background 0.1s, color 0.1s;\n }\n .gf-picker-option:hover { background: #27272a; color: #fafafa; }\n .gf-picker-option.selected { color: #6366f1; }\n\n /* Preset chips */\n .gf-presets-row {\n display: flex; align-items: center; gap: 4px; flex-wrap: wrap;\n }\n .gf-preset-chip {\n padding: 3px 8px; border-radius: 10px; font-size: 11px; font-weight: 500;\n background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.5);\n cursor: pointer; border: 1px solid transparent;\n transition: all 0.15s; white-space: nowrap;\n }\n .gf-preset-chip:hover { color: rgba(255,255,255,0.8); background: rgba(255,255,255,0.1); }\n .gf-preset-chip.active { border-color: #6366f1; color: #a5b4fc; background: rgba(99,102,241,0.12); }\n .gf-preset-chip.add {\n color: rgba(255,255,255,0.3); border: 1px dashed rgba(255,255,255,0.15);\n background: transparent;\n }\n .gf-preset-chip.add:hover { color: rgba(255,255,255,0.6); border-color: rgba(255,255,255,0.3); }\n\n /* Preset list in settings */\n .gf-preset-list { display: flex; flex-direction: column; gap: 4px; }\n .gf-preset-item {\n display: flex; align-items: center; justify-content: space-between;\n padding: 4px 8px; border-radius: 6px; background: rgba(255,255,255,0.04);\n }\n .gf-preset-item-name { font-size: 12px; color: rgba(255,255,255,0.7); }\n .gf-preset-del {\n background: none; border: none; color: rgba(255,255,255,0.25); cursor: pointer;\n font-size: 14px; padding: 0 2px; line-height: 1; transition: color 0.15s;\n }\n .gf-preset-del:hover { color: #f87171; }\n\n /* Preset add form */\n .gf-preset-form { display: flex; flex-direction: column; gap: 6px; }\n .gf-preset-form-row { display: flex; gap: 4px; }\n .gf-preset-form-row .gf-input { flex: 1; }\n .gf-preset-form-actions { display: flex; gap: 4px; justify-content: flex-end; }\n .gf-preset-form-btn {\n padding: 3px 10px; border: none; border-radius: 6px; font-size: 11px;\n cursor: pointer; font-family: inherit; transition: background 0.15s;\n }\n .gf-preset-form-btn.save { background: #6366f1; color: white; }\n .gf-preset-form-btn.save:hover { background: #4f46e5; }\n .gf-preset-form-btn.cancel { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.5); }\n .gf-preset-form-btn.cancel:hover { background: rgba(255,255,255,0.1); }\n\n /* Help badge */\n .gf-help {\n display: inline-flex; align-items: center; justify-content: center;\n width: 14px; height: 14px; border-radius: 50%;\n background: #3f3f46; color: #a1a1aa; font-size: 9px; font-weight: 700;\n cursor: help; flex-shrink: 0;\n }\n`;\n\n// ─── Build UI ───────────────────────────────────────────────────────────────\n\nexport function createOverlay(options: GhostFillOptions): {\n state: GhostFillState;\n destroy: () => void;\n} {\n const saved = loadSettings();\n if (options.apiKey && !saved.apiKey) {\n saved.apiKey = options.apiKey;\n saveSettings(saved);\n }\n if (options.model && !saved.model) saved.model = options.model;\n if (options.baseURL && !saved.baseURL) saved.baseURL = options.baseURL;\n\n const host = document.createElement(\"div\");\n host.id = \"ghostfill-root\";\n host.style.cssText = \"display:contents;\";\n document.body.appendChild(host);\n const shadow = host.attachShadow({ mode: \"open\" });\n\n const style = document.createElement(\"style\");\n style.textContent = CSS;\n shadow.appendChild(style);\n\n const state: GhostFillState = {\n active: false, selecting: false, selectedBlock: null,\n fields: [], overlay: host, shadowRoot: shadow,\n };\n\n // ── Toolbar ──\n const bar = document.createElement(\"div\");\n bar.className = \"gf-bar\";\n shadow.appendChild(bar);\n\n // Start minimized — bar hidden, fab visible\n bar.style.display = \"none\";\n const savedPos = loadPosition();\n if (savedPos) {\n bar.style.left = `${savedPos.x}px`;\n bar.style.top = `${savedPos.y}px`;\n } else {\n bar.style.bottom = \"20px\";\n bar.style.left = \"50%\";\n bar.style.transform = \"translateX(-50%)\";\n }\n\n function makeBtn(icon: string): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.className = \"gf-bar-btn\";\n btn.innerHTML = icon;\n return btn;\n }\n\n const btnSelect = makeBtn(ICONS.select);\n const btnFill = makeBtn(ICONS.sparkles);\n const btnSettings = makeBtn(ICONS.settings);\n const btnMinimize = makeBtn(ICONS.close);\n\n btnFill.disabled = true;\n\n const badge = document.createElement(\"span\");\n badge.className = \"gf-badge\";\n badge.style.display = \"none\";\n btnSelect.style.position = \"relative\";\n btnSelect.appendChild(badge);\n\n const dotWarn = document.createElement(\"span\");\n dotWarn.className = \"gf-dot-warn\";\n btnSettings.style.position = \"relative\";\n btnSettings.appendChild(dotWarn);\n if (!saved.useAI || saved.apiKey) dotWarn.style.display = \"none\";\n\n const divider1 = document.createElement(\"span\");\n divider1.className = \"gf-divider\";\n const divider2 = document.createElement(\"span\");\n divider2.className = \"gf-divider\";\n\n bar.append(btnSelect, btnFill, divider1, btnSettings, divider2, btnMinimize);\n\n // ── Mini FAB ──\n const fab = document.createElement(\"button\");\n fab.className = \"gf-fab visible\";\n fab.innerHTML = ICONS.ghost;\n fab.title = \"GhostFill\";\n // Restore saved fab position or default bottom-right\n const savedFabPos = (() => {\n try {\n const raw = localStorage.getItem(FAB_POS_KEY);\n if (raw) return JSON.parse(raw) as { x: number; y: number };\n } catch {}\n return null;\n })();\n // Always clamp to viewport — ignore stale saved positions\n if (savedFabPos) {\n const x = Math.min(savedFabPos.x, window.innerWidth - 60);\n const y = Math.min(savedFabPos.y, window.innerHeight - 60);\n fab.style.left = `${Math.max(8, x)}px`;\n fab.style.top = `${Math.max(8, y)}px`;\n } else {\n fab.style.right = \"80px\";\n fab.style.bottom = \"80px\";\n }\n shadow.appendChild(fab);\n\n function positionFab() {\n // Use last saved fab position, or fall back to bar center\n const savedFab = (() => {\n try {\n const raw = localStorage.getItem(FAB_POS_KEY);\n if (raw) return JSON.parse(raw) as { x: number; y: number };\n } catch {}\n return null;\n })();\n\n if (savedFab) {\n fab.style.left = `${savedFab.x}px`;\n fab.style.top = `${savedFab.y}px`;\n } else {\n const barRect = bar.getBoundingClientRect();\n fab.style.left = `${barRect.left + barRect.width / 2 - 22}px`;\n fab.style.top = `${barRect.top + barRect.height / 2 - 22}px`;\n }\n fab.style.bottom = \"\";\n fab.style.right = \"\";\n }\n\n // ── Drag ──\n let isDragging = false;\n let dragStartX = 0;\n let dragStartY = 0;\n let barStartX = 0;\n let barStartY = 0;\n let hasDragged = false;\n\n function onDragStart(e: MouseEvent) {\n isDragging = true;\n hasDragged = false;\n dragStartX = e.clientX;\n dragStartY = e.clientY;\n const rect = bar.getBoundingClientRect();\n barStartX = rect.left;\n barStartY = rect.top;\n bar.style.transform = \"none\";\n bar.style.bottom = \"\";\n document.addEventListener(\"mousemove\", onDragMove);\n document.addEventListener(\"mouseup\", onDragEnd);\n }\n\n function onDragMove(e: MouseEvent) {\n if (!isDragging) return;\n const dx = e.clientX - dragStartX;\n const dy = e.clientY - dragStartY;\n if (!hasDragged && (Math.abs(dx) > 4 || Math.abs(dy) > 4)) {\n hasDragged = true;\n bar.classList.add(\"dragging\");\n }\n if (!hasDragged) return;\n const barW = bar.offsetWidth;\n const barH = bar.offsetHeight;\n bar.style.left = `${Math.max(0, Math.min(window.innerWidth - barW, barStartX + dx))}px`;\n bar.style.top = `${Math.max(0, Math.min(window.innerHeight - barH, barStartY + dy))}px`;\n }\n\n function onDragEnd() {\n isDragging = false;\n bar.classList.remove(\"dragging\");\n document.removeEventListener(\"mousemove\", onDragMove);\n document.removeEventListener(\"mouseup\", onDragEnd);\n if (hasDragged) {\n const rect = bar.getBoundingClientRect();\n savePosition(rect.left, rect.top);\n repositionPopover();\n setTimeout(() => { hasDragged = false; }, 0);\n }\n }\n\n bar.addEventListener(\"mousedown\", onDragStart);\n\n // ── Settings Popover ──\n const HIGHLIGHT_COLORS = [\n { color: \"#8b5cf6\", name: \"Purple\" },\n { color: \"#3b82f6\", name: \"Blue\" },\n { color: \"#06b6d4\", name: \"Cyan\" },\n { color: \"#22c55e\", name: \"Green\" },\n { color: \"#eab308\", name: \"Yellow\" },\n { color: \"#f97316\", name: \"Orange\" },\n { color: \"#ef4444\", name: \"Red\" },\n ];\n\n const settingsPop = document.createElement(\"div\");\n settingsPop.className = \"gf-popover\";\n settingsPop.innerHTML = `\n <div class=\"gf-pop-header\">\n <h3><span class=\"gf-slash\">/</span>ghostfill</h3>\n <div class=\"gf-header-right\">\n <span class=\"gf-version\">v0.1.0</span>\n <button class=\"gf-theme-btn\" id=\"gf-s-theme\" title=\"Toggle theme\">\n ${saved.theme === \"dark\" ? ICONS.sun : ICONS.moon}\n </button>\n </div>\n </div>\n <div class=\"gf-pop-body\">\n <div class=\"gf-field\">\n <label class=\"gf-label\">Highlight Colour</label>\n <div class=\"gf-colors\" id=\"gf-s-colors\">\n ${HIGHLIGHT_COLORS.map((c) =>\n `<div class=\"gf-color-dot${saved.highlightColor === c.color ? \" selected\" : \"\"}\" data-color=\"${c.color}\" style=\"background:${c.color}\" title=\"${c.name}\"></div>`\n ).join(\"\")}\n </div>\n </div>\n <div class=\"gf-sep\"></div>\n <div class=\"gf-field\" style=\"flex-direction:row;align-items:center;justify-content:space-between\">\n <label class=\"gf-label\" style=\"margin:0\">Use AI</label>\n <label class=\"gf-toggle\">\n <input type=\"checkbox\" id=\"gf-s-useai\" ${saved.useAI ? \"checked\" : \"\"} />\n <span class=\"gf-toggle-slider\"></span>\n </label>\n </div>\n <div id=\"gf-s-ai-section\" style=\"display:${saved.useAI ? \"flex\" : \"none\"};flex-direction:column;gap:12px\">\n <div class=\"gf-field\" style=\"flex-direction:row;align-items:center;justify-content:space-between\">\n <div style=\"display:flex;align-items:center;gap:4px\">\n <label class=\"gf-label\" style=\"margin:0\">Provider</label>\n <span class=\"gf-help\" id=\"gf-s-help\" title=\"\">?</span>\n </div>\n <div class=\"gf-picker\" id=\"gf-s-provider-picker\">\n <span class=\"gf-picker-value\" id=\"gf-s-provider-label\">${PROVIDERS[saved.provider]?.label || \"OpenAI\"}</span>\n </div>\n </div>\n <div class=\"gf-field\">\n <label class=\"gf-label\">API Key</label>\n <input type=\"password\" class=\"gf-input gf-input-mono\" id=\"gf-s-key\" placeholder=\"sk-...\" autocomplete=\"off\" spellcheck=\"false\" />\n </div>\n </div>\n <div class=\"gf-sep\"></div>\n <div class=\"gf-field\">\n <div style=\"display:flex;align-items:center;justify-content:space-between\">\n <label class=\"gf-label\" style=\"margin:0\">Presets</label>\n <button class=\"gf-preset-chip add\" id=\"gf-s-preset-add\" style=\"font-size:10px;padding:2px 6px\">+ Add</button>\n </div>\n <div class=\"gf-preset-list\" id=\"gf-s-preset-list\"></div>\n <div class=\"gf-preset-form\" id=\"gf-s-preset-form\" style=\"display:none\">\n <input class=\"gf-input\" id=\"gf-s-preset-name\" placeholder=\"Name (e.g. D365)\" />\n <textarea class=\"gf-input\" id=\"gf-s-preset-prompt\" placeholder=\"Prompt context...\" rows=\"2\" style=\"min-height:40px\"></textarea>\n <div class=\"gf-preset-form-actions\">\n <button class=\"gf-preset-form-btn cancel\" id=\"gf-s-preset-cancel\">Cancel</button>\n <button class=\"gf-preset-form-btn save\" id=\"gf-s-preset-save\">Save</button>\n </div>\n </div>\n </div>\n <button class=\"gf-save-btn\" id=\"gf-s-save\">Save</button>\n </div>\n `;\n shadow.appendChild(settingsPop);\n\n const sKeyInput = settingsPop.querySelector<HTMLInputElement>(\"#gf-s-key\")!;\n const sUseAIToggle = settingsPop.querySelector<HTMLInputElement>(\"#gf-s-useai\")!;\n const sAISection = settingsPop.querySelector<HTMLDivElement>(\"#gf-s-ai-section\")!;\n const sHelpEl = settingsPop.querySelector<HTMLSpanElement>(\"#gf-s-help\")!;\n const sSaveBtn = settingsPop.querySelector<HTMLButtonElement>(\"#gf-s-save\")!;\n const sThemeBtn = settingsPop.querySelector<HTMLButtonElement>(\"#gf-s-theme\")!;\n const sColorsDiv = settingsPop.querySelector<HTMLDivElement>(\"#gf-s-colors\")!;\n const sPickerEl = settingsPop.querySelector<HTMLDivElement>(\"#gf-s-provider-picker\")!;\n const sPickerLabel = settingsPop.querySelector<HTMLSpanElement>(\"#gf-s-provider-label\")!;\n sKeyInput.value = saved.apiKey;\n\n // ── Provider picker — click to cycle ──\n const providerOrder: Provider[] = [\"openai\", \"xai\", \"moonshot\"];\n let selectedProvider: Provider = saved.provider || \"openai\";\n\n function updateProviderDisplay() {\n const p = PROVIDERS[selectedProvider] || PROVIDERS.openai;\n sPickerLabel.textContent = `${p.label} (${p.model})`;\n sHelpEl.title = p.helpText;\n }\n updateProviderDisplay();\n\n sPickerEl.addEventListener(\"click\", () => {\n const idx = providerOrder.indexOf(selectedProvider);\n selectedProvider = providerOrder[(idx + 1) % providerOrder.length]!;\n updateProviderDisplay();\n });\n\n // Toggle AI section\n sUseAIToggle.addEventListener(\"change\", () => {\n sAISection.style.display = sUseAIToggle.checked ? \"flex\" : \"none\";\n });\n\n // ── Highlight color selection ──\n let currentHighlightColor = saved.highlightColor || \"#6366f1\";\n sColorsDiv.addEventListener(\"click\", (e) => {\n const dot = (e.target as HTMLElement).closest(\".gf-color-dot\") as HTMLElement;\n if (!dot) return;\n sColorsDiv.querySelectorAll(\".gf-color-dot\").forEach((d) => d.classList.remove(\"selected\"));\n dot.classList.add(\"selected\");\n currentHighlightColor = dot.dataset.color || \"#6366f1\";\n });\n\n // ── Theme toggle ──\n let currentTheme = saved.theme || \"dark\";\n\n function applyTheme(theme: \"dark\" | \"light\") {\n currentTheme = theme;\n const isDark = theme === \"dark\";\n sThemeBtn.innerHTML = isDark ? ICONS.sun : ICONS.moon;\n\n const bg = isDark ? \"#18181b\" : \"#ffffff\";\n const bgInput = isDark ? \"#09090b\" : \"#f4f4f5\";\n const border = isDark ? \"#27272a\" : \"#e4e4e7\";\n const text = isDark ? \"#fafafa\" : \"#18181b\";\n const textMuted = isDark ? \"#a1a1aa\" : \"#52525b\";\n const textDim = isDark ? \"#52525b\" : \"#a1a1aa\";\n const btnHoverBg = isDark ? \"#27272a\" : \"#f4f4f5\";\n\n for (const pop of [settingsPop, promptPop]) {\n pop.style.background = bg;\n pop.style.boxShadow = isDark\n ? \"0 12px 40px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.06)\"\n : \"0 12px 40px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.08)\";\n pop.querySelectorAll<HTMLElement>(\".gf-pop-header h3\").forEach((el) => el.style.color = text);\n pop.querySelectorAll<HTMLElement>(\".gf-label\").forEach((el) => el.style.color = textMuted);\n pop.querySelectorAll<HTMLElement>(\".gf-input\").forEach((el) => {\n el.style.background = bgInput;\n el.style.borderColor = border;\n el.style.color = text;\n });\n pop.querySelectorAll<HTMLElement>(\".gf-sep\").forEach((el) => el.style.background = border);\n pop.querySelectorAll<HTMLElement>(\".gf-version\").forEach((el) => el.style.color = textDim);\n pop.querySelectorAll<HTMLElement>(\".gf-field-count\").forEach((el) => el.style.color = textMuted);\n pop.querySelectorAll<HTMLElement>(\".gf-fc-label\").forEach((el) => el.style.color = isDark ? \"#d4d4d8\" : \"#3f3f46\");\n pop.querySelectorAll<HTMLElement>(\".gf-field-card\").forEach((el) => {\n el.style.background = isDark ? \"#27272a\" : \"#f4f4f5\";\n el.style.borderColor = border;\n });\n }\n\n bar.style.background = bg;\n bar.style.boxShadow = isDark\n ? \"0 8px 32px rgba(0,0,0,0.35), 0 0 0 1px rgba(255,255,255,0.06)\"\n : \"0 8px 32px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.08)\";\n bar.querySelectorAll<HTMLElement>(\".gf-bar-btn\").forEach((btn) => {\n btn.style.color = textMuted;\n // Fix hover colors for light mode\n btn.onmouseenter = () => { btn.style.background = btnHoverBg; btn.style.color = text; };\n btn.onmouseleave = () => {\n if (!btn.classList.contains(\"active\")) { btn.style.background = \"transparent\"; btn.style.color = textMuted; }\n };\n });\n bar.querySelectorAll<HTMLElement>(\".gf-divider\").forEach((el) => el.style.background = border);\n\n fab.style.background = bg;\n fab.style.color = textMuted;\n fab.style.boxShadow = isDark\n ? \"0 4px 16px rgba(0,0,0,0.35), 0 0 0 1px rgba(255,255,255,0.06)\"\n : \"0 4px 16px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.08)\";\n }\n\n if (currentTheme === \"light\") applyTheme(\"light\");\n\n sThemeBtn.addEventListener(\"click\", () => {\n applyTheme(currentTheme === \"dark\" ? \"light\" : \"dark\");\n });\n\n // ── Prompt Popover ──\n const promptPop = document.createElement(\"div\");\n promptPop.className = \"gf-popover\";\n promptPop.style.width = \"300px\";\n promptPop.innerHTML = `\n <div class=\"gf-pop-header\">\n <h3>Fill Fields</h3>\n <span class=\"gf-field-count\" id=\"gf-p-count\">0 fields</span>\n </div>\n <div class=\"gf-pop-body\">\n <div id=\"gf-p-fields-wrap\" style=\"display:none\">\n <div class=\"gf-fields-grid\" id=\"gf-p-grid\"></div>\n </div>\n <div class=\"gf-field\" id=\"gf-p-preset-row\" style=\"display:none;flex-direction:row;align-items:center;justify-content:space-between\">\n <label class=\"gf-label\" style=\"margin:0\">Preset</label>\n <div class=\"gf-picker\" id=\"gf-p-preset-picker\">\n <span class=\"gf-picker-value\" id=\"gf-p-preset-label\">None</span>\n </div>\n </div>\n <div class=\"gf-field\" id=\"gf-p-prompt-wrap\">\n <textarea class=\"gf-input\" id=\"gf-p-prompt\" placeholder=\"Optional: describe the data you want&#10;Leave empty for auto-generated data\" rows=\"2\"></textarea>\n </div>\n <button class=\"gf-fill-btn\" id=\"gf-p-fill\">\n ${ICONS.sparkles} Fill\n </button>\n <div class=\"gf-status info\" id=\"gf-p-status\"></div>\n </div>\n `;\n shadow.appendChild(promptPop);\n\n const pCountEl = promptPop.querySelector<HTMLSpanElement>(\"#gf-p-count\")!;\n const pFieldsWrap = promptPop.querySelector<HTMLDivElement>(\"#gf-p-fields-wrap\")!;\n const pFieldGrid = promptPop.querySelector<HTMLDivElement>(\"#gf-p-grid\")!;\n const pPresetRow = promptPop.querySelector<HTMLDivElement>(\"#gf-p-preset-row\")!;\n const pPresetPicker = promptPop.querySelector<HTMLDivElement>(\"#gf-p-preset-picker\")!;\n const pPresetLabel = promptPop.querySelector<HTMLSpanElement>(\"#gf-p-preset-label\")!;\n const pPromptWrap = promptPop.querySelector<HTMLDivElement>(\"#gf-p-prompt-wrap\")!;\n const pPromptEl = promptPop.querySelector<HTMLTextAreaElement>(\"#gf-p-prompt\")!;\n const pFillBtn = promptPop.querySelector<HTMLButtonElement>(\"#gf-p-fill\")!;\n const pStatusEl = promptPop.querySelector<HTMLDivElement>(\"#gf-p-status\")!;\n\n let presets: Preset[] = saved.presets || [];\n let activePresetId: string | null = saved.activePresetId || null;\n\n function updateFillPresetUI() {\n if (presets.length === 0) {\n pPresetRow.style.display = \"none\";\n pPromptWrap.style.display = \"flex\";\n activePresetId = null;\n return;\n }\n pPresetRow.style.display = \"flex\";\n\n // Find active preset\n const active = activePresetId ? presets.find((p) => p.id === activePresetId) : null;\n pPresetLabel.textContent = active ? active.name : \"None\";\n\n // Hide prompt textarea when a preset is active\n pPromptWrap.style.display = active ? \"none\" : \"flex\";\n }\n\n function persistActivePreset() {\n const s = loadSettings();\n s.activePresetId = activePresetId;\n saveSettings(s);\n }\n\n // Click to cycle: None → preset1 → preset2 → ... → None\n pPresetPicker.addEventListener(\"click\", () => {\n if (presets.length === 0) return;\n if (!activePresetId) {\n activePresetId = presets[0]!.id;\n } else {\n const idx = presets.findIndex((p) => p.id === activePresetId);\n if (idx < presets.length - 1) {\n activePresetId = presets[idx + 1]!.id;\n } else {\n activePresetId = null;\n }\n }\n persistActivePreset();\n updateFillPresetUI();\n });\n\n updateFillPresetUI();\n\n function setStatus(text: string, type: \"info\" | \"success\" | \"error\") {\n pStatusEl.textContent = text;\n pStatusEl.className = `gf-status ${type}`;\n }\n\n function clearStatus() {\n pStatusEl.textContent = \"\";\n pStatusEl.className = \"gf-status info\";\n }\n\n // ── Popover positioning ──\n function repositionPopover() {\n const barRect = bar.getBoundingClientRect();\n const popCenterX = barRect.left + barRect.width / 2;\n const popBottom = barRect.top - 8;\n for (const pop of [settingsPop, promptPop]) {\n pop.style.position = \"fixed\";\n pop.style.bottom = \"\";\n pop.style.left = `${popCenterX}px`;\n pop.style.top = `${popBottom}px`;\n pop.style.transform = \"translate(-50%, -100%)\";\n }\n }\n\n type PopoverName = \"settings\" | \"prompt\" | null;\n let currentPopover: PopoverName = null;\n\n function openPopover(name: PopoverName) {\n settingsPop.classList.remove(\"open\");\n promptPop.classList.remove(\"open\");\n btnSettings.classList.remove(\"active\");\n btnFill.classList.remove(\"active\");\n if (name === currentPopover || name === null) { currentPopover = null; return; }\n repositionPopover();\n currentPopover = name;\n if (name === \"settings\") {\n settingsPop.classList.add(\"open\");\n btnSettings.classList.add(\"active\");\n sKeyInput.focus();\n } else if (name === \"prompt\") {\n promptPop.classList.add(\"open\");\n btnFill.classList.add(\"active\");\n pPromptEl.focus();\n }\n }\n\n // ── Block highlight ──\n let blockHighlight: HTMLDivElement | null = null;\n\n function highlightBlock(el: HTMLElement) {\n removeBlockHighlight();\n blockHighlight = document.createElement(\"div\");\n blockHighlight.id = \"ghostfill-block-highlight\";\n const rect = el.getBoundingClientRect();\n const c = currentHighlightColor;\n Object.assign(blockHighlight.style, {\n position: \"fixed\", top: `${rect.top}px`, left: `${rect.left}px`,\n width: `${rect.width}px`, height: `${rect.height}px`,\n border: `2px solid ${c}`, borderRadius: \"6px\",\n backgroundColor: `${c}0d`,\n pointerEvents: \"none\", zIndex: \"2147483644\", transition: \"all 0.2s\",\n });\n document.body.appendChild(blockHighlight);\n }\n\n function removeBlockHighlight() {\n blockHighlight?.remove();\n blockHighlight = null;\n }\n\n function fieldTypeIcon(type: string): string {\n switch (type) {\n case \"email\": return ICONS.ftEmail;\n case \"tel\": return ICONS.ftPhone;\n case \"number\": case \"range\": return ICONS.ftNumber;\n case \"date\": case \"datetime-local\": case \"time\": case \"month\": case \"week\": return ICONS.ftDate;\n case \"select\": return ICONS.ftSelect;\n case \"textarea\": return ICONS.ftTextarea;\n case \"checkbox\": return ICONS.ftCheckbox;\n case \"radio\": return ICONS.ftRadio;\n case \"url\": return ICONS.ftUrl;\n case \"password\": return ICONS.ftPassword;\n case \"file\": return ICONS.ftFile;\n default: return ICONS.ftText;\n }\n }\n\n // Track field highlight so we can remove it\n let fieldHighlightEl: HTMLElement | null = null;\n function highlightField(el: HTMLElement) {\n clearFieldHighlight();\n el.style.outline = `2px solid ${currentHighlightColor}`;\n el.style.outlineOffset = \"2px\";\n el.style.transition = \"outline 0.15s, outline-offset 0.15s\";\n fieldHighlightEl = el;\n }\n function clearFieldHighlight() {\n if (fieldHighlightEl) {\n fieldHighlightEl.style.outline = \"\";\n fieldHighlightEl.style.outlineOffset = \"\";\n fieldHighlightEl = null;\n }\n }\n\n function showFieldsInPrompt(fields: DetectedField[]) {\n pCountEl.textContent = `${fields.length} field${fields.length === 1 ? \"\" : \"s\"}`;\n pFieldGrid.innerHTML = \"\";\n fields.forEach((f) => {\n const card = document.createElement(\"div\");\n card.className = \"gf-field-card\";\n\n const icon = document.createElement(\"span\");\n icon.className = \"gf-fc-icon\";\n icon.innerHTML = fieldTypeIcon(f.type);\n\n const label = document.createElement(\"span\");\n label.className = \"gf-fc-label\";\n label.textContent = f.label;\n\n card.appendChild(icon);\n card.appendChild(label);\n\n if (f.required) {\n const req = document.createElement(\"span\");\n req.className = \"gf-fc-req\";\n req.textContent = \"*\";\n card.appendChild(req);\n }\n\n // Hover → highlight the actual field on the page\n card.addEventListener(\"mouseenter\", () => highlightField(f.element));\n card.addEventListener(\"mouseleave\", () => clearFieldHighlight());\n\n pFieldGrid.appendChild(card);\n });\n pFieldsWrap.style.display = \"block\";\n }\n\n let cleanupSelector: (() => void) | null = null;\n\n // ── Button: Select ──\n btnSelect.addEventListener(\"click\", () => {\n if (hasDragged) return;\n if (state.selecting) {\n cleanupSelector?.();\n cleanupSelector = null;\n state.selecting = false;\n btnSelect.classList.remove(\"active\");\n return;\n }\n openPopover(null);\n state.selecting = true;\n btnSelect.classList.add(\"active\");\n\n cleanupSelector = startSelection(\n (element) => {\n state.selecting = false;\n state.selectedBlock = element;\n btnSelect.classList.remove(\"active\");\n cleanupSelector = null;\n const fields = detectFields(element);\n state.fields = fields;\n if (fields.length === 0) {\n badge.style.display = \"none\";\n btnFill.disabled = true;\n return;\n }\n highlightBlock(element);\n showFieldsInPrompt(fields);\n badge.textContent = String(fields.length);\n badge.style.display = \"flex\";\n btnFill.disabled = false;\n },\n () => {\n state.selecting = false;\n btnSelect.classList.remove(\"active\");\n cleanupSelector = null;\n },\n host,\n currentHighlightColor\n );\n });\n\n // ── Button: Fill ──\n btnFill.addEventListener(\"click\", () => {\n if (hasDragged) return;\n if (state.fields.length === 0) return;\n openPopover(\"prompt\");\n });\n\n // ── Button: Settings ──\n btnSettings.addEventListener(\"click\", () => {\n if (hasDragged) return;\n openPopover(\"settings\");\n });\n\n // ── Button: Close (minimize) ──\n btnMinimize.addEventListener(\"click\", () => {\n if (hasDragged) return;\n openPopover(null);\n removeBlockHighlight();\n cleanupSelector?.();\n state.selecting = false;\n state.selectedBlock = null;\n state.fields = [];\n badge.style.display = \"none\";\n btnFill.disabled = true;\n positionFab();\n bar.style.display = \"none\";\n fab.classList.add(\"visible\");\n state.active = false;\n });\n\n // ── FAB: drag + click ──\n let fabDragState = { dragging: false, moved: false, startX: 0, startY: 0, fabX: 0, fabY: 0 };\n\n function onFabMouseDown(e: MouseEvent) {\n fabDragState = {\n dragging: true, moved: false,\n startX: e.clientX, startY: e.clientY,\n fabX: fab.getBoundingClientRect().left,\n fabY: fab.getBoundingClientRect().top,\n };\n const onMove = (ev: MouseEvent) => {\n const dx = ev.clientX - fabDragState.startX;\n const dy = ev.clientY - fabDragState.startY;\n if (!fabDragState.moved && (Math.abs(dx) > 4 || Math.abs(dy) > 4)) fabDragState.moved = true;\n if (!fabDragState.moved) return;\n fab.style.left = `${Math.max(0, Math.min(window.innerWidth - 44, fabDragState.fabX + dx))}px`;\n fab.style.top = `${Math.max(0, Math.min(window.innerHeight - 44, fabDragState.fabY + dy))}px`;\n fab.style.right = \"\";\n fab.style.bottom = \"\";\n };\n const onUp = () => {\n document.removeEventListener(\"mousemove\", onMove);\n document.removeEventListener(\"mouseup\", onUp);\n fabDragState.dragging = false;\n if (fabDragState.moved) {\n localStorage.setItem(FAB_POS_KEY, JSON.stringify({ x: fab.getBoundingClientRect().left, y: fab.getBoundingClientRect().top }));\n }\n };\n document.addEventListener(\"mousemove\", onMove);\n document.addEventListener(\"mouseup\", onUp);\n }\n fab.addEventListener(\"mousedown\", onFabMouseDown);\n\n fab.addEventListener(\"click\", () => {\n if (fabDragState.moved) { fabDragState.moved = false; return; }\n fab.classList.remove(\"visible\");\n bar.style.left = fab.style.left || `${window.innerWidth - 250}px`;\n bar.style.top = fab.style.top || `${window.innerHeight - 80}px`;\n bar.style.transform = \"none\";\n bar.style.bottom = \"\";\n bar.style.display = \"flex\";\n state.active = true;\n // Auto-start selection mode after a tick\n setTimeout(() => btnSelect.click(), 50);\n });\n\n // ── Preset management ──\n const sPresetList = settingsPop.querySelector<HTMLDivElement>(\"#gf-s-preset-list\")!;\n const sPresetForm = settingsPop.querySelector<HTMLDivElement>(\"#gf-s-preset-form\")!;\n const sPresetAddBtn = settingsPop.querySelector<HTMLButtonElement>(\"#gf-s-preset-add\")!;\n const sPresetName = settingsPop.querySelector<HTMLInputElement>(\"#gf-s-preset-name\")!;\n const sPresetPrompt = settingsPop.querySelector<HTMLTextAreaElement>(\"#gf-s-preset-prompt\")!;\n const sPresetSaveBtn = settingsPop.querySelector<HTMLButtonElement>(\"#gf-s-preset-save\")!;\n const sPresetCancelBtn = settingsPop.querySelector<HTMLButtonElement>(\"#gf-s-preset-cancel\")!;\n\n let editingPresetId: string | null = null;\n\n function renderPresetList() {\n sPresetList.innerHTML = \"\";\n presets.forEach((p) => {\n const item = document.createElement(\"div\");\n item.className = \"gf-preset-item\";\n const name = document.createElement(\"span\");\n name.className = \"gf-preset-item-name\";\n name.textContent = p.name;\n name.style.cursor = \"pointer\";\n name.addEventListener(\"click\", () => {\n // Edit this preset\n editingPresetId = p.id;\n sPresetForm.style.display = \"flex\";\n sPresetName.value = p.name;\n sPresetPrompt.value = p.prompt;\n sPresetName.focus();\n });\n const del = document.createElement(\"button\");\n del.className = \"gf-preset-del\";\n del.innerHTML = \"&times;\";\n del.addEventListener(\"click\", () => {\n presets = presets.filter((x) => x.id !== p.id);\n if (activePresetId === p.id) activePresetId = null;\n renderPresetList();\n updateFillPresetUI();\n });\n item.append(name, del);\n sPresetList.appendChild(item);\n });\n }\n renderPresetList();\n\n sPresetAddBtn.addEventListener(\"click\", () => {\n editingPresetId = null;\n sPresetForm.style.display = \"flex\";\n sPresetName.value = \"\";\n sPresetPrompt.value = \"\";\n sPresetName.focus();\n });\n\n sPresetCancelBtn.addEventListener(\"click\", () => {\n sPresetForm.style.display = \"none\";\n editingPresetId = null;\n });\n\n sPresetSaveBtn.addEventListener(\"click\", () => {\n const name = sPresetName.value.trim();\n const prompt = sPresetPrompt.value.trim();\n if (!name || !prompt) return;\n if (editingPresetId) {\n // Update existing\n const idx = presets.findIndex((p) => p.id === editingPresetId);\n if (idx >= 0) presets[idx] = { ...presets[idx]!, name, prompt };\n } else {\n // Add new\n presets.push({ id: Date.now().toString(36), name, prompt });\n }\n editingPresetId = null;\n sPresetForm.style.display = \"none\";\n renderPresetList();\n updateFillPresetUI();\n });\n\n // ── Settings: Save ──\n sSaveBtn.addEventListener(\"click\", () => {\n const s: GhostFillSettings = {\n apiKey: sKeyInput.value.trim(),\n provider: selectedProvider,\n highlightColor: currentHighlightColor,\n theme: currentTheme,\n useAI: sUseAIToggle.checked,\n presets,\n activePresetId,\n };\n saveSettings(s);\n dotWarn.style.display = (s.useAI && !s.apiKey) ? \"block\" : \"none\";\n openPopover(null);\n });\n\n // ── Prompt: Fill ──\n async function doFill() {\n const settings = loadSettings();\n // Build prompt: preset + user text\n const activePreset = activePresetId\n ? (settings.presets || []).find((p) => p.id === activePresetId)\n : null;\n const userText = pPromptEl.value.trim();\n const promptText = [activePreset?.prompt, userText].filter(Boolean).join(\"\\n\\n\");\n\n if (state.fields.length === 0) return;\n\n pFillBtn.disabled = true;\n pFillBtn.innerHTML = `<span class=\"gf-spin\">${ICONS.spinner}</span> Filling...`;\n clearStatus();\n\n try {\n let fillData;\n\n if (settings.useAI) {\n // AI mode\n if (!settings.apiKey) {\n setStatus(\"Set your API key in Settings first\", \"error\");\n pFillBtn.disabled = false;\n pFillBtn.innerHTML = `${ICONS.sparkles} Fill`;\n return;\n }\n const blockContext = state.selectedBlock\n ? extractBlockContext(state.selectedBlock)\n : \"\";\n fillData = await generateFillData(\n state.fields,\n promptText,\n settings,\n options.systemPrompt,\n blockContext\n );\n } else {\n // Local faker mode — instant, no API call\n fillData = generateFakeData(state.fields);\n }\n\n const { filled, errors } = await fillFields(state.fields, fillData);\n\n if (errors.length > 0) {\n setStatus(`Filled ${filled}/${state.fields.length} fields`, filled > 0 ? \"success\" : \"error\");\n } else {\n setStatus(`Filled ${filled} field${filled === 1 ? \"\" : \"s\"}`, \"success\");\n }\n removeBlockHighlight();\n setTimeout(() => openPopover(null), 600);\n } catch (err) {\n setStatus(cleanError(err), \"error\");\n } finally {\n pFillBtn.disabled = false;\n pFillBtn.innerHTML = `${ICONS.sparkles} Fill`;\n }\n }\n\n pFillBtn.addEventListener(\"click\", doFill);\n pPromptEl.addEventListener(\"keydown\", (e) => {\n if ((e.ctrlKey || e.metaKey) && e.key === \"Enter\") { e.preventDefault(); doFill(); }\n });\n\n // ── Keyboard shortcut ──\n const shortcut = options.shortcut || \"Alt+G\";\n const keys = shortcut.toLowerCase().split(\"+\");\n function handleShortcut(e: KeyboardEvent) {\n const mainKey = keys.filter(\n (k) => ![\"alt\", \"ctrl\", \"control\", \"shift\", \"meta\", \"cmd\"].includes(k)\n )[0];\n const match =\n (keys.includes(\"alt\") ? e.altKey : !e.altKey) &&\n (keys.includes(\"ctrl\") || keys.includes(\"control\") ? e.ctrlKey : !e.ctrlKey) &&\n (keys.includes(\"shift\") ? e.shiftKey : !e.shiftKey) &&\n (keys.includes(\"meta\") || keys.includes(\"cmd\") ? e.metaKey : !e.metaKey) &&\n e.key.toLowerCase() === mainKey;\n if (match) {\n e.preventDefault();\n if (state.active) {\n openPopover(null);\n positionFab();\n bar.style.display = \"none\";\n fab.classList.add(\"visible\");\n state.active = false;\n } else {\n fab.classList.remove(\"visible\");\n bar.style.display = \"flex\";\n state.active = true;\n }\n }\n }\n document.addEventListener(\"keydown\", handleShortcut);\n\n function destroy() {\n cleanupSelector?.();\n removeBlockHighlight();\n document.removeEventListener(\"keydown\", handleShortcut);\n host.remove();\n }\n\n return { state, destroy };\n}\n","import type { GhostFillOptions } from \"./types\";\nimport { createOverlay } from \"./overlay\";\nimport { detectFields } from \"./detector\";\nimport { generateFakeData } from \"./faker\";\nimport { fillFields } from \"./filler\";\n\nexport type { GhostFillOptions, DetectedField, FieldFillData } from \"./types\";\n\nlet instance: { destroy: () => void } | null = null;\n\n/**\n * Initialize GhostFill — adds a floating ghost icon to the page.\n *\n * @example\n * ```ts\n * import { init } from \"ghostfill\";\n * init();\n * ```\n */\nexport function init(options: GhostFillOptions = {}): { destroy: () => void } {\n const existing = document.getElementById(\"ghostfill-root\");\n if (existing && instance) {\n return instance;\n }\n\n if (instance) {\n instance.destroy();\n instance = null;\n }\n\n const { state, destroy } = createOverlay(options);\n instance = { destroy };\n return { destroy };\n}\n\n/**\n * Programmatic API — detect fields and fill them without the UI.\n */\nexport async function fill(params: {\n container: HTMLElement;\n prompt?: string;\n}): Promise<{ filled: number; errors: string[] }> {\n const fields = detectFields(params.container);\n\n if (fields.length === 0) {\n return { filled: 0, errors: [\"No fillable fields found in container\"] };\n }\n\n const fillData = generateFakeData(fields);\n return fillFields(fields, fillData);\n}\n"],"mappings":"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R;AAIA,IAAMC,OAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["field","findLabel","CSS","createOverlay","createOverlay"]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "ghostfill",
3
+ "version": "0.1.0",
4
+ "description": "AI-powered form filler — select a block, detect fields, fill with AI-generated data",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsup --watch",
22
+ "typecheck": "tsc --noEmit",
23
+ "demo": "npx serve demo"
24
+ },
25
+ "keywords": [
26
+ "form-filler",
27
+ "ai",
28
+ "openai",
29
+ "fake-data",
30
+ "testing",
31
+ "developer-tool"
32
+ ],
33
+ "author": "afkhalid",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/afkhalid/ghostfill.git"
38
+ },
39
+ "homepage": "https://github.com/afkhalid/ghostfill#readme",
40
+ "bugs": {
41
+ "url": "https://github.com/afkhalid/ghostfill/issues"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.4.0"
46
+ }
47
+ }