@ai-me-chat/react 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +27 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +27 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -692,30 +692,34 @@ function AIMeChat({
|
|
|
692
692
|
}
|
|
693
693
|
)
|
|
694
694
|
] }),
|
|
695
|
-
messages.map((m) =>
|
|
696
|
-
"
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
695
|
+
messages.map((m) => {
|
|
696
|
+
const hasTextContent = m.parts.some((p) => p.type === "text");
|
|
697
|
+
if (!hasTextContent && m.role === "assistant") return null;
|
|
698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
699
|
+
"div",
|
|
700
|
+
{
|
|
701
|
+
style: {
|
|
702
|
+
alignSelf: m.role === "user" ? "flex-end" : "flex-start",
|
|
703
|
+
maxWidth: "85%",
|
|
704
|
+
padding: "8px 12px",
|
|
705
|
+
borderRadius: 8,
|
|
706
|
+
backgroundColor: m.role === "user" ? "var(--ai-me-primary)" : "var(--ai-me-bg-secondary)",
|
|
707
|
+
color: m.role === "user" ? "#fff" : "var(--ai-me-text)",
|
|
708
|
+
fontSize: 14,
|
|
709
|
+
lineHeight: 1.5,
|
|
710
|
+
whiteSpace: "pre-wrap",
|
|
711
|
+
wordBreak: "break-word"
|
|
712
|
+
},
|
|
713
|
+
children: [
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: srOnly, children: m.role === "user" ? "You: " : "Assistant: " }),
|
|
715
|
+
m.parts.map(
|
|
716
|
+
(p, i) => p.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
717
|
+
)
|
|
718
|
+
]
|
|
709
719
|
},
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
(p, i) => p.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
714
|
-
)
|
|
715
|
-
]
|
|
716
|
-
},
|
|
717
|
-
m.id
|
|
718
|
-
)),
|
|
720
|
+
m.id
|
|
721
|
+
);
|
|
722
|
+
}),
|
|
719
723
|
status === "submitted" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
720
724
|
"div",
|
|
721
725
|
{
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/provider.tsx","../src/chat.tsx","../src/use-ai-me.ts","../src/styles.ts","../src/markdown.tsx","../src/command-palette.tsx","../src/confirm.tsx"],"sourcesContent":["export { AIMeProvider } from \"./provider.js\";\nexport type { AIMeProviderProps } from \"./provider.js\";\nexport { AIMeChat } from \"./chat.js\";\nexport type { AIMeChatProps } from \"./chat.js\";\nexport { AIMeCommandPalette } from \"./command-palette.js\";\nexport type {\n AIMeCommandPaletteProps,\n CommandItem,\n} from \"./command-palette.js\";\nexport { AIMeConfirm } from \"./confirm.js\";\nexport type { AIMeConfirmProps } from \"./confirm.js\";\nexport { useAIMe } from \"./use-ai-me.js\";\nexport { useAIMeContext } from \"./context.js\";\nexport type { AIMeContextValue } from \"./context.js\";\nexport type { AIMeTheme } from \"./styles.js\";\nexport { renderMarkdown } from \"./markdown.js\";\n","import { createContext, useContext } from \"react\";\n\n/** Payload passed to the `onAction` callback */\nexport interface AIMeAction {\n /** Action type — e.g. \"navigate\", \"prefill\", \"open-modal\" */\n type: string;\n /** Flexible additional payload supplied by the AI tool */\n [key: string]: unknown;\n}\n\nexport interface AIMeContextValue {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n * Use this to handle navigation, form pre-fill, modal opening, etc.\n * without the AI making an API call directly.\n */\n onAction?: (action: AIMeAction) => void;\n}\n\nexport const AIMeContext = createContext<AIMeContextValue | null>(null);\n\nexport function useAIMeContext(): AIMeContextValue {\n const ctx = useContext(AIMeContext);\n if (!ctx) {\n throw new Error(\"useAIMe must be used within an <AIMeProvider>\");\n }\n return ctx;\n}\n","import type { ReactNode } from \"react\";\nimport { AIMeContext } from \"./context.js\";\nimport type { AIMeAction } from \"./context.js\";\n\nexport interface AIMeProviderProps {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Optional: additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n *\n * The AI can emit structured actions (e.g. \"navigate\", \"prefill\",\n * \"open-modal\") that your app handles without making an API call.\n * Wire the corresponding `__navigate` / `__prefill` tools in your\n * AI-Me handler to produce these actions, then consume them here.\n *\n * @example\n * ```tsx\n * <AIMeProvider\n * endpoint=\"/api/ai-me\"\n * onAction={(action) => {\n * if (action.type === \"navigate\") {\n * router.push(action.href as string);\n * }\n * }}\n * >\n * {children}\n * </AIMeProvider>\n * ```\n */\n onAction?: (action: AIMeAction) => void;\n /** Child components */\n children: ReactNode;\n}\n\nexport function AIMeProvider({ endpoint, headers, onAction, children }: AIMeProviderProps) {\n return (\n <AIMeContext value={{ endpoint, headers, onAction }}>\n {children}\n </AIMeContext>\n );\n}\n","import { useState, useRef, useEffect, useCallback, useId } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useAIMe } from \"./use-ai-me.js\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { renderMarkdown } from \"./markdown.js\";\n\n/** Tool execution result passed to onToolComplete */\nexport interface ToolCompleteEvent {\n /** Tool (function) name */\n name: string;\n /** HTTP method used, if available from the tool result */\n httpMethod?: string;\n /** API path called, if available from the tool result */\n path?: string;\n /** Raw result returned by the tool */\n result: unknown;\n /** Whether the tool required user confirmation */\n requiresConfirmation?: boolean;\n}\n\n/** Completed assistant message passed to onMessageComplete */\nexport interface MessageCompleteEvent {\n role: string;\n content: string;\n toolCalls?: unknown[];\n}\n\nexport interface AIMeChatProps {\n /** Position of chat panel */\n position?: \"bottom-right\" | \"bottom-left\" | \"inline\";\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Welcome message shown on empty chat */\n welcomeMessage?: string;\n /** Suggested prompts shown on empty chat */\n suggestedPrompts?: string[];\n /** Whether chat starts open */\n defaultOpen?: boolean;\n /** Callback when chat opens/closes */\n onToggle?: (open: boolean) => void;\n /**\n * Fired after each tool execution completes (after the API call returns).\n * Use this to trigger client-side data refreshes when the AI mutates data.\n */\n onToolComplete?: (tool: ToolCompleteEvent) => void;\n /**\n * Fired when the assistant finishes a full response (status transitions\n * from \"streaming\" to \"ready\").\n */\n onMessageComplete?: (message: MessageCompleteEvent) => void;\n /**\n * Custom renderer for the tool confirmation dialog.\n *\n * When provided, AI-Me will call this function instead of showing the\n * default confirmation UI. Return any React node — a modal, an inline\n * card, a drawer, etc.\n *\n * If not provided, the built-in `<AIMeConfirm>` dialog is used.\n *\n * @example\n * ```tsx\n * <AIMeChat\n * renderConfirmation={({ tool, params, onConfirm, onCancel }) => (\n * <MyCustomConfirmDialog\n * title={`Run ${tool.name}?`}\n * description={tool.description}\n * params={params}\n * onConfirm={onConfirm}\n * onCancel={onCancel}\n * />\n * )}\n * />\n * ```\n */\n renderConfirmation?: (props: {\n /** Metadata about the tool that is about to be executed */\n tool: {\n /** Tool (function) name */\n name: string;\n /** HTTP method the tool maps to, e.g. \"POST\" */\n httpMethod: string;\n /** API path the tool will call, e.g. \"/api/projects\" */\n path: string;\n /** Human-readable description of what the tool does */\n description: string;\n };\n /** Resolved parameters the tool will be called with */\n params: Record<string, unknown>;\n /** Call to proceed with the tool execution */\n onConfirm: () => void;\n /** Call to abort without executing the tool */\n onCancel: () => void;\n }) => ReactNode;\n}\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeChat({\n position = \"bottom-right\",\n theme,\n welcomeMessage = \"Hi! I can help you navigate and use this app. What would you like to do?\",\n suggestedPrompts,\n defaultOpen = false,\n onToggle,\n onToolComplete,\n onMessageComplete,\n}: AIMeChatProps) {\n const [open, setOpen] = useState(defaultOpen);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // Track tool-result part IDs that have already fired onToolComplete\n const firedToolResults = useRef<Set<string>>(new Set());\n // Track the previous status to detect the streaming → ready transition\n const prevStatus = useRef<string | null>(null);\n const {\n messages,\n input,\n handleInputChange,\n handleSubmit,\n status,\n error,\n setInput,\n } = useAIMe();\n\n // Stable IDs for aria-labelledby / aria-describedby\n const titleId = useId();\n const messagesId = useId();\n\n const isInline = position === \"inline\";\n\n const toggleOpen = useCallback(() => {\n const next = !open;\n setOpen(next);\n onToggle?.(next);\n }, [open, onToggle]);\n\n // Keyboard shortcut: Cmd+. to toggle\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \".\") {\n e.preventDefault();\n toggleOpen();\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleOpen]);\n\n // Scroll to bottom on new messages\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n // Fire onToolComplete for each new tool-result part observed in messages.\n // We deduplicate by tracking the tool-call ID so the callback fires exactly\n // once per tool execution, even across re-renders during streaming.\n useEffect(() => {\n if (!onToolComplete) return;\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type !== \"tool-result\") continue;\n // Each tool-result part has a stable toolCallId\n const id = (part as { toolCallId?: string }).toolCallId;\n const dedupeKey = id ?? `${message.id}:${part.type}`;\n if (firedToolResults.current.has(dedupeKey)) continue;\n firedToolResults.current.add(dedupeKey);\n onToolComplete({\n name: (part as { toolName?: string }).toolName ?? \"\",\n result: (part as { result?: unknown }).result,\n });\n }\n }\n }, [messages, onToolComplete]);\n\n // Fire onMessageComplete when status transitions from streaming → ready.\n // prevStatus tracks the last seen status so we only fire on the transition.\n useEffect(() => {\n const prev = prevStatus.current;\n prevStatus.current = status;\n\n if (!onMessageComplete) return;\n // Only fire on the transition away from an active streaming state\n if (status !== \"ready\") return;\n if (prev !== \"streaming\" && prev !== \"submitted\") return;\n\n // Find the last assistant message\n // Walk backwards to find the most recent assistant message without copying the array\n let lastAssistant: (typeof messages)[number] | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"assistant\") { lastAssistant = messages[i]; break; }\n }\n if (!lastAssistant) return;\n\n const textContent = lastAssistant.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n\n const toolCalls: unknown[] = lastAssistant.parts.filter((p) => p.type === \"tool-call\");\n\n onMessageComplete({\n role: lastAssistant.role,\n content: textContent,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n });\n }, [status, messages, onMessageComplete]);\n\n // Focus panel when opened; return focus to trigger when closed\n useEffect(() => {\n if (open) {\n // Shift focus into the panel so screen readers announce the dialog\n panelRef.current?.focus();\n // Then move focus to the input after a tick so the panel focus is set first\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to the trigger that opened the panel\n triggerRef.current?.focus();\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the panel while open\n useEffect(() => {\n if (!open || isInline) return;\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n toggleOpen();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const panel = panelRef.current;\n if (!panel) return;\n\n const focusable = panel.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, isInline, toggleOpen]);\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n const panelStyle: CSSProperties = isInline\n ? {\n ...themeVars,\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n }\n : {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 380,\n height: \"70vh\",\n maxHeight: 600,\n display: open ? \"flex\" : \"none\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n boxShadow: \"var(--ai-me-shadow)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n zIndex: 9999,\n };\n\n const triggerStyle: CSSProperties = {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n cursor: \"pointer\",\n display: isInline || open ? \"none\" : \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"var(--ai-me-shadow)\",\n fontSize: 24,\n zIndex: 9999,\n };\n\n const isStreaming = status === \"submitted\" || status === \"streaming\";\n\n return (\n <>\n {/* Floating trigger button */}\n <button\n ref={triggerRef}\n onClick={toggleOpen}\n style={triggerStyle}\n aria-label=\"Open AI chat\"\n aria-expanded={open}\n aria-controls={isInline ? undefined : \"ai-me-chat-panel\"}\n type=\"button\"\n >\n {/* Icon is decorative; label is on the button */}\n <span aria-hidden=\"true\">💬</span>\n </button>\n\n {/* Chat panel */}\n <div\n id=\"ai-me-chat-panel\"\n ref={panelRef}\n style={panelStyle}\n role=\"dialog\"\n aria-modal={isInline ? undefined : \"true\"}\n aria-labelledby={titleId}\n aria-busy={isStreaming}\n // tabIndex={-1} allows programmatic focus on the panel element itself\n tabIndex={-1}\n >\n {/* Header */}\n <div\n style={{\n padding: \"12px 16px\",\n borderBottom: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n }}\n >\n <span id={titleId} style={{ fontWeight: 600, fontSize: 14 }}>\n AI Assistant\n </span>\n {!isInline && (\n <button\n onClick={toggleOpen}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: 18,\n color: \"var(--ai-me-text-secondary)\",\n padding: 4,\n borderRadius: 4,\n // Visible focus indicator without outline:none\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Close chat\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">✕</span>\n </button>\n )}\n </div>\n\n {/* Skip link: jump straight to the input */}\n <a\n href=\"#ai-me-chat-input\"\n style={{\n ...srOnly,\n // Reveal on focus so keyboard users can see it\n }}\n onFocus={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, {\n position: \"static\",\n width: \"auto\",\n height: \"auto\",\n padding: \"4px 8px\",\n margin: 0,\n overflow: \"visible\",\n clip: \"auto\",\n whiteSpace: \"normal\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n fontSize: 12,\n borderRadius: 4,\n });\n }}\n onBlur={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, srOnly);\n }}\n >\n Skip to message input\n </a>\n\n {/* Messages — live region so screen readers announce new content */}\n <div\n id={messagesId}\n aria-live=\"polite\"\n aria-label=\"Conversation\"\n aria-relevant=\"additions\"\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n }}\n >\n {messages.length === 0 && (\n <div style={{ color: \"var(--ai-me-text-secondary)\", fontSize: 14 }}>\n <p>{welcomeMessage}</p>\n {suggestedPrompts && suggestedPrompts.length > 0 && (\n <div\n style={{\n marginTop: 12,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 8,\n }}\n >\n <p style={{ margin: \"0 0 4px\", fontSize: 12, fontWeight: 500 }}>\n Suggested questions:\n </p>\n {suggestedPrompts.map((prompt) => (\n <button\n key={prompt}\n type=\"button\"\n onClick={() => {\n setInput(prompt);\n inputRef.current?.focus();\n }}\n style={{\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n background: \"var(--ai-me-bg)\",\n cursor: \"pointer\",\n textAlign: \"left\",\n fontSize: 13,\n color: \"var(--ai-me-text)\",\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {prompt}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {messages.map((m) => (\n <div\n key={m.id}\n style={{\n alignSelf: m.role === \"user\" ? \"flex-end\" : \"flex-start\",\n maxWidth: \"85%\",\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor:\n m.role === \"user\"\n ? \"var(--ai-me-primary)\"\n : \"var(--ai-me-bg-secondary)\",\n color: m.role === \"user\" ? \"#fff\" : \"var(--ai-me-text)\",\n fontSize: 14,\n lineHeight: 1.5,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n }}\n >\n {/* Screen reader role prefix */}\n <span style={srOnly}>\n {m.role === \"user\" ? \"You: \" : \"Assistant: \"}\n </span>\n {m.parts.map((p, i) =>\n p.type === \"text\" ? (\n <span key={i}>\n {m.role === \"assistant\"\n ? renderMarkdown(p.text)\n : p.text}\n </span>\n ) : null,\n )}\n </div>\n ))}\n\n {/* \"Thinking\" indicator — announced by the live region above */}\n {status === \"submitted\" && (\n <div\n aria-label=\"Assistant is thinking\"\n style={{\n alignSelf: \"flex-start\",\n color: \"var(--ai-me-text-secondary)\",\n fontSize: 13,\n }}\n >\n <span aria-hidden=\"true\">Thinking…</span>\n </div>\n )}\n\n {/* Error — role=\"alert\" ensures immediate announcement */}\n {error && (\n <div\n role=\"alert\"\n style={{\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor: \"#fef2f2\",\n // #dc2626 on #fef2f2 ≈ 5.1:1 — passes AA for normal text\n color: \"#dc2626\",\n fontSize: 13,\n border: \"1px solid #fca5a5\",\n }}\n >\n Something went wrong. Please try again.\n </div>\n )}\n\n <div ref={messagesEndRef} aria-hidden=\"true\" />\n </div>\n\n {/* Input */}\n <form\n onSubmit={handleSubmit}\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n gap: 8,\n }}\n >\n {/* Visible label for the input (positioned absolutely so only visible on focus for compact layout) */}\n <label\n htmlFor=\"ai-me-chat-input\"\n style={srOnly}\n >\n Message to AI Assistant\n </label>\n <input\n id=\"ai-me-chat-input\"\n ref={inputRef}\n value={input}\n onChange={handleInputChange}\n placeholder=\"Ask anything…\"\n disabled={status !== \"ready\"}\n aria-disabled={status !== \"ready\"}\n style={{\n flex: 1,\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n // Do NOT use outline:none — use outline with transparent color + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n />\n <button\n type=\"submit\"\n disabled={status !== \"ready\" || !input.trim()}\n aria-disabled={status !== \"ready\" || !input.trim()}\n style={{\n padding: \"8px 16px\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 8,\n cursor: status === \"ready\" && input.trim() ? \"pointer\" : \"not-allowed\",\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n opacity: status === \"ready\" && input.trim() ? 1 : 0.5,\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n (e.currentTarget as HTMLButtonElement).style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Send message\"\n >\n Send\n </button>\n </form>\n </div>\n </>\n );\n}\n","import { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useState, useCallback, useEffect, useRef } from \"react\";\nimport { useAIMeContext } from \"./context.js\";\n\nconst STORAGE_KEY = \"ai-me-messages\";\n\n/**\n * Hook wrapping AI SDK's useChat with AI-Me configuration.\n * Provides chat state, message handling, confirmation support,\n * and session persistence (survives page navigation within the same tab).\n */\nexport function useAIMe() {\n const { endpoint, headers } = useAIMeContext();\n const [input, setInput] = useState(\"\");\n const initialized = useRef(false);\n\n const chat = useChat({\n transport: new DefaultChatTransport({\n api: endpoint,\n headers,\n }),\n });\n\n // Restore messages from sessionStorage on mount\n useEffect(() => {\n if (initialized.current) return;\n initialized.current = true;\n\n try {\n const stored = sessionStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (Array.isArray(parsed) && parsed.length > 0) {\n chat.setMessages(parsed);\n }\n }\n } catch {\n // ignore — sessionStorage may be unavailable or corrupted\n }\n }, []);\n\n // Persist messages to sessionStorage on change\n useEffect(() => {\n if (!initialized.current) return;\n try {\n if (chat.messages.length > 0) {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(chat.messages));\n } else {\n sessionStorage.removeItem(STORAGE_KEY);\n }\n } catch {\n // ignore\n }\n }, [chat.messages]);\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setInput(e.target.value);\n },\n [],\n );\n\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n if (!input.trim()) return;\n chat.sendMessage({ text: input });\n setInput(\"\");\n },\n [input, chat],\n );\n\n const clearMessages = useCallback(() => {\n chat.setMessages([]);\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n }, [chat]);\n\n return {\n /** Conversation messages */\n messages: chat.messages,\n /** Current input value */\n input,\n /** Set input value */\n setInput,\n /** Handle input change */\n handleInputChange,\n /** Submit the current message */\n handleSubmit,\n /** Send a message directly */\n sendMessage: chat.sendMessage,\n /** Chat status: \"ready\" | \"submitted\" | \"streaming\" */\n status: chat.status,\n /** Error if any */\n error: chat.error,\n /** Stop streaming */\n stop: chat.stop,\n /** Set messages */\n setMessages: chat.setMessages,\n /** Clear all messages and session storage */\n clearMessages,\n };\n}\n","/**\n * CSS custom properties for AI-Me theming.\n * All prefixed with --ai-me- to avoid conflicts with host app styles.\n */\nexport const defaultThemeVars = {\n \"--ai-me-primary\": \"#6366f1\",\n \"--ai-me-primary-hover\": \"#4f46e5\",\n \"--ai-me-bg\": \"#ffffff\",\n \"--ai-me-bg-secondary\": \"#f9fafb\",\n \"--ai-me-text\": \"#111827\",\n \"--ai-me-text-secondary\": \"#6b7280\",\n \"--ai-me-border\": \"#e5e7eb\",\n \"--ai-me-radius\": \"12px\",\n \"--ai-me-font\": \"system-ui, -apple-system, sans-serif\",\n \"--ai-me-shadow\": \"0 4px 24px rgba(0, 0, 0, 0.12)\",\n} as const;\n\nexport interface AIMeTheme {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n}\n\nexport function themeToVars(theme?: AIMeTheme): Record<string, string> {\n if (!theme) return {};\n const vars: Record<string, string> = {};\n if (theme.primaryColor) vars[\"--ai-me-primary\"] = theme.primaryColor;\n if (theme.backgroundColor) vars[\"--ai-me-bg\"] = theme.backgroundColor;\n if (theme.textColor) vars[\"--ai-me-text\"] = theme.textColor;\n if (theme.borderRadius) vars[\"--ai-me-radius\"] = theme.borderRadius;\n if (theme.fontFamily) vars[\"--ai-me-font\"] = theme.fontFamily;\n return vars;\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\n/**\n * Lightweight inline markdown renderer for chat messages.\n * Supports: **bold**, *italic*, `code`, ```code blocks```, [links](url), - lists\n * No external dependencies — renders to React elements with inline styles.\n */\nexport function renderMarkdown(text: string): ReactNode[] {\n const lines = text.split(\"\\n\");\n const result: ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Fenced code block\n if (line.trimStart().startsWith(\"```\")) {\n const lang = line.trimStart().slice(3).trim();\n const codeLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].trimStart().startsWith(\"```\")) {\n codeLines.push(lines[i]);\n i++;\n }\n i++; // skip closing ```\n result.push(\n <pre\n key={`code-${result.length}`}\n style={codeBlockStyle}\n data-lang={lang || undefined}\n >\n <code>{codeLines.join(\"\\n\")}</code>\n </pre>,\n );\n continue;\n }\n\n // Unordered list item\n if (/^[\\s]*[-*]\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*[-*]\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*[-*]\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ul\n key={`ul-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20, listStyleType: \"disc\" }}\n >\n {listItems}\n </ul>,\n );\n continue;\n }\n\n // Ordered list item\n if (/^[\\s]*\\d+\\.\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*\\d+\\.\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*\\d+\\.\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ol\n key={`ol-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20 }}\n >\n {listItems}\n </ol>,\n );\n continue;\n }\n\n // Heading (clamp to h3+ in chat context)\n const headingMatch = /^(#{1,6})\\s+(.+)$/.exec(line);\n if (headingMatch) {\n const level = Math.max(headingMatch[1].length, 3);\n const fontSize =\n ({ 3: 15, 4: 14, 5: 13, 6: 13 } as Record<number, number>)[level] ??\n 14;\n result.push(\n <p\n key={`h-${result.length}`}\n style={{ fontWeight: 600, fontSize, margin: \"8px 0 4px\" }}\n >\n {renderInline(headingMatch[2])}\n </p>,\n );\n i++;\n continue;\n }\n\n // Empty line\n if (line.trim() === \"\") {\n i++;\n continue;\n }\n\n // Regular text\n result.push(\n <span\n key={`p-${result.length}`}\n style={{ display: \"block\", marginBottom: 2 }}\n >\n {renderInline(line)}\n </span>,\n );\n i++;\n }\n\n return result;\n}\n\n/** Parse inline markdown: bold, italic, code, links */\nfunction renderInline(text: string): ReactNode[] {\n const result: ReactNode[] = [];\n const pattern = /(`[^`]+`|\\*\\*[^*]+\\*\\*|\\*[^*]+\\*|\\[[^\\]]+\\]\\([^)]+\\))/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n if (match.index > lastIndex) {\n result.push(text.slice(lastIndex, match.index));\n }\n\n const token = match[0];\n\n if (token.startsWith(\"`\")) {\n result.push(\n <code key={result.length} style={inlineCodeStyle}>\n {token.slice(1, -1)}\n </code>,\n );\n } else if (token.startsWith(\"**\")) {\n result.push(\n <strong key={result.length}>{token.slice(2, -2)}</strong>,\n );\n } else if (token.startsWith(\"*\")) {\n result.push(<em key={result.length}>{token.slice(1, -1)}</em>);\n } else if (token.startsWith(\"[\")) {\n const linkMatch = /\\[([^\\]]+)\\]\\(([^)]+)\\)/.exec(token);\n if (linkMatch) {\n result.push(\n <a\n key={result.length}\n href={linkMatch[2]}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={linkStyle}\n >\n {linkMatch[1]}\n </a>,\n );\n }\n }\n\n lastIndex = match.index + token.length;\n }\n\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return result;\n}\n\nconst codeBlockStyle: CSSProperties = {\n margin: \"6px 0\",\n padding: \"10px 12px\",\n borderRadius: 6,\n backgroundColor: \"rgba(0,0,0,0.15)\",\n fontSize: 12,\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n overflow: \"auto\",\n whiteSpace: \"pre\",\n lineHeight: 1.5,\n};\n\nconst inlineCodeStyle: CSSProperties = {\n padding: \"1px 5px\",\n borderRadius: 3,\n backgroundColor: \"rgba(0,0,0,0.12)\",\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: \"0.9em\",\n};\n\nconst linkStyle: CSSProperties = {\n color: \"var(--ai-me-primary, #6366f1)\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n};\n","import { useState, useEffect, useRef, useCallback, useId } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { useAIMe } from \"./use-ai-me.js\";\n\nexport interface AIMeCommandPaletteProps {\n /** List of available commands/actions */\n commands?: CommandItem[];\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Custom keyboard shortcut (default: Cmd+K / Ctrl+K) */\n shortcut?: { key: string; meta?: boolean; ctrl?: boolean };\n /** Callback when palette opens/closes */\n onToggle?: (open: boolean) => void;\n}\n\nexport interface CommandItem {\n /** Unique command ID */\n id: string;\n /** Display label */\n label: string;\n /** Description shown below label */\n description?: string;\n /** Category for grouping */\n category?: string;\n /** Icon (emoji or text) */\n icon?: string;\n /** Action to run — either a callback or a prompt to send to AI */\n action: (() => void) | string;\n}\n\nconst defaultCommands: CommandItem[] = [\n {\n id: \"help\",\n label: \"Ask AI for help\",\n description: \"Get assistance with any task\",\n category: \"AI\",\n icon: \"💡\",\n action: \"What can you help me with?\",\n },\n {\n id: \"list-actions\",\n label: \"List available actions\",\n description: \"Show all API actions the AI can perform\",\n category: \"AI\",\n icon: \"📋\",\n action: \"What actions can you perform? List them all.\",\n },\n {\n id: \"recent-activity\",\n label: \"Show recent activity\",\n description: \"Summarize recent actions and changes\",\n category: \"AI\",\n icon: \"🕐\",\n action: \"What has happened recently? Summarize recent activity.\",\n },\n];\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeCommandPalette({\n commands = defaultCommands,\n theme,\n shortcut = { key: \"k\", meta: true },\n onToggle,\n}: AIMeCommandPaletteProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n // Remember what had focus before the palette opened so we can restore it\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const { sendMessage } = useAIMe();\n\n // Stable IDs\n const titleId = useId();\n const inputId = useId();\n\n const toggle = useCallback(\n (next: boolean) => {\n setOpen(next);\n setQuery(\"\");\n setSelectedIndex(0);\n onToggle?.(next);\n },\n [onToggle],\n );\n\n // Keyboard shortcut to open\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n const metaMatch = shortcut.meta ? e.metaKey : true;\n const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;\n if ((metaMatch || ctrlMatch) && e.key === shortcut.key) {\n e.preventDefault();\n // Capture current focus before opening\n if (!open) {\n previousFocusRef.current = document.activeElement as HTMLElement;\n }\n toggle(!open);\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, shortcut, toggle]);\n\n // Focus the search input when opened; restore focus when closed\n useEffect(() => {\n if (open) {\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to whatever had it before the palette opened\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n previousFocusRef.current = null;\n }\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the palette while open\n useEffect(() => {\n if (!open) return;\n\n function handleFocusTrap(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleFocusTrap);\n return () => window.removeEventListener(\"keydown\", handleFocusTrap);\n }, [open]);\n\n // Filter commands by query\n const filtered = query.trim()\n ? commands.filter(\n (cmd) =>\n cmd.label.toLowerCase().includes(query.toLowerCase()) ||\n cmd.description?.toLowerCase().includes(query.toLowerCase()) ||\n cmd.category?.toLowerCase().includes(query.toLowerCase()),\n )\n : commands;\n\n // Clamp selected index\n useEffect(() => {\n if (selectedIndex >= filtered.length) {\n setSelectedIndex(Math.max(0, filtered.length - 1));\n }\n }, [filtered.length, selectedIndex]);\n\n // Scroll selected item into view\n useEffect(() => {\n const list = listRef.current;\n if (!list) return;\n const selected = list.children[selectedIndex] as HTMLElement | undefined;\n selected?.scrollIntoView({ block: \"nearest\" });\n }, [selectedIndex]);\n\n function executeCommand(cmd: CommandItem) {\n toggle(false);\n if (typeof cmd.action === \"string\") {\n sendMessage({ text: cmd.action });\n } else {\n cmd.action();\n }\n }\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.min(prev + 1, filtered.length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.max(prev - 1, 0));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (filtered[selectedIndex]) {\n executeCommand(filtered[selectedIndex]);\n } else if (query.trim()) {\n // Send raw query as AI prompt\n toggle(false);\n sendMessage({ text: query });\n }\n } else if (e.key === \"Escape\") {\n toggle(false);\n }\n }\n\n if (!open) return null;\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n // Group by category\n const grouped = new Map<string, CommandItem[]>();\n for (const cmd of filtered) {\n const cat = cmd.category ?? \"Actions\";\n if (!grouped.has(cat)) grouped.set(cat, []);\n grouped.get(cat)!.push(cmd);\n }\n\n let flatIndex = 0;\n\n return (\n <>\n {/* Backdrop — keyboard-dismissable via Escape (handled in handleKeyDown) */}\n <div\n onClick={() => toggle(false)}\n style={{\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n zIndex: 99998,\n }}\n // aria-hidden so screen readers go straight to the dialog\n aria-hidden=\"true\"\n />\n\n {/* Palette dialog */}\n <div\n ref={dialogRef}\n style={{\n ...themeVars,\n position: \"fixed\",\n top: \"20%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n width: \"min(520px, 90vw)\",\n maxHeight: \"60vh\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n boxShadow: \"0 24px 48px rgba(0,0,0,0.3)\",\n overflow: \"hidden\",\n zIndex: 99999,\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n // tabIndex={-1} so the dialog element itself can receive programmatic focus\n tabIndex={-1}\n >\n {/* Visually hidden dialog title for screen readers */}\n <h2 id={titleId} style={srOnly}>\n Command Palette\n </h2>\n\n {/* Search input */}\n <div style={{ padding: \"12px 16px\", borderBottom: \"1px solid var(--ai-me-border)\" }}>\n <label htmlFor={inputId} style={srOnly}>\n Search commands or ask AI\n </label>\n <input\n id={inputId}\n ref={inputRef}\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setSelectedIndex(0);\n }}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a command or ask AI...\"\n style={{\n width: \"100%\",\n padding: \"8px 0\",\n border: \"none\",\n // Do NOT suppress the outline entirely — use transparent + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n fontSize: 15,\n fontFamily: \"var(--ai-me-font)\",\n backgroundColor: \"transparent\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"ai-me-cmd-listbox\"\n aria-activedescendant={\n filtered[selectedIndex]\n ? `cmd-${filtered[selectedIndex].id}`\n : undefined\n }\n />\n </div>\n\n {/* Results listbox */}\n <div\n id=\"ai-me-cmd-listbox\"\n ref={listRef}\n style={{ overflowY: \"auto\", padding: \"8px 0\" }}\n role=\"listbox\"\n aria-label=\"Commands\"\n >\n {filtered.length === 0 && query.trim() && (\n <div\n role=\"option\"\n aria-selected=\"false\"\n style={{\n padding: \"16px\",\n textAlign: \"center\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n Press Enter to ask AI: “{query}”\n </div>\n )}\n\n {Array.from(grouped.entries()).map(([category, items]) => (\n // role=\"group\" with aria-label for the category heading\n <div key={category} role=\"group\" aria-label={category}>\n {/* Category heading — aria-hidden because role=\"group\" aria-label carries the name */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"6px 16px 4px\",\n fontSize: 11,\n fontWeight: 500,\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {category}\n </div>\n {items.map((cmd) => {\n const idx = flatIndex++;\n const isSelected = idx === selectedIndex;\n return (\n <div\n key={cmd.id}\n id={`cmd-${cmd.id}`}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => executeCommand(cmd)}\n onMouseEnter={() => setSelectedIndex(idx)}\n // Allow keyboard activation of each option when it has focus\n tabIndex={isSelected ? 0 : -1}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n executeCommand(cmd);\n }\n }}\n style={{\n padding: \"8px 16px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: isSelected\n ? \"var(--ai-me-bg-secondary)\"\n : \"transparent\",\n outline: \"2px solid transparent\",\n outlineOffset: -2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {cmd.icon && (\n // Icon is decorative — label comes from cmd.label\n <span aria-hidden=\"true\" style={{ fontSize: 16, flexShrink: 0 }}>\n {cmd.icon}\n </span>\n )}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontSize: 14, fontWeight: 500 }}>\n {cmd.label}\n </div>\n {cmd.description && (\n <div\n style={{\n fontSize: 12,\n color: \"var(--ai-me-text-secondary)\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {cmd.description}\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n\n {/* Footer keyboard hints — aria-hidden because these are redundant for screen readers\n (keyboard shortcuts are announced via aria-keyshortcuts on the input) */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"8px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n fontSize: 11,\n color: \"var(--ai-me-text-secondary)\",\n display: \"flex\",\n gap: 16,\n }}\n >\n <span>↑↓ Navigate</span>\n <span>↵ Select</span>\n <span>Esc Close</span>\n </div>\n </div>\n </>\n );\n}\n","import { useRef, useEffect, useId, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars } from \"./styles.js\";\n\nexport interface AIMeConfirmProps {\n /** Tool/action name */\n action: string;\n /** Description of what will happen */\n description: string;\n /** Parameters being sent */\n parameters?: Record<string, unknown>;\n /** Callback when user confirms */\n onConfirm: () => void;\n /** Callback when user rejects */\n onReject: () => void;\n}\n\nexport function AIMeConfirm({\n action,\n description,\n parameters,\n onConfirm,\n onReject,\n}: AIMeConfirmProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n\n // Stable IDs for ARIA associations\n const titleId = useId();\n const descriptionId = useId();\n\n // Close on Escape and focus-trap within the dialog\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onReject();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onReject],\n );\n\n // Auto-focus the Cancel button when the dialog mounts (safe default for\n // destructive confirmations — avoids accidental confirmation on Enter).\n // Also wire up Escape / focus-trap and restore focus on unmount.\n useEffect(() => {\n const previousFocus = document.activeElement as HTMLElement | null;\n\n cancelButtonRef.current?.focus();\n window.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n // Restore focus to whatever triggered the dialog\n previousFocus?.focus();\n };\n }, [handleKeyDown]);\n\n const overlayStyle: CSSProperties = {\n ...defaultThemeVars,\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.4)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10000,\n fontFamily: \"var(--ai-me-font)\",\n } as CSSProperties;\n\n const dialogStyle: CSSProperties = {\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n padding: 24,\n maxWidth: 420,\n width: \"90%\",\n boxShadow: \"var(--ai-me-shadow)\",\n color: \"var(--ai-me-text)\",\n };\n\n const focusStyle: CSSProperties = {\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n };\n\n function applyFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid var(--ai-me-primary)\";\n el.style.outlineOffset = \"2px\";\n }\n\n function removeFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid transparent\";\n el.style.outlineOffset = \"2px\";\n }\n\n return (\n // Overlay is presentational — role and aria go on the inner dialog\n <div\n style={overlayStyle}\n // Clicking outside the dialog rejects (same as pressing Escape)\n onClick={(e) => {\n if (e.target === e.currentTarget) onReject();\n }}\n aria-hidden=\"false\"\n >\n <div\n ref={dialogRef}\n style={dialogStyle}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n // tabIndex={-1} allows programmatic focus on the dialog element itself\n tabIndex={-1}\n // Prevent clicks inside the dialog from bubbling to the overlay\n onClick={(e) => e.stopPropagation()}\n >\n <h3 id={titleId} style={{ margin: \"0 0 8px\", fontSize: 16 }}>\n Confirm Action\n </h3>\n <p style={{ margin: \"0 0 4px\", fontSize: 14, fontWeight: 600 }}>\n {action}\n </p>\n <p\n id={descriptionId}\n style={{\n margin: \"0 0 16px\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {description}\n </p>\n\n {parameters && Object.keys(parameters).length > 0 && (\n <pre\n style={{\n margin: \"0 0 16px\",\n padding: 12,\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n borderRadius: 8,\n fontSize: 12,\n overflow: \"auto\",\n maxHeight: 200,\n border: \"1px solid var(--ai-me-border)\",\n }}\n >\n {JSON.stringify(parameters, null, 2)}\n </pre>\n )}\n\n <div style={{ display: \"flex\", gap: 8, justifyContent: \"flex-end\" }}>\n {/* Cancel is focused first — avoids accidental confirmation */}\n <button\n ref={cancelButtonRef}\n type=\"button\"\n onClick={onReject}\n style={{\n padding: \"8px 16px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n style={{\n padding: \"8px 16px\",\n border: \"none\",\n borderRadius: 8,\n // #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Confirm\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA0C;AAuBnC,IAAM,kBAAc,4BAAuC,IAAI;AAE/D,SAAS,iBAAmC;AACjD,QAAM,UAAM,yBAAW,WAAW;AAClC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,SAAO;AACT;;;ACOI;AAFG,SAAS,aAAa,EAAE,UAAU,SAAS,UAAU,SAAS,GAAsB;AACzF,SACE,4CAAC,eAAY,OAAO,EAAE,UAAU,SAAS,SAAS,GAC/C,UACH;AAEJ;;;AC1CA,IAAAA,gBAAgE;;;ACAhE,IAAAC,gBAAwB;AACxB,gBAAqC;AACrC,IAAAA,gBAAyD;AAGzD,IAAM,cAAc;AAOb,SAAS,UAAU;AACxB,QAAM,EAAE,UAAU,QAAQ,IAAI,eAAe;AAC7C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,kBAAc,sBAAO,KAAK;AAEhC,QAAM,WAAO,uBAAQ;AAAA,IACnB,WAAW,IAAI,+BAAqB;AAAA,MAClC,KAAK;AAAA,MACL;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAGD,+BAAU,MAAM;AACd,QAAI,YAAY,QAAS;AACzB,gBAAY,UAAU;AAEtB,QAAI;AACF,YAAM,SAAS,eAAe,QAAQ,WAAW;AACjD,UAAI,QAAQ;AACV,cAAM,SAAS,KAAK,MAAM,MAAM;AAChC,YAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,GAAG;AAC9C,eAAK,YAAY,MAAM;AAAA,QACzB;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,+BAAU,MAAM;AACd,QAAI,CAAC,YAAY,QAAS;AAC1B,QAAI;AACF,UAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,uBAAe,QAAQ,aAAa,KAAK,UAAU,KAAK,QAAQ,CAAC;AAAA,MACnE,OAAO;AACL,uBAAe,WAAW,WAAW;AAAA,MACvC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,KAAK,QAAQ,CAAC;AAElB,QAAM,wBAAoB;AAAA,IACxB,CAAC,MAAiE;AAChE,eAAS,EAAE,OAAO,KAAK;AAAA,IACzB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,mBAAe;AAAA,IACnB,CAAC,MAAwB;AACvB,SAAG,eAAe;AAClB,UAAI,CAAC,MAAM,KAAK,EAAG;AACnB,WAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AAChC,eAAS,EAAE;AAAA,IACb;AAAA,IACA,CAAC,OAAO,IAAI;AAAA,EACd;AAEA,QAAM,oBAAgB,2BAAY,MAAM;AACtC,SAAK,YAAY,CAAC,CAAC;AACnB,QAAI;AACF,qBAAe,WAAW,WAAW;AAAA,IACvC,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,SAAO;AAAA;AAAA,IAEL,UAAU,KAAK;AAAA;AAAA,IAEf;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA,aAAa,KAAK;AAAA;AAAA,IAElB,QAAQ,KAAK;AAAA;AAAA,IAEb,OAAO,KAAK;AAAA;AAAA,IAEZ,MAAM,KAAK;AAAA;AAAA,IAEX,aAAa,KAAK;AAAA;AAAA,IAElB;AAAA,EACF;AACF;;;ACtGO,IAAM,mBAAmB;AAAA,EAC9B,mBAAmB;AAAA,EACnB,yBAAyB;AAAA,EACzB,cAAc;AAAA,EACd,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,0BAA0B;AAAA,EAC1B,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,kBAAkB;AACpB;AAUO,SAAS,YAAY,OAA2C;AACrE,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,OAA+B,CAAC;AACtC,MAAI,MAAM,aAAc,MAAK,iBAAiB,IAAI,MAAM;AACxD,MAAI,MAAM,gBAAiB,MAAK,YAAY,IAAI,MAAM;AACtD,MAAI,MAAM,UAAW,MAAK,cAAc,IAAI,MAAM;AAClD,MAAI,MAAM,aAAc,MAAK,gBAAgB,IAAI,MAAM;AACvD,MAAI,MAAM,WAAY,MAAK,cAAc,IAAI,MAAM;AACnD,SAAO;AACT;;;ACHU,IAAAC,sBAAA;AAxBH,SAAS,eAAe,MAA2B;AACxD,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,QAAM,SAAsB,CAAC;AAC7B,MAAI,IAAI;AAER,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,OAAO,MAAM,CAAC;AAGpB,QAAI,KAAK,UAAU,EAAE,WAAW,KAAK,GAAG;AACtC,YAAM,OAAO,KAAK,UAAU,EAAE,MAAM,CAAC,EAAE,KAAK;AAC5C,YAAM,YAAsB,CAAC;AAC7B;AACA,aAAO,IAAI,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,WAAW,KAAK,GAAG;AAClE,kBAAU,KAAK,MAAM,CAAC,CAAC;AACvB;AAAA,MACF;AACA;AACA,aAAO;AAAA,QACL;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO;AAAA,YACP,aAAW,QAAQ;AAAA,YAEnB,uDAAC,UAAM,oBAAU,KAAK,IAAI,GAAE;AAAA;AAAA,UAJvB,QAAQ,OAAO,MAAM;AAAA,QAK5B;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,YAAM,YAAyB,CAAC;AAChC,aAAO,IAAI,MAAM,UAAU,eAAe,KAAK,MAAM,CAAC,CAAC,GAAG;AACxD,kBAAU;AAAA,UACR,6CAAC,QAA0B,OAAO,EAAE,cAAc,EAAE,GACjD,uBAAa,MAAM,CAAC,EAAE,QAAQ,gBAAgB,EAAE,CAAC,KAD3C,UAAU,MAEnB;AAAA,QACF;AACA;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,EAAE,QAAQ,SAAS,aAAa,IAAI,eAAe,OAAO;AAAA,YAEhE;AAAA;AAAA,UAHI,MAAM,OAAO,MAAM;AAAA,QAI1B;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,gBAAgB,KAAK,IAAI,GAAG;AAC9B,YAAM,YAAyB,CAAC;AAChC,aAAO,IAAI,MAAM,UAAU,gBAAgB,KAAK,MAAM,CAAC,CAAC,GAAG;AACzD,kBAAU;AAAA,UACR,6CAAC,QAA0B,OAAO,EAAE,cAAc,EAAE,GACjD,uBAAa,MAAM,CAAC,EAAE,QAAQ,iBAAiB,EAAE,CAAC,KAD5C,UAAU,MAEnB;AAAA,QACF;AACA;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,EAAE,QAAQ,SAAS,aAAa,GAAG;AAAA,YAEzC;AAAA;AAAA,UAHI,MAAM,OAAO,MAAM;AAAA,QAI1B;AAAA,MACF;AACA;AAAA,IACF;AAGA,UAAM,eAAe,oBAAoB,KAAK,IAAI;AAClD,QAAI,cAAc;AAChB,YAAM,QAAQ,KAAK,IAAI,aAAa,CAAC,EAAE,QAAQ,CAAC;AAChD,YAAM,WACH,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,EAA6B,KAAK,KAChE;AACF,aAAO;AAAA,QACL;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,EAAE,YAAY,KAAK,UAAU,QAAQ,YAAY;AAAA,YAEvD,uBAAa,aAAa,CAAC,CAAC;AAAA;AAAA,UAHxB,KAAK,OAAO,MAAM;AAAA,QAIzB;AAAA,MACF;AACA;AACA;AAAA,IACF;AAGA,QAAI,KAAK,KAAK,MAAM,IAAI;AACtB;AACA;AAAA,IACF;AAGA,WAAO;AAAA,MACL;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO,EAAE,SAAS,SAAS,cAAc,EAAE;AAAA,UAE1C,uBAAa,IAAI;AAAA;AAAA,QAHb,KAAK,OAAO,MAAM;AAAA,MAIzB;AAAA,IACF;AACA;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,aAAa,MAA2B;AAC/C,QAAM,SAAsB,CAAC;AAC7B,QAAM,UAAU;AAChB,MAAI,YAAY;AAChB,MAAI;AAEJ,UAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;AAC5C,QAAI,MAAM,QAAQ,WAAW;AAC3B,aAAO,KAAK,KAAK,MAAM,WAAW,MAAM,KAAK,CAAC;AAAA,IAChD;AAEA,UAAM,QAAQ,MAAM,CAAC;AAErB,QAAI,MAAM,WAAW,GAAG,GAAG;AACzB,aAAO;AAAA,QACL,6CAAC,UAAyB,OAAO,iBAC9B,gBAAM,MAAM,GAAG,EAAE,KADT,OAAO,MAElB;AAAA,MACF;AAAA,IACF,WAAW,MAAM,WAAW,IAAI,GAAG;AACjC,aAAO;AAAA,QACL,6CAAC,YAA4B,gBAAM,MAAM,GAAG,EAAE,KAAjC,OAAO,MAA4B;AAAA,MAClD;AAAA,IACF,WAAW,MAAM,WAAW,GAAG,GAAG;AAChC,aAAO,KAAK,6CAAC,QAAwB,gBAAM,MAAM,GAAG,EAAE,KAAjC,OAAO,MAA4B,CAAK;AAAA,IAC/D,WAAW,MAAM,WAAW,GAAG,GAAG;AAChC,YAAM,YAAY,0BAA0B,KAAK,KAAK;AACtD,UAAI,WAAW;AACb,eAAO;AAAA,UACL;AAAA,YAAC;AAAA;AAAA,cAEC,MAAM,UAAU,CAAC;AAAA,cACjB,QAAO;AAAA,cACP,KAAI;AAAA,cACJ,OAAO;AAAA,cAEN,oBAAU,CAAC;AAAA;AAAA,YANP,OAAO;AAAA,UAOd;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,gBAAY,MAAM,QAAQ,MAAM;AAAA,EAClC;AAEA,MAAI,YAAY,KAAK,QAAQ;AAC3B,WAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAAA,EACnC;AAEA,SAAO;AACT;AAEA,IAAM,iBAAgC;AAAA,EACpC,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,YACE;AAAA,EACF,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AACd;AAEA,IAAM,kBAAiC;AAAA,EACrC,SAAS;AAAA,EACT,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,YACE;AAAA,EACF,UAAU;AACZ;AAEA,IAAM,YAA2B;AAAA,EAC/B,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,qBAAqB;AACvB;;;AHwII,IAAAC,sBAAA;AA/OJ,IAAM,SAAwB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,SAAS,SAAS;AAAA,EACvB,WAAW;AAAA,EACX;AAAA,EACA,iBAAiB;AAAA,EACjB;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,WAAW;AAC5C,QAAM,qBAAiB,sBAAuB,IAAI;AAClD,QAAM,eAAW,sBAAyB,IAAI;AAC9C,QAAM,eAAW,sBAAuB,IAAI;AAC5C,QAAM,iBAAa,sBAA0B,IAAI;AAEjD,QAAM,uBAAmB,sBAAoB,oBAAI,IAAI,CAAC;AAEtD,QAAM,iBAAa,sBAAsB,IAAI;AAC7C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,QAAQ;AAGZ,QAAM,cAAU,qBAAM;AACtB,QAAM,iBAAa,qBAAM;AAEzB,QAAM,WAAW,aAAa;AAE9B,QAAM,iBAAa,2BAAY,MAAM;AACnC,UAAM,OAAO,CAAC;AACd,YAAQ,IAAI;AACZ,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,MAAM,QAAQ,CAAC;AAGnB,+BAAU,MAAM;AACd,aAAS,cAAc,GAAkB;AACvC,WAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,KAAK;AAC7C,UAAE,eAAe;AACjB,mBAAW;AAAA,MACb;AAAA,IACF;AACA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,UAAU,CAAC;AAGf,+BAAU,MAAM;AACd,mBAAe,SAAS,eAAe,EAAE,UAAU,SAAS,CAAC;AAAA,EAC/D,GAAG,CAAC,QAAQ,CAAC;AAKb,+BAAU,MAAM;AACd,QAAI,CAAC,eAAgB;AACrB,eAAW,WAAW,UAAU;AAC9B,iBAAW,QAAQ,QAAQ,OAAO;AAChC,YAAI,KAAK,SAAS,cAAe;AAEjC,cAAM,KAAM,KAAiC;AAC7C,cAAM,YAAY,MAAM,GAAG,QAAQ,EAAE,IAAI,KAAK,IAAI;AAClD,YAAI,iBAAiB,QAAQ,IAAI,SAAS,EAAG;AAC7C,yBAAiB,QAAQ,IAAI,SAAS;AACtC,uBAAe;AAAA,UACb,MAAO,KAA+B,YAAY;AAAA,UAClD,QAAS,KAA8B;AAAA,QACzC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,cAAc,CAAC;AAI7B,+BAAU,MAAM;AACd,UAAM,OAAO,WAAW;AACxB,eAAW,UAAU;AAErB,QAAI,CAAC,kBAAmB;AAExB,QAAI,WAAW,QAAS;AACxB,QAAI,SAAS,eAAe,SAAS,YAAa;AAIlD,QAAI;AACJ,aAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAI,SAAS,CAAC,EAAE,SAAS,aAAa;AAAE,wBAAgB,SAAS,CAAC;AAAG;AAAA,MAAO;AAAA,IAC9E;AACA,QAAI,CAAC,cAAe;AAEpB,UAAM,cAAc,cAAc,MAC/B,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAuB,IAAI,EACvC,KAAK,EAAE;AAEV,UAAM,YAAuB,cAAc,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AAErF,sBAAkB;AAAA,MAChB,MAAM,cAAc;AAAA,MACpB,SAAS;AAAA,MACT,WAAW,UAAU,SAAS,IAAI,YAAY;AAAA,IAChD,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,UAAU,iBAAiB,CAAC;AAGxC,+BAAU,MAAM;AACd,QAAI,MAAM;AAER,eAAS,SAAS,MAAM;AAExB,iBAAW,MAAM,SAAS,SAAS,MAAM,GAAG,CAAC;AAAA,IAC/C,OAAO;AAEL,iBAAW,SAAS,MAAM;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAGT,+BAAU,MAAM;AACd,QAAI,CAAC,QAAQ,SAAU;AAEvB,aAAS,cAAc,GAAkB;AACvC,UAAI,EAAE,QAAQ,UAAU;AACtB,UAAE,eAAe;AACjB,mBAAW;AACX;AAAA,MACF;AAEA,UAAI,EAAE,QAAQ,MAAO;AACrB,YAAM,QAAQ,SAAS;AACvB,UAAI,CAAC,MAAO;AAEZ,YAAM,YAAY,MAAM;AAAA,QACtB;AAAA,MACF;AACA,UAAI,UAAU,WAAW,EAAG;AAE5B,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAE3C,UAAI,EAAE,UAAU;AACd,YAAI,SAAS,kBAAkB,OAAO;AACpC,YAAE,eAAe;AACjB,eAAK,MAAM;AAAA,QACb;AAAA,MACF,OAAO;AACL,YAAI,SAAS,kBAAkB,MAAM;AACnC,YAAE,eAAe;AACjB,gBAAM,MAAM;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,EAClE,GAAG,CAAC,MAAM,UAAU,UAAU,CAAC;AAE/B,QAAM,YAA2B;AAAA,IAC/B,GAAG;AAAA,IACH,GAAG,YAAY,KAAK;AAAA,EACtB;AAEA,QAAM,aAA4B,WAC9B;AAAA,IACE,GAAG;AAAA,IACH,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,IACA;AAAA,IACE,GAAG;AAAA,IACH,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,GAAI,aAAa,iBAAiB,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,GAAG;AAAA,IAC7D,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,SAAS,OAAO,SAAS;AAAA,IACzB,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAEJ,QAAM,eAA8B;AAAA,IAClC,GAAG;AAAA,IACH,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,GAAI,aAAa,iBAAiB,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,GAAG;AAAA,IAC7D,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS,YAAY,OAAO,SAAS;AAAA,IACrC,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAEA,QAAM,cAAc,WAAW,eAAe,WAAW;AAEzD,SACE,8EAEE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,QACP,cAAW;AAAA,QACX,iBAAe;AAAA,QACf,iBAAe,WAAW,SAAY;AAAA,QACtC,MAAK;AAAA,QAGL,uDAAC,UAAK,eAAY,QAAO,uBAAE;AAAA;AAAA,IAC7B;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,IAAG;AAAA,QACH,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAK;AAAA,QACL,cAAY,WAAW,SAAY;AAAA,QACnC,mBAAiB;AAAA,QACjB,aAAW;AAAA,QAEX,UAAU;AAAA,QAGV;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,gBAAgB;AAAA,gBAChB,iBAAiB;AAAA,cACnB;AAAA,cAEA;AAAA,6DAAC,UAAK,IAAI,SAAS,OAAO,EAAE,YAAY,KAAK,UAAU,GAAG,GAAG,0BAE7D;AAAA,gBACC,CAAC,YACA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAS;AAAA,oBACT,OAAO;AAAA,sBACL,YAAY;AAAA,sBACZ,QAAQ;AAAA,sBACR,QAAQ;AAAA,sBACR,UAAU;AAAA,sBACV,OAAO;AAAA,sBACP,SAAS;AAAA,sBACT,cAAc;AAAA;AAAA,sBAEd,SAAS;AAAA,sBACT,eAAe;AAAA,oBACjB;AAAA,oBACA,SAAS,CAAC,MAAM;AACd,sBAAC,EAAE,cAAoC,MAAM,UAC3C;AAAA,oBACJ;AAAA,oBACA,QAAQ,CAAC,MAAM;AACb,sBAAC,EAAE,cAAoC,MAAM,UAC3C;AAAA,oBACJ;AAAA,oBACA,cAAW;AAAA,oBACX,MAAK;AAAA,oBAEL,uDAAC,UAAK,eAAY,QAAO,oBAAC;AAAA;AAAA,gBAC5B;AAAA;AAAA;AAAA,UAEJ;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAO;AAAA,gBACL,GAAG;AAAA;AAAA,cAEL;AAAA,cACA,SAAS,CAAC,MAAM;AACd,uBAAO,OAAQ,EAAE,cAAoC,OAAO;AAAA,kBAC1D,UAAU;AAAA,kBACV,OAAO;AAAA,kBACP,QAAQ;AAAA,kBACR,SAAS;AAAA,kBACT,QAAQ;AAAA,kBACR,UAAU;AAAA,kBACV,MAAM;AAAA,kBACN,YAAY;AAAA,kBACZ,iBAAiB;AAAA,kBACjB,OAAO;AAAA,kBACP,UAAU;AAAA,kBACV,cAAc;AAAA,gBAChB,CAAC;AAAA,cACH;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,uBAAO,OAAQ,EAAE,cAAoC,OAAO,MAAM;AAAA,cACpE;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,IAAI;AAAA,cACJ,aAAU;AAAA,cACV,cAAW;AAAA,cACX,iBAAc;AAAA,cACd,OAAO;AAAA,gBACL,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,SAAS;AAAA,gBACT,SAAS;AAAA,gBACT,eAAe;AAAA,gBACf,KAAK;AAAA,cACP;AAAA,cAEC;AAAA,yBAAS,WAAW,KACnB,8CAAC,SAAI,OAAO,EAAE,OAAO,+BAA+B,UAAU,GAAG,GAC/D;AAAA,+DAAC,OAAG,0BAAe;AAAA,kBAClB,oBAAoB,iBAAiB,SAAS,KAC7C;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,wBACL,WAAW;AAAA,wBACX,SAAS;AAAA,wBACT,eAAe;AAAA,wBACf,KAAK;AAAA,sBACP;AAAA,sBAEA;AAAA,qEAAC,OAAE,OAAO,EAAE,QAAQ,WAAW,UAAU,IAAI,YAAY,IAAI,GAAG,kCAEhE;AAAA,wBACC,iBAAiB,IAAI,CAAC,WACrB;AAAA,0BAAC;AAAA;AAAA,4BAEC,MAAK;AAAA,4BACL,SAAS,MAAM;AACb,uCAAS,MAAM;AACf,uCAAS,SAAS,MAAM;AAAA,4BAC1B;AAAA,4BACA,OAAO;AAAA,8BACL,SAAS;AAAA,8BACT,QAAQ;AAAA,8BACR,cAAc;AAAA,8BACd,YAAY;AAAA,8BACZ,QAAQ;AAAA,8BACR,WAAW;AAAA,8BACX,UAAU;AAAA,8BACV,OAAO;AAAA,8BACP,SAAS;AAAA,8BACT,eAAe;AAAA,4BACjB;AAAA,4BACA,SAAS,CAAC,MAAM;AACd,8BAAC,EAAE,cAAoC,MAAM,UAC3C;AAAA,4BACJ;AAAA,4BACA,QAAQ,CAAC,MAAM;AACb,8BAAC,EAAE,cAAoC,MAAM,UAC3C;AAAA,4BACJ;AAAA,4BAEC;AAAA;AAAA,0BA3BI;AAAA,wBA4BP,CACD;AAAA;AAAA;AAAA,kBACH;AAAA,mBAEJ;AAAA,gBAGD,SAAS,IAAI,CAAC,MACb;AAAA,kBAAC;AAAA;AAAA,oBAEC,OAAO;AAAA,sBACL,WAAW,EAAE,SAAS,SAAS,aAAa;AAAA,sBAC5C,UAAU;AAAA,sBACV,SAAS;AAAA,sBACT,cAAc;AAAA,sBACd,iBACE,EAAE,SAAS,SACP,yBACA;AAAA,sBACN,OAAO,EAAE,SAAS,SAAS,SAAS;AAAA,sBACpC,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,YAAY;AAAA,sBACZ,WAAW;AAAA,oBACb;AAAA,oBAGA;AAAA,mEAAC,UAAK,OAAO,QACV,YAAE,SAAS,SAAS,UAAU,eACjC;AAAA,sBACC,EAAE,MAAM;AAAA,wBAAI,CAAC,GAAG,MACf,EAAE,SAAS,SACT,6CAAC,UACE,YAAE,SAAS,cACR,eAAe,EAAE,IAAI,IACrB,EAAE,QAHG,CAIX,IACE;AAAA,sBACN;AAAA;AAAA;AAAA,kBA7BK,EAAE;AAAA,gBA8BT,CACD;AAAA,gBAGA,WAAW,eACV;AAAA,kBAAC;AAAA;AAAA,oBACC,cAAW;AAAA,oBACX,OAAO;AAAA,sBACL,WAAW;AAAA,sBACX,OAAO;AAAA,sBACP,UAAU;AAAA,oBACZ;AAAA,oBAEA,uDAAC,UAAK,eAAY,QAAO,4BAAS;AAAA;AAAA,gBACpC;AAAA,gBAID,SACC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,cAAc;AAAA,sBACd,iBAAiB;AAAA;AAAA,sBAEjB,OAAO;AAAA,sBACP,UAAU;AAAA,sBACV,QAAQ;AAAA,oBACV;AAAA,oBACD;AAAA;AAAA,gBAED;AAAA,gBAGF,6CAAC,SAAI,KAAK,gBAAgB,eAAY,QAAO;AAAA;AAAA;AAAA,UAC/C;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,UAAU;AAAA,cACV,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,WAAW;AAAA,gBACX,SAAS;AAAA,gBACT,KAAK;AAAA,cACP;AAAA,cAGA;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,OAAO;AAAA,oBACR;AAAA;AAAA,gBAED;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,IAAG;AAAA,oBACH,KAAK;AAAA,oBACL,OAAO;AAAA,oBACP,UAAU;AAAA,oBACV,aAAY;AAAA,oBACZ,UAAU,WAAW;AAAA,oBACrB,iBAAe,WAAW;AAAA,oBAC1B,OAAO;AAAA,sBACL,MAAM;AAAA,sBACN,SAAS;AAAA,sBACT,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,UAAU;AAAA,sBACV,YAAY;AAAA;AAAA,sBAEZ,SAAS;AAAA,sBACT,eAAe;AAAA,sBACf,iBAAiB;AAAA,sBACjB,OAAO;AAAA,oBACT;AAAA,oBACA,SAAS,CAAC,MAAM;AACd,sBAAC,EAAE,cAAmC,MAAM,UAC1C;AAAA,oBACJ;AAAA,oBACA,QAAQ,CAAC,MAAM;AACb,sBAAC,EAAE,cAAmC,MAAM,UAC1C;AAAA,oBACJ;AAAA;AAAA,gBACF;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,UAAU,WAAW,WAAW,CAAC,MAAM,KAAK;AAAA,oBAC5C,iBAAe,WAAW,WAAW,CAAC,MAAM,KAAK;AAAA,oBACjD,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,iBAAiB;AAAA,sBACjB,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,QAAQ,WAAW,WAAW,MAAM,KAAK,IAAI,YAAY;AAAA,sBACzD,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,SAAS,WAAW,WAAW,MAAM,KAAK,IAAI,IAAI;AAAA,sBAClD,SAAS;AAAA,sBACT,eAAe;AAAA,oBACjB;AAAA,oBACA,SAAS,CAAC,MAAM;AACd,sBAAC,EAAE,cAAoC,MAAM,UAC3C;AACF,sBAAC,EAAE,cAAoC,MAAM,gBAAgB;AAAA,oBAC/D;AAAA,oBACA,QAAQ,CAAC,MAAM;AACb,sBAAC,EAAE,cAAoC,MAAM,UAC3C;AAAA,oBACJ;AAAA,oBACA,cAAW;AAAA,oBACZ;AAAA;AAAA,gBAED;AAAA;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;AIhpBA,IAAAC,gBAAgE;AAgP5D,IAAAC,sBAAA;AAhNJ,IAAM,kBAAiC;AAAA,EACrC;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AACF;AAGA,IAAMC,UAAwB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,SAAS,mBAAmB;AAAA,EACjC,WAAW;AAAA,EACX;AAAA,EACA,WAAW,EAAE,KAAK,KAAK,MAAM,KAAK;AAAA,EAClC;AACF,GAA4B;AAC1B,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,CAAC;AACpD,QAAM,eAAW,sBAAyB,IAAI;AAC9C,QAAM,cAAU,sBAAuB,IAAI;AAC3C,QAAM,gBAAY,sBAAuB,IAAI;AAE7C,QAAM,uBAAmB,sBAA2B,IAAI;AACxD,QAAM,EAAE,YAAY,IAAI,QAAQ;AAGhC,QAAM,cAAU,qBAAM;AACtB,QAAM,cAAU,qBAAM;AAEtB,QAAM,aAAS;AAAA,IACb,CAAC,SAAkB;AACjB,cAAQ,IAAI;AACZ,eAAS,EAAE;AACX,uBAAiB,CAAC;AAClB,iBAAW,IAAI;AAAA,IACjB;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAGA,+BAAU,MAAM;AACd,aAASC,eAAc,GAAkB;AACvC,YAAM,YAAY,SAAS,OAAO,EAAE,UAAU;AAC9C,YAAM,YAAY,SAAS,OAAO,EAAE,UAAU,CAAC,SAAS,OAAO,EAAE,UAAU;AAC3E,WAAK,aAAa,cAAc,EAAE,QAAQ,SAAS,KAAK;AACtD,UAAE,eAAe;AAEjB,YAAI,CAAC,MAAM;AACT,2BAAiB,UAAU,SAAS;AAAA,QACtC;AACA,eAAO,CAAC,IAAI;AAAA,MACd;AAAA,IACF;AACA,WAAO,iBAAiB,WAAWA,cAAa;AAChD,WAAO,MAAM,OAAO,oBAAoB,WAAWA,cAAa;AAAA,EAClE,GAAG,CAAC,MAAM,UAAU,MAAM,CAAC;AAG3B,+BAAU,MAAM;AACd,QAAI,MAAM;AACR,iBAAW,MAAM,SAAS,SAAS,MAAM,GAAG,CAAC;AAAA,IAC/C,OAAO;AAEL,UAAI,iBAAiB,SAAS;AAC5B,yBAAiB,QAAQ,MAAM;AAC/B,yBAAiB,UAAU;AAAA,MAC7B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAGT,+BAAU,MAAM;AACd,QAAI,CAAC,KAAM;AAEX,aAAS,gBAAgB,GAAkB;AACzC,UAAI,EAAE,QAAQ,MAAO;AACrB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,OAAQ;AAEb,YAAM,YAAY,OAAO;AAAA,QACvB;AAAA,MACF;AACA,UAAI,UAAU,WAAW,EAAG;AAE5B,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAE3C,UAAI,EAAE,UAAU;AACd,YAAI,SAAS,kBAAkB,OAAO;AACpC,YAAE,eAAe;AACjB,eAAK,MAAM;AAAA,QACb;AAAA,MACF,OAAO;AACL,YAAI,SAAS,kBAAkB,MAAM;AACnC,YAAE,eAAe;AACjB,gBAAM,MAAM;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,eAAe;AAClD,WAAO,MAAM,OAAO,oBAAoB,WAAW,eAAe;AAAA,EACpE,GAAG,CAAC,IAAI,CAAC;AAGT,QAAM,WAAW,MAAM,KAAK,IACxB,SAAS;AAAA,IACP,CAAC,QACC,IAAI,MAAM,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC,KACpD,IAAI,aAAa,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC,KAC3D,IAAI,UAAU,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC;AAAA,EAC5D,IACA;AAGJ,+BAAU,MAAM;AACd,QAAI,iBAAiB,SAAS,QAAQ;AACpC,uBAAiB,KAAK,IAAI,GAAG,SAAS,SAAS,CAAC,CAAC;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,aAAa,CAAC;AAGnC,+BAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,WAAW,KAAK,SAAS,aAAa;AAC5C,cAAU,eAAe,EAAE,OAAO,UAAU,CAAC;AAAA,EAC/C,GAAG,CAAC,aAAa,CAAC;AAElB,WAAS,eAAe,KAAkB;AACxC,WAAO,KAAK;AACZ,QAAI,OAAO,IAAI,WAAW,UAAU;AAClC,kBAAY,EAAE,MAAM,IAAI,OAAO,CAAC;AAAA,IAClC,OAAO;AACL,UAAI,OAAO;AAAA,IACb;AAAA,EACF;AAEA,WAAS,cAAc,GAAwB;AAC7C,QAAI,EAAE,QAAQ,aAAa;AACzB,QAAE,eAAe;AACjB,uBAAiB,CAAC,SAAS,KAAK,IAAI,OAAO,GAAG,SAAS,SAAS,CAAC,CAAC;AAAA,IACpE,WAAW,EAAE,QAAQ,WAAW;AAC9B,QAAE,eAAe;AACjB,uBAAiB,CAAC,SAAS,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;AAAA,IAClD,WAAW,EAAE,QAAQ,SAAS;AAC5B,QAAE,eAAe;AACjB,UAAI,SAAS,aAAa,GAAG;AAC3B,uBAAe,SAAS,aAAa,CAAC;AAAA,MACxC,WAAW,MAAM,KAAK,GAAG;AAEvB,eAAO,KAAK;AACZ,oBAAY,EAAE,MAAM,MAAM,CAAC;AAAA,MAC7B;AAAA,IACF,WAAW,EAAE,QAAQ,UAAU;AAC7B,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAEA,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,YAA2B;AAAA,IAC/B,GAAG;AAAA,IACH,GAAG,YAAY,KAAK;AAAA,EACtB;AAGA,QAAM,UAAU,oBAAI,IAA2B;AAC/C,aAAW,OAAO,UAAU;AAC1B,UAAM,MAAM,IAAI,YAAY;AAC5B,QAAI,CAAC,QAAQ,IAAI,GAAG,EAAG,SAAQ,IAAI,KAAK,CAAC,CAAC;AAC1C,YAAQ,IAAI,GAAG,EAAG,KAAK,GAAG;AAAA,EAC5B;AAEA,MAAI,YAAY;AAEhB,SACE,8EAEE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM,OAAO,KAAK;AAAA,QAC3B,OAAO;AAAA,UACL,UAAU;AAAA,UACV,OAAO;AAAA,UACP,iBAAiB;AAAA,UACjB,QAAQ;AAAA,QACV;AAAA,QAEA,eAAY;AAAA;AAAA,IACd;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,OAAO;AAAA,UACL,GAAG;AAAA,UACH,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,OAAO;AAAA,UACP,WAAW;AAAA,UACX,SAAS;AAAA,UACT,eAAe;AAAA,UACf,iBAAiB;AAAA,UACjB,cAAc;AAAA,UACd,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,OAAO;AAAA,QACT;AAAA,QACA,MAAK;AAAA,QACL,cAAW;AAAA,QACX,mBAAiB;AAAA,QAEjB,UAAU;AAAA,QAGV;AAAA,uDAAC,QAAG,IAAI,SAAS,OAAOD,SAAQ,6BAEhC;AAAA,UAGA,8CAAC,SAAI,OAAO,EAAE,SAAS,aAAa,cAAc,gCAAgC,GAChF;AAAA,yDAAC,WAAM,SAAS,SAAS,OAAOA,SAAQ,uCAExC;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI;AAAA,gBACJ,KAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM;AACf,2BAAS,EAAE,OAAO,KAAK;AACvB,mCAAiB,CAAC;AAAA,gBACpB;AAAA,gBACA,WAAW;AAAA,gBACX,aAAY;AAAA,gBACZ,OAAO;AAAA,kBACL,OAAO;AAAA,kBACP,SAAS;AAAA,kBACT,QAAQ;AAAA;AAAA,kBAER,SAAS;AAAA,kBACT,eAAe;AAAA,kBACf,UAAU;AAAA,kBACV,YAAY;AAAA,kBACZ,iBAAiB;AAAA,kBACjB,OAAO;AAAA,gBACT;AAAA,gBACA,SAAS,CAAC,MAAM;AACd,kBAAC,EAAE,cAAmC,MAAM,UAC1C;AAAA,gBACJ;AAAA,gBACA,QAAQ,CAAC,MAAM;AACb,kBAAC,EAAE,cAAmC,MAAM,UAC1C;AAAA,gBACJ;AAAA,gBACA,MAAK;AAAA,gBACL,iBAAc;AAAA,gBACd,qBAAkB;AAAA,gBAClB,iBAAc;AAAA,gBACd,yBACE,SAAS,aAAa,IAClB,OAAO,SAAS,aAAa,EAAE,EAAE,KACjC;AAAA;AAAA,YAER;AAAA,aACF;AAAA,UAGA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,KAAK;AAAA,cACL,OAAO,EAAE,WAAW,QAAQ,SAAS,QAAQ;AAAA,cAC7C,MAAK;AAAA,cACL,cAAW;AAAA,cAEV;AAAA,yBAAS,WAAW,KAAK,MAAM,KAAK,KACnC;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,iBAAc;AAAA,oBACd,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,WAAW;AAAA,sBACX,UAAU;AAAA,sBACV,OAAO;AAAA,oBACT;AAAA,oBACD;AAAA;AAAA,sBACgC;AAAA,sBAAM;AAAA;AAAA;AAAA,gBACvC;AAAA,gBAGD,MAAM,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,KAAK;AAAA;AAAA,kBAElD,8CAAC,SAAmB,MAAK,SAAQ,cAAY,UAE3C;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,eAAY;AAAA,wBACZ,OAAO;AAAA,0BACL,SAAS;AAAA,0BACT,UAAU;AAAA,0BACV,YAAY;AAAA,0BACZ,eAAe;AAAA,0BACf,eAAe;AAAA,0BACf,OAAO;AAAA,wBACT;AAAA,wBAEC;AAAA;AAAA,oBACH;AAAA,oBACC,MAAM,IAAI,CAAC,QAAQ;AAClB,4BAAM,MAAM;AACZ,4BAAM,aAAa,QAAQ;AAC3B,6BACE;AAAA,wBAAC;AAAA;AAAA,0BAEC,IAAI,OAAO,IAAI,EAAE;AAAA,0BACjB,MAAK;AAAA,0BACL,iBAAe;AAAA,0BACf,SAAS,MAAM,eAAe,GAAG;AAAA,0BACjC,cAAc,MAAM,iBAAiB,GAAG;AAAA,0BAExC,UAAU,aAAa,IAAI;AAAA,0BAC3B,WAAW,CAAC,MAAM;AAChB,gCAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,gCAAE,eAAe;AACjB,6CAAe,GAAG;AAAA,4BACpB;AAAA,0BACF;AAAA,0BACA,OAAO;AAAA,4BACL,SAAS;AAAA,4BACT,QAAQ;AAAA,4BACR,SAAS;AAAA,4BACT,YAAY;AAAA,4BACZ,KAAK;AAAA,4BACL,iBAAiB,aACb,8BACA;AAAA,4BACJ,SAAS;AAAA,4BACT,eAAe;AAAA,0BACjB;AAAA,0BACA,SAAS,CAAC,MAAM;AACd,4BAAC,EAAE,cAAiC,MAAM,UACxC;AAAA,0BACJ;AAAA,0BACA,QAAQ,CAAC,MAAM;AACb,4BAAC,EAAE,cAAiC,MAAM,UACxC;AAAA,0BACJ;AAAA,0BAEC;AAAA,gCAAI;AAAA,4BAEH,6CAAC,UAAK,eAAY,QAAO,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GAC3D,cAAI,MACP;AAAA,4BAEF,8CAAC,SAAI,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,GACjC;AAAA,2EAAC,SAAI,OAAO,EAAE,UAAU,IAAI,YAAY,IAAI,GACzC,cAAI,OACP;AAAA,8BACC,IAAI,eACH;AAAA,gCAAC;AAAA;AAAA,kCACC,OAAO;AAAA,oCACL,UAAU;AAAA,oCACV,OAAO;AAAA,oCACP,YAAY;AAAA,oCACZ,UAAU;AAAA,oCACV,cAAc;AAAA,kCAChB;AAAA,kCAEC,cAAI;AAAA;AAAA,8BACP;AAAA,+BAEJ;AAAA;AAAA;AAAA,wBA1DK,IAAI;AAAA,sBA2DX;AAAA,oBAEJ,CAAC;AAAA,uBAjFO,QAkFV;AAAA,iBACD;AAAA;AAAA;AAAA,UACH;AAAA,UAIA;AAAA,YAAC;AAAA;AAAA,cACC,eAAY;AAAA,cACZ,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,WAAW;AAAA,gBACX,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,KAAK;AAAA,cACP;AAAA,cAEA;AAAA,6DAAC,UAAK,mCAAW;AAAA,gBACjB,6CAAC,UAAK,2BAAQ;AAAA,gBACd,6CAAC,UAAK,uBAAS;AAAA;AAAA;AAAA,UACjB;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;ACjdA,IAAAE,gBAAsD;AA8I9C,IAAAC,sBAAA;AA7HD,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,gBAAY,sBAAuB,IAAI;AAC7C,QAAM,sBAAkB,sBAA0B,IAAI;AAGtD,QAAM,cAAU,qBAAM;AACtB,QAAM,oBAAgB,qBAAM;AAG5B,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAAqB;AACpB,UAAI,EAAE,QAAQ,UAAU;AACtB,UAAE,eAAe;AACjB,iBAAS;AACT;AAAA,MACF;AAEA,UAAI,EAAE,QAAQ,MAAO;AACrB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,OAAQ;AAEb,YAAM,YAAY,OAAO;AAAA,QACvB;AAAA,MACF;AACA,UAAI,UAAU,WAAW,EAAG;AAE5B,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAE3C,UAAI,EAAE,UAAU;AACd,YAAI,SAAS,kBAAkB,OAAO;AACpC,YAAE,eAAe;AACjB,eAAK,MAAM;AAAA,QACb;AAAA,MACF,OAAO;AACL,YAAI,SAAS,kBAAkB,MAAM;AACnC,YAAE,eAAe;AACjB,gBAAM,MAAM;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAKA,+BAAU,MAAM;AACd,UAAM,gBAAgB,SAAS;AAE/B,oBAAgB,SAAS,MAAM;AAC/B,WAAO,iBAAiB,WAAW,aAAa;AAEhD,WAAO,MAAM;AACX,aAAO,oBAAoB,WAAW,aAAa;AAEnD,qBAAe,MAAM;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,eAA8B;AAAA,IAClC,GAAG;AAAA,IACH,UAAU;AAAA,IACV,OAAO;AAAA,IACP,iBAAiB;AAAA,IACjB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,YAAY;AAAA,EACd;AAEA,QAAM,cAA6B;AAAA,IACjC,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,OAAO;AAAA,EACT;AAEA,QAAM,aAA4B;AAAA,IAChC,SAAS;AAAA,IACT,eAAe;AAAA,EACjB;AAEA,WAAS,eAAe,IAAiB;AACvC,OAAG,MAAM,UAAU;AACnB,OAAG,MAAM,gBAAgB;AAAA,EAC3B;AAEA,WAAS,gBAAgB,IAAiB;AACxC,OAAG,MAAM,UAAU;AACnB,OAAG,MAAM,gBAAgB;AAAA,EAC3B;AAEA;AAAA;AAAA,IAEE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QAEP,SAAS,CAAC,MAAM;AACd,cAAI,EAAE,WAAW,EAAE,cAAe,UAAS;AAAA,QAC7C;AAAA,QACA,eAAY;AAAA,QAEZ;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,OAAO;AAAA,YACP,MAAK;AAAA,YACL,cAAW;AAAA,YACX,mBAAiB;AAAA,YACjB,oBAAkB;AAAA,YAElB,UAAU;AAAA,YAEV,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,YAElC;AAAA,2DAAC,QAAG,IAAI,SAAS,OAAO,EAAE,QAAQ,WAAW,UAAU,GAAG,GAAG,4BAE7D;AAAA,cACA,6CAAC,OAAE,OAAO,EAAE,QAAQ,WAAW,UAAU,IAAI,YAAY,IAAI,GAC1D,kBACH;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,IAAI;AAAA,kBACJ,OAAO;AAAA,oBACL,QAAQ;AAAA,oBACR,UAAU;AAAA,oBACV,OAAO;AAAA,kBACT;AAAA,kBAEC;AAAA;AAAA,cACH;AAAA,cAEC,cAAc,OAAO,KAAK,UAAU,EAAE,SAAS,KAC9C;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,QAAQ;AAAA,oBACR,SAAS;AAAA,oBACT,iBAAiB;AAAA,oBACjB,cAAc;AAAA,oBACd,UAAU;AAAA,oBACV,UAAU;AAAA,oBACV,WAAW;AAAA,oBACX,QAAQ;AAAA,kBACV;AAAA,kBAEC,eAAK,UAAU,YAAY,MAAM,CAAC;AAAA;AAAA,cACrC;AAAA,cAGF,8CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,GAAG,gBAAgB,WAAW,GAEhE;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,KAAK;AAAA,oBACL,MAAK;AAAA,oBACL,SAAS;AAAA,oBACT,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,iBAAiB;AAAA,sBACjB,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,UAAU;AAAA,sBACV,GAAG;AAAA,oBACL;AAAA,oBACA,SAAS,CAAC,MAAM,eAAe,EAAE,aAAa;AAAA,oBAC9C,QAAQ,CAAC,MAAM,gBAAgB,EAAE,aAAa;AAAA,oBAC/C;AAAA;AAAA,gBAED;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS;AAAA,oBACT,OAAO;AAAA,sBACL,SAAS;AAAA,sBACT,QAAQ;AAAA,sBACR,cAAc;AAAA;AAAA,sBAEd,iBAAiB;AAAA,sBACjB,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,UAAU;AAAA,sBACV,GAAG;AAAA,oBACL;AAAA,oBACA,SAAS,CAAC,MAAM,eAAe,EAAE,aAAa;AAAA,oBAC9C,QAAQ,CAAC,MAAM,gBAAgB,EAAE,aAAa;AAAA,oBAC/C;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA;AAEJ;","names":["import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","srOnly","handleKeyDown","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/provider.tsx","../src/chat.tsx","../src/use-ai-me.ts","../src/styles.ts","../src/markdown.tsx","../src/command-palette.tsx","../src/confirm.tsx"],"sourcesContent":["export { AIMeProvider } from \"./provider.js\";\nexport type { AIMeProviderProps } from \"./provider.js\";\nexport { AIMeChat } from \"./chat.js\";\nexport type { AIMeChatProps } from \"./chat.js\";\nexport { AIMeCommandPalette } from \"./command-palette.js\";\nexport type {\n AIMeCommandPaletteProps,\n CommandItem,\n} from \"./command-palette.js\";\nexport { AIMeConfirm } from \"./confirm.js\";\nexport type { AIMeConfirmProps } from \"./confirm.js\";\nexport { useAIMe } from \"./use-ai-me.js\";\nexport { useAIMeContext } from \"./context.js\";\nexport type { AIMeContextValue } from \"./context.js\";\nexport type { AIMeTheme } from \"./styles.js\";\nexport { renderMarkdown } from \"./markdown.js\";\n","import { createContext, useContext } from \"react\";\n\n/** Payload passed to the `onAction` callback */\nexport interface AIMeAction {\n /** Action type — e.g. \"navigate\", \"prefill\", \"open-modal\" */\n type: string;\n /** Flexible additional payload supplied by the AI tool */\n [key: string]: unknown;\n}\n\nexport interface AIMeContextValue {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n * Use this to handle navigation, form pre-fill, modal opening, etc.\n * without the AI making an API call directly.\n */\n onAction?: (action: AIMeAction) => void;\n}\n\nexport const AIMeContext = createContext<AIMeContextValue | null>(null);\n\nexport function useAIMeContext(): AIMeContextValue {\n const ctx = useContext(AIMeContext);\n if (!ctx) {\n throw new Error(\"useAIMe must be used within an <AIMeProvider>\");\n }\n return ctx;\n}\n","import type { ReactNode } from \"react\";\nimport { AIMeContext } from \"./context.js\";\nimport type { AIMeAction } from \"./context.js\";\n\nexport interface AIMeProviderProps {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Optional: additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n *\n * The AI can emit structured actions (e.g. \"navigate\", \"prefill\",\n * \"open-modal\") that your app handles without making an API call.\n * Wire the corresponding `__navigate` / `__prefill` tools in your\n * AI-Me handler to produce these actions, then consume them here.\n *\n * @example\n * ```tsx\n * <AIMeProvider\n * endpoint=\"/api/ai-me\"\n * onAction={(action) => {\n * if (action.type === \"navigate\") {\n * router.push(action.href as string);\n * }\n * }}\n * >\n * {children}\n * </AIMeProvider>\n * ```\n */\n onAction?: (action: AIMeAction) => void;\n /** Child components */\n children: ReactNode;\n}\n\nexport function AIMeProvider({ endpoint, headers, onAction, children }: AIMeProviderProps) {\n return (\n <AIMeContext value={{ endpoint, headers, onAction }}>\n {children}\n </AIMeContext>\n );\n}\n","import { useState, useRef, useEffect, useCallback, useId } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useAIMe } from \"./use-ai-me.js\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { renderMarkdown } from \"./markdown.js\";\n\n/** Tool execution result passed to onToolComplete */\nexport interface ToolCompleteEvent {\n /** Tool (function) name */\n name: string;\n /** HTTP method used, if available from the tool result */\n httpMethod?: string;\n /** API path called, if available from the tool result */\n path?: string;\n /** Raw result returned by the tool */\n result: unknown;\n /** Whether the tool required user confirmation */\n requiresConfirmation?: boolean;\n}\n\n/** Completed assistant message passed to onMessageComplete */\nexport interface MessageCompleteEvent {\n role: string;\n content: string;\n toolCalls?: unknown[];\n}\n\nexport interface AIMeChatProps {\n /** Position of chat panel */\n position?: \"bottom-right\" | \"bottom-left\" | \"inline\";\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Welcome message shown on empty chat */\n welcomeMessage?: string;\n /** Suggested prompts shown on empty chat */\n suggestedPrompts?: string[];\n /** Whether chat starts open */\n defaultOpen?: boolean;\n /** Callback when chat opens/closes */\n onToggle?: (open: boolean) => void;\n /**\n * Fired after each tool execution completes (after the API call returns).\n * Use this to trigger client-side data refreshes when the AI mutates data.\n */\n onToolComplete?: (tool: ToolCompleteEvent) => void;\n /**\n * Fired when the assistant finishes a full response (status transitions\n * from \"streaming\" to \"ready\").\n */\n onMessageComplete?: (message: MessageCompleteEvent) => void;\n /**\n * Custom renderer for the tool confirmation dialog.\n *\n * When provided, AI-Me will call this function instead of showing the\n * default confirmation UI. Return any React node — a modal, an inline\n * card, a drawer, etc.\n *\n * If not provided, the built-in `<AIMeConfirm>` dialog is used.\n *\n * @example\n * ```tsx\n * <AIMeChat\n * renderConfirmation={({ tool, params, onConfirm, onCancel }) => (\n * <MyCustomConfirmDialog\n * title={`Run ${tool.name}?`}\n * description={tool.description}\n * params={params}\n * onConfirm={onConfirm}\n * onCancel={onCancel}\n * />\n * )}\n * />\n * ```\n */\n renderConfirmation?: (props: {\n /** Metadata about the tool that is about to be executed */\n tool: {\n /** Tool (function) name */\n name: string;\n /** HTTP method the tool maps to, e.g. \"POST\" */\n httpMethod: string;\n /** API path the tool will call, e.g. \"/api/projects\" */\n path: string;\n /** Human-readable description of what the tool does */\n description: string;\n };\n /** Resolved parameters the tool will be called with */\n params: Record<string, unknown>;\n /** Call to proceed with the tool execution */\n onConfirm: () => void;\n /** Call to abort without executing the tool */\n onCancel: () => void;\n }) => ReactNode;\n}\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeChat({\n position = \"bottom-right\",\n theme,\n welcomeMessage = \"Hi! I can help you navigate and use this app. What would you like to do?\",\n suggestedPrompts,\n defaultOpen = false,\n onToggle,\n onToolComplete,\n onMessageComplete,\n}: AIMeChatProps) {\n const [open, setOpen] = useState(defaultOpen);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // Track tool-result part IDs that have already fired onToolComplete\n const firedToolResults = useRef<Set<string>>(new Set());\n // Track the previous status to detect the streaming → ready transition\n const prevStatus = useRef<string | null>(null);\n const {\n messages,\n input,\n handleInputChange,\n handleSubmit,\n status,\n error,\n setInput,\n } = useAIMe();\n\n // Stable IDs for aria-labelledby / aria-describedby\n const titleId = useId();\n const messagesId = useId();\n\n const isInline = position === \"inline\";\n\n const toggleOpen = useCallback(() => {\n const next = !open;\n setOpen(next);\n onToggle?.(next);\n }, [open, onToggle]);\n\n // Keyboard shortcut: Cmd+. to toggle\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \".\") {\n e.preventDefault();\n toggleOpen();\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleOpen]);\n\n // Scroll to bottom on new messages\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n // Fire onToolComplete for each new tool-result part observed in messages.\n // We deduplicate by tracking the tool-call ID so the callback fires exactly\n // once per tool execution, even across re-renders during streaming.\n useEffect(() => {\n if (!onToolComplete) return;\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type !== \"tool-result\") continue;\n // Each tool-result part has a stable toolCallId\n const id = (part as { toolCallId?: string }).toolCallId;\n const dedupeKey = id ?? `${message.id}:${part.type}`;\n if (firedToolResults.current.has(dedupeKey)) continue;\n firedToolResults.current.add(dedupeKey);\n onToolComplete({\n name: (part as { toolName?: string }).toolName ?? \"\",\n result: (part as { result?: unknown }).result,\n });\n }\n }\n }, [messages, onToolComplete]);\n\n // Fire onMessageComplete when status transitions from streaming → ready.\n // prevStatus tracks the last seen status so we only fire on the transition.\n useEffect(() => {\n const prev = prevStatus.current;\n prevStatus.current = status;\n\n if (!onMessageComplete) return;\n // Only fire on the transition away from an active streaming state\n if (status !== \"ready\") return;\n if (prev !== \"streaming\" && prev !== \"submitted\") return;\n\n // Find the last assistant message\n // Walk backwards to find the most recent assistant message without copying the array\n let lastAssistant: (typeof messages)[number] | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"assistant\") { lastAssistant = messages[i]; break; }\n }\n if (!lastAssistant) return;\n\n const textContent = lastAssistant.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n\n const toolCalls: unknown[] = lastAssistant.parts.filter((p) => p.type === \"tool-call\");\n\n onMessageComplete({\n role: lastAssistant.role,\n content: textContent,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n });\n }, [status, messages, onMessageComplete]);\n\n // Focus panel when opened; return focus to trigger when closed\n useEffect(() => {\n if (open) {\n // Shift focus into the panel so screen readers announce the dialog\n panelRef.current?.focus();\n // Then move focus to the input after a tick so the panel focus is set first\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to the trigger that opened the panel\n triggerRef.current?.focus();\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the panel while open\n useEffect(() => {\n if (!open || isInline) return;\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n toggleOpen();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const panel = panelRef.current;\n if (!panel) return;\n\n const focusable = panel.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, isInline, toggleOpen]);\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n const panelStyle: CSSProperties = isInline\n ? {\n ...themeVars,\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n }\n : {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 380,\n height: \"70vh\",\n maxHeight: 600,\n display: open ? \"flex\" : \"none\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n boxShadow: \"var(--ai-me-shadow)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n zIndex: 9999,\n };\n\n const triggerStyle: CSSProperties = {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n cursor: \"pointer\",\n display: isInline || open ? \"none\" : \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"var(--ai-me-shadow)\",\n fontSize: 24,\n zIndex: 9999,\n };\n\n const isStreaming = status === \"submitted\" || status === \"streaming\";\n\n return (\n <>\n {/* Floating trigger button */}\n <button\n ref={triggerRef}\n onClick={toggleOpen}\n style={triggerStyle}\n aria-label=\"Open AI chat\"\n aria-expanded={open}\n aria-controls={isInline ? undefined : \"ai-me-chat-panel\"}\n type=\"button\"\n >\n {/* Icon is decorative; label is on the button */}\n <span aria-hidden=\"true\">💬</span>\n </button>\n\n {/* Chat panel */}\n <div\n id=\"ai-me-chat-panel\"\n ref={panelRef}\n style={panelStyle}\n role=\"dialog\"\n aria-modal={isInline ? undefined : \"true\"}\n aria-labelledby={titleId}\n aria-busy={isStreaming}\n // tabIndex={-1} allows programmatic focus on the panel element itself\n tabIndex={-1}\n >\n {/* Header */}\n <div\n style={{\n padding: \"12px 16px\",\n borderBottom: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n }}\n >\n <span id={titleId} style={{ fontWeight: 600, fontSize: 14 }}>\n AI Assistant\n </span>\n {!isInline && (\n <button\n onClick={toggleOpen}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: 18,\n color: \"var(--ai-me-text-secondary)\",\n padding: 4,\n borderRadius: 4,\n // Visible focus indicator without outline:none\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Close chat\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">✕</span>\n </button>\n )}\n </div>\n\n {/* Skip link: jump straight to the input */}\n <a\n href=\"#ai-me-chat-input\"\n style={{\n ...srOnly,\n // Reveal on focus so keyboard users can see it\n }}\n onFocus={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, {\n position: \"static\",\n width: \"auto\",\n height: \"auto\",\n padding: \"4px 8px\",\n margin: 0,\n overflow: \"visible\",\n clip: \"auto\",\n whiteSpace: \"normal\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n fontSize: 12,\n borderRadius: 4,\n });\n }}\n onBlur={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, srOnly);\n }}\n >\n Skip to message input\n </a>\n\n {/* Messages — live region so screen readers announce new content */}\n <div\n id={messagesId}\n aria-live=\"polite\"\n aria-label=\"Conversation\"\n aria-relevant=\"additions\"\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n }}\n >\n {messages.length === 0 && (\n <div style={{ color: \"var(--ai-me-text-secondary)\", fontSize: 14 }}>\n <p>{welcomeMessage}</p>\n {suggestedPrompts && suggestedPrompts.length > 0 && (\n <div\n style={{\n marginTop: 12,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 8,\n }}\n >\n <p style={{ margin: \"0 0 4px\", fontSize: 12, fontWeight: 500 }}>\n Suggested questions:\n </p>\n {suggestedPrompts.map((prompt) => (\n <button\n key={prompt}\n type=\"button\"\n onClick={() => {\n setInput(prompt);\n inputRef.current?.focus();\n }}\n style={{\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n background: \"var(--ai-me-bg)\",\n cursor: \"pointer\",\n textAlign: \"left\",\n fontSize: 13,\n color: \"var(--ai-me-text)\",\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {prompt}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {messages.map((m) => {\n // Skip messages that have no renderable content (e.g. reasoning-only messages\n // from providers like Groq that emit reasoning tokens).\n const hasTextContent = m.parts.some((p) => p.type === \"text\");\n if (!hasTextContent && m.role === \"assistant\") return null;\n\n return (\n <div\n key={m.id}\n style={{\n alignSelf: m.role === \"user\" ? \"flex-end\" : \"flex-start\",\n maxWidth: \"85%\",\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor:\n m.role === \"user\"\n ? \"var(--ai-me-primary)\"\n : \"var(--ai-me-bg-secondary)\",\n color: m.role === \"user\" ? \"#fff\" : \"var(--ai-me-text)\",\n fontSize: 14,\n lineHeight: 1.5,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n }}\n >\n {/* Screen reader role prefix */}\n <span style={srOnly}>\n {m.role === \"user\" ? \"You: \" : \"Assistant: \"}\n </span>\n {m.parts.map((p, i) =>\n p.type === \"text\" ? (\n <span key={i}>\n {m.role === \"assistant\"\n ? renderMarkdown(p.text)\n : p.text}\n </span>\n ) : null,\n )}\n </div>\n );\n })}\n\n {/* \"Thinking\" indicator — announced by the live region above */}\n {status === \"submitted\" && (\n <div\n aria-label=\"Assistant is thinking\"\n style={{\n alignSelf: \"flex-start\",\n color: \"var(--ai-me-text-secondary)\",\n fontSize: 13,\n }}\n >\n <span aria-hidden=\"true\">Thinking…</span>\n </div>\n )}\n\n {/* Error — role=\"alert\" ensures immediate announcement */}\n {error && (\n <div\n role=\"alert\"\n style={{\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor: \"#fef2f2\",\n // #dc2626 on #fef2f2 ≈ 5.1:1 — passes AA for normal text\n color: \"#dc2626\",\n fontSize: 13,\n border: \"1px solid #fca5a5\",\n }}\n >\n Something went wrong. Please try again.\n </div>\n )}\n\n <div ref={messagesEndRef} aria-hidden=\"true\" />\n </div>\n\n {/* Input */}\n <form\n onSubmit={handleSubmit}\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n gap: 8,\n }}\n >\n {/* Visible label for the input (positioned absolutely so only visible on focus for compact layout) */}\n <label\n htmlFor=\"ai-me-chat-input\"\n style={srOnly}\n >\n Message to AI Assistant\n </label>\n <input\n id=\"ai-me-chat-input\"\n ref={inputRef}\n value={input}\n onChange={handleInputChange}\n placeholder=\"Ask anything…\"\n disabled={status !== \"ready\"}\n aria-disabled={status !== \"ready\"}\n style={{\n flex: 1,\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n // Do NOT use outline:none — use outline with transparent color + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n />\n <button\n type=\"submit\"\n disabled={status !== \"ready\" || !input.trim()}\n aria-disabled={status !== \"ready\" || !input.trim()}\n style={{\n padding: \"8px 16px\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 8,\n cursor: status === \"ready\" && input.trim() ? \"pointer\" : \"not-allowed\",\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n opacity: status === \"ready\" && input.trim() ? 1 : 0.5,\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n (e.currentTarget as HTMLButtonElement).style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Send message\"\n >\n Send\n </button>\n </form>\n </div>\n </>\n );\n}\n","import { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useState, useCallback, useEffect, useRef } from \"react\";\nimport { useAIMeContext } from \"./context.js\";\n\nconst STORAGE_KEY = \"ai-me-messages\";\n\n/**\n * Hook wrapping AI SDK's useChat with AI-Me configuration.\n * Provides chat state, message handling, confirmation support,\n * and session persistence (survives page navigation within the same tab).\n */\nexport function useAIMe() {\n const { endpoint, headers } = useAIMeContext();\n const [input, setInput] = useState(\"\");\n const initialized = useRef(false);\n\n const chat = useChat({\n transport: new DefaultChatTransport({\n api: endpoint,\n headers,\n }),\n });\n\n // Restore messages from sessionStorage on mount\n useEffect(() => {\n if (initialized.current) return;\n initialized.current = true;\n\n try {\n const stored = sessionStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (Array.isArray(parsed) && parsed.length > 0) {\n chat.setMessages(parsed);\n }\n }\n } catch {\n // ignore — sessionStorage may be unavailable or corrupted\n }\n }, []);\n\n // Persist messages to sessionStorage on change\n useEffect(() => {\n if (!initialized.current) return;\n try {\n if (chat.messages.length > 0) {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(chat.messages));\n } else {\n sessionStorage.removeItem(STORAGE_KEY);\n }\n } catch {\n // ignore\n }\n }, [chat.messages]);\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setInput(e.target.value);\n },\n [],\n );\n\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n if (!input.trim()) return;\n chat.sendMessage({ text: input });\n setInput(\"\");\n },\n [input, chat],\n );\n\n const clearMessages = useCallback(() => {\n chat.setMessages([]);\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n }, [chat]);\n\n return {\n /** Conversation messages */\n messages: chat.messages,\n /** Current input value */\n input,\n /** Set input value */\n setInput,\n /** Handle input change */\n handleInputChange,\n /** Submit the current message */\n handleSubmit,\n /** Send a message directly */\n sendMessage: chat.sendMessage,\n /** Chat status: \"ready\" | \"submitted\" | \"streaming\" */\n status: chat.status,\n /** Error if any */\n error: chat.error,\n /** Stop streaming */\n stop: chat.stop,\n /** Set messages */\n setMessages: chat.setMessages,\n /** Clear all messages and session storage */\n clearMessages,\n };\n}\n","/**\n * CSS custom properties for AI-Me theming.\n * All prefixed with --ai-me- to avoid conflicts with host app styles.\n */\nexport const defaultThemeVars = {\n \"--ai-me-primary\": \"#6366f1\",\n \"--ai-me-primary-hover\": \"#4f46e5\",\n \"--ai-me-bg\": \"#ffffff\",\n \"--ai-me-bg-secondary\": \"#f9fafb\",\n \"--ai-me-text\": \"#111827\",\n \"--ai-me-text-secondary\": \"#6b7280\",\n \"--ai-me-border\": \"#e5e7eb\",\n \"--ai-me-radius\": \"12px\",\n \"--ai-me-font\": \"system-ui, -apple-system, sans-serif\",\n \"--ai-me-shadow\": \"0 4px 24px rgba(0, 0, 0, 0.12)\",\n} as const;\n\nexport interface AIMeTheme {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n}\n\nexport function themeToVars(theme?: AIMeTheme): Record<string, string> {\n if (!theme) return {};\n const vars: Record<string, string> = {};\n if (theme.primaryColor) vars[\"--ai-me-primary\"] = theme.primaryColor;\n if (theme.backgroundColor) vars[\"--ai-me-bg\"] = theme.backgroundColor;\n if (theme.textColor) vars[\"--ai-me-text\"] = theme.textColor;\n if (theme.borderRadius) vars[\"--ai-me-radius\"] = theme.borderRadius;\n if (theme.fontFamily) vars[\"--ai-me-font\"] = theme.fontFamily;\n return vars;\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\n/**\n * Lightweight inline markdown renderer for chat messages.\n * Supports: **bold**, *italic*, `code`, ```code blocks```, [links](url), - lists\n * No external dependencies — renders to React elements with inline styles.\n */\nexport function renderMarkdown(text: string): ReactNode[] {\n const lines = text.split(\"\\n\");\n const result: ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Fenced code block\n if (line.trimStart().startsWith(\"```\")) {\n const lang = line.trimStart().slice(3).trim();\n const codeLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].trimStart().startsWith(\"```\")) {\n codeLines.push(lines[i]);\n i++;\n }\n i++; // skip closing ```\n result.push(\n <pre\n key={`code-${result.length}`}\n style={codeBlockStyle}\n data-lang={lang || undefined}\n >\n <code>{codeLines.join(\"\\n\")}</code>\n </pre>,\n );\n continue;\n }\n\n // Unordered list item\n if (/^[\\s]*[-*]\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*[-*]\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*[-*]\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ul\n key={`ul-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20, listStyleType: \"disc\" }}\n >\n {listItems}\n </ul>,\n );\n continue;\n }\n\n // Ordered list item\n if (/^[\\s]*\\d+\\.\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*\\d+\\.\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*\\d+\\.\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ol\n key={`ol-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20 }}\n >\n {listItems}\n </ol>,\n );\n continue;\n }\n\n // Heading (clamp to h3+ in chat context)\n const headingMatch = /^(#{1,6})\\s+(.+)$/.exec(line);\n if (headingMatch) {\n const level = Math.max(headingMatch[1].length, 3);\n const fontSize =\n ({ 3: 15, 4: 14, 5: 13, 6: 13 } as Record<number, number>)[level] ??\n 14;\n result.push(\n <p\n key={`h-${result.length}`}\n style={{ fontWeight: 600, fontSize, margin: \"8px 0 4px\" }}\n >\n {renderInline(headingMatch[2])}\n </p>,\n );\n i++;\n continue;\n }\n\n // Empty line\n if (line.trim() === \"\") {\n i++;\n continue;\n }\n\n // Regular text\n result.push(\n <span\n key={`p-${result.length}`}\n style={{ display: \"block\", marginBottom: 2 }}\n >\n {renderInline(line)}\n </span>,\n );\n i++;\n }\n\n return result;\n}\n\n/** Parse inline markdown: bold, italic, code, links */\nfunction renderInline(text: string): ReactNode[] {\n const result: ReactNode[] = [];\n const pattern = /(`[^`]+`|\\*\\*[^*]+\\*\\*|\\*[^*]+\\*|\\[[^\\]]+\\]\\([^)]+\\))/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n if (match.index > lastIndex) {\n result.push(text.slice(lastIndex, match.index));\n }\n\n const token = match[0];\n\n if (token.startsWith(\"`\")) {\n result.push(\n <code key={result.length} style={inlineCodeStyle}>\n {token.slice(1, -1)}\n </code>,\n );\n } else if (token.startsWith(\"**\")) {\n result.push(\n <strong key={result.length}>{token.slice(2, -2)}</strong>,\n );\n } else if (token.startsWith(\"*\")) {\n result.push(<em key={result.length}>{token.slice(1, -1)}</em>);\n } else if (token.startsWith(\"[\")) {\n const linkMatch = /\\[([^\\]]+)\\]\\(([^)]+)\\)/.exec(token);\n if (linkMatch) {\n result.push(\n <a\n key={result.length}\n href={linkMatch[2]}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={linkStyle}\n >\n {linkMatch[1]}\n </a>,\n );\n }\n }\n\n lastIndex = match.index + token.length;\n }\n\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return result;\n}\n\nconst codeBlockStyle: CSSProperties = {\n margin: \"6px 0\",\n padding: \"10px 12px\",\n borderRadius: 6,\n backgroundColor: \"rgba(0,0,0,0.15)\",\n fontSize: 12,\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n overflow: \"auto\",\n whiteSpace: \"pre\",\n lineHeight: 1.5,\n};\n\nconst inlineCodeStyle: CSSProperties = {\n padding: \"1px 5px\",\n borderRadius: 3,\n backgroundColor: \"rgba(0,0,0,0.12)\",\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: \"0.9em\",\n};\n\nconst linkStyle: CSSProperties = {\n color: \"var(--ai-me-primary, #6366f1)\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n};\n","import { useState, useEffect, useRef, useCallback, useId } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { useAIMe } from \"./use-ai-me.js\";\n\nexport interface AIMeCommandPaletteProps {\n /** List of available commands/actions */\n commands?: CommandItem[];\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Custom keyboard shortcut (default: Cmd+K / Ctrl+K) */\n shortcut?: { key: string; meta?: boolean; ctrl?: boolean };\n /** Callback when palette opens/closes */\n onToggle?: (open: boolean) => void;\n}\n\nexport interface CommandItem {\n /** Unique command ID */\n id: string;\n /** Display label */\n label: string;\n /** Description shown below label */\n description?: string;\n /** Category for grouping */\n category?: string;\n /** Icon (emoji or text) */\n icon?: string;\n /** Action to run — either a callback or a prompt to send to AI */\n action: (() => void) | string;\n}\n\nconst defaultCommands: CommandItem[] = [\n {\n id: \"help\",\n label: \"Ask AI for help\",\n description: \"Get assistance with any task\",\n category: \"AI\",\n icon: \"💡\",\n action: \"What can you help me with?\",\n },\n {\n id: \"list-actions\",\n label: \"List available actions\",\n description: \"Show all API actions the AI can perform\",\n category: \"AI\",\n icon: \"📋\",\n action: \"What actions can you perform? List them all.\",\n },\n {\n id: \"recent-activity\",\n label: \"Show recent activity\",\n description: \"Summarize recent actions and changes\",\n category: \"AI\",\n icon: \"🕐\",\n action: \"What has happened recently? Summarize recent activity.\",\n },\n];\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeCommandPalette({\n commands = defaultCommands,\n theme,\n shortcut = { key: \"k\", meta: true },\n onToggle,\n}: AIMeCommandPaletteProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n // Remember what had focus before the palette opened so we can restore it\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const { sendMessage } = useAIMe();\n\n // Stable IDs\n const titleId = useId();\n const inputId = useId();\n\n const toggle = useCallback(\n (next: boolean) => {\n setOpen(next);\n setQuery(\"\");\n setSelectedIndex(0);\n onToggle?.(next);\n },\n [onToggle],\n );\n\n // Keyboard shortcut to open\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n const metaMatch = shortcut.meta ? e.metaKey : true;\n const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;\n if ((metaMatch || ctrlMatch) && e.key === shortcut.key) {\n e.preventDefault();\n // Capture current focus before opening\n if (!open) {\n previousFocusRef.current = document.activeElement as HTMLElement;\n }\n toggle(!open);\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, shortcut, toggle]);\n\n // Focus the search input when opened; restore focus when closed\n useEffect(() => {\n if (open) {\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to whatever had it before the palette opened\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n previousFocusRef.current = null;\n }\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the palette while open\n useEffect(() => {\n if (!open) return;\n\n function handleFocusTrap(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleFocusTrap);\n return () => window.removeEventListener(\"keydown\", handleFocusTrap);\n }, [open]);\n\n // Filter commands by query\n const filtered = query.trim()\n ? commands.filter(\n (cmd) =>\n cmd.label.toLowerCase().includes(query.toLowerCase()) ||\n cmd.description?.toLowerCase().includes(query.toLowerCase()) ||\n cmd.category?.toLowerCase().includes(query.toLowerCase()),\n )\n : commands;\n\n // Clamp selected index\n useEffect(() => {\n if (selectedIndex >= filtered.length) {\n setSelectedIndex(Math.max(0, filtered.length - 1));\n }\n }, [filtered.length, selectedIndex]);\n\n // Scroll selected item into view\n useEffect(() => {\n const list = listRef.current;\n if (!list) return;\n const selected = list.children[selectedIndex] as HTMLElement | undefined;\n selected?.scrollIntoView({ block: \"nearest\" });\n }, [selectedIndex]);\n\n function executeCommand(cmd: CommandItem) {\n toggle(false);\n if (typeof cmd.action === \"string\") {\n sendMessage({ text: cmd.action });\n } else {\n cmd.action();\n }\n }\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.min(prev + 1, filtered.length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.max(prev - 1, 0));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (filtered[selectedIndex]) {\n executeCommand(filtered[selectedIndex]);\n } else if (query.trim()) {\n // Send raw query as AI prompt\n toggle(false);\n sendMessage({ text: query });\n }\n } else if (e.key === \"Escape\") {\n toggle(false);\n }\n }\n\n if (!open) return null;\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n // Group by category\n const grouped = new Map<string, CommandItem[]>();\n for (const cmd of filtered) {\n const cat = cmd.category ?? \"Actions\";\n if (!grouped.has(cat)) grouped.set(cat, []);\n grouped.get(cat)!.push(cmd);\n }\n\n let flatIndex = 0;\n\n return (\n <>\n {/* Backdrop — keyboard-dismissable via Escape (handled in handleKeyDown) */}\n <div\n onClick={() => toggle(false)}\n style={{\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n zIndex: 99998,\n }}\n // aria-hidden so screen readers go straight to the dialog\n aria-hidden=\"true\"\n />\n\n {/* Palette dialog */}\n <div\n ref={dialogRef}\n style={{\n ...themeVars,\n position: \"fixed\",\n top: \"20%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n width: \"min(520px, 90vw)\",\n maxHeight: \"60vh\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n boxShadow: \"0 24px 48px rgba(0,0,0,0.3)\",\n overflow: \"hidden\",\n zIndex: 99999,\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n // tabIndex={-1} so the dialog element itself can receive programmatic focus\n tabIndex={-1}\n >\n {/* Visually hidden dialog title for screen readers */}\n <h2 id={titleId} style={srOnly}>\n Command Palette\n </h2>\n\n {/* Search input */}\n <div style={{ padding: \"12px 16px\", borderBottom: \"1px solid var(--ai-me-border)\" }}>\n <label htmlFor={inputId} style={srOnly}>\n Search commands or ask AI\n </label>\n <input\n id={inputId}\n ref={inputRef}\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setSelectedIndex(0);\n }}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a command or ask AI...\"\n style={{\n width: \"100%\",\n padding: \"8px 0\",\n border: \"none\",\n // Do NOT suppress the outline entirely — use transparent + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n fontSize: 15,\n fontFamily: \"var(--ai-me-font)\",\n backgroundColor: \"transparent\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"ai-me-cmd-listbox\"\n aria-activedescendant={\n filtered[selectedIndex]\n ? `cmd-${filtered[selectedIndex].id}`\n : undefined\n }\n />\n </div>\n\n {/* Results listbox */}\n <div\n id=\"ai-me-cmd-listbox\"\n ref={listRef}\n style={{ overflowY: \"auto\", padding: \"8px 0\" }}\n role=\"listbox\"\n aria-label=\"Commands\"\n >\n {filtered.length === 0 && query.trim() && (\n <div\n role=\"option\"\n aria-selected=\"false\"\n style={{\n padding: \"16px\",\n textAlign: \"center\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n Press Enter to ask AI: “{query}”\n </div>\n )}\n\n {Array.from(grouped.entries()).map(([category, items]) => (\n // role=\"group\" with aria-label for the category heading\n <div key={category} role=\"group\" aria-label={category}>\n {/* Category heading — aria-hidden because role=\"group\" aria-label carries the name */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"6px 16px 4px\",\n fontSize: 11,\n fontWeight: 500,\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {category}\n </div>\n {items.map((cmd) => {\n const idx = flatIndex++;\n const isSelected = idx === selectedIndex;\n return (\n <div\n key={cmd.id}\n id={`cmd-${cmd.id}`}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => executeCommand(cmd)}\n onMouseEnter={() => setSelectedIndex(idx)}\n // Allow keyboard activation of each option when it has focus\n tabIndex={isSelected ? 0 : -1}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n executeCommand(cmd);\n }\n }}\n style={{\n padding: \"8px 16px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: isSelected\n ? \"var(--ai-me-bg-secondary)\"\n : \"transparent\",\n outline: \"2px solid transparent\",\n outlineOffset: -2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {cmd.icon && (\n // Icon is decorative — label comes from cmd.label\n <span aria-hidden=\"true\" style={{ fontSize: 16, flexShrink: 0 }}>\n {cmd.icon}\n </span>\n )}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontSize: 14, fontWeight: 500 }}>\n {cmd.label}\n </div>\n {cmd.description && (\n <div\n style={{\n fontSize: 12,\n color: \"var(--ai-me-text-secondary)\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {cmd.description}\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n\n {/* Footer keyboard hints — aria-hidden because these are redundant for screen readers\n (keyboard shortcuts are announced via aria-keyshortcuts on the input) */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"8px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n fontSize: 11,\n color: \"var(--ai-me-text-secondary)\",\n display: \"flex\",\n gap: 16,\n }}\n >\n <span>↑↓ Navigate</span>\n <span>↵ Select</span>\n <span>Esc Close</span>\n </div>\n </div>\n </>\n );\n}\n","import { useRef, useEffect, useId, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars } from \"./styles.js\";\n\nexport interface AIMeConfirmProps {\n /** Tool/action name */\n action: string;\n /** Description of what will happen */\n description: string;\n /** Parameters being sent */\n parameters?: Record<string, unknown>;\n /** Callback when user confirms */\n onConfirm: () => void;\n /** Callback when user rejects */\n onReject: () => void;\n}\n\nexport function AIMeConfirm({\n action,\n description,\n parameters,\n onConfirm,\n onReject,\n}: AIMeConfirmProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n\n // Stable IDs for ARIA associations\n const titleId = useId();\n const descriptionId = useId();\n\n // Close on Escape and focus-trap within the dialog\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onReject();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onReject],\n );\n\n // Auto-focus the Cancel button when the dialog mounts (safe default for\n // destructive confirmations — avoids accidental confirmation on Enter).\n // Also wire up Escape / focus-trap and restore focus on unmount.\n useEffect(() => {\n const previousFocus = document.activeElement as HTMLElement | null;\n\n cancelButtonRef.current?.focus();\n window.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n // Restore focus to whatever triggered the dialog\n previousFocus?.focus();\n };\n }, [handleKeyDown]);\n\n const overlayStyle: CSSProperties = {\n ...defaultThemeVars,\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.4)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10000,\n fontFamily: \"var(--ai-me-font)\",\n } as CSSProperties;\n\n const dialogStyle: CSSProperties = {\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n padding: 24,\n maxWidth: 420,\n width: \"90%\",\n boxShadow: \"var(--ai-me-shadow)\",\n color: \"var(--ai-me-text)\",\n };\n\n const focusStyle: CSSProperties = {\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n };\n\n function applyFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid var(--ai-me-primary)\";\n el.style.outlineOffset = \"2px\";\n }\n\n function removeFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid transparent\";\n el.style.outlineOffset = \"2px\";\n }\n\n return (\n // Overlay is presentational — role and aria go on the inner dialog\n <div\n style={overlayStyle}\n // Clicking outside the dialog rejects (same as pressing Escape)\n onClick={(e) => {\n if (e.target === e.currentTarget) onReject();\n }}\n aria-hidden=\"false\"\n >\n <div\n ref={dialogRef}\n style={dialogStyle}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n // tabIndex={-1} allows programmatic focus on the dialog element itself\n tabIndex={-1}\n // Prevent clicks inside the dialog from bubbling to the overlay\n onClick={(e) => e.stopPropagation()}\n >\n <h3 id={titleId} style={{ margin: \"0 0 8px\", fontSize: 16 }}>\n Confirm Action\n </h3>\n <p style={{ margin: \"0 0 4px\", fontSize: 14, fontWeight: 600 }}>\n {action}\n </p>\n <p\n id={descriptionId}\n style={{\n margin: \"0 0 16px\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {description}\n </p>\n\n {parameters && Object.keys(parameters).length > 0 && (\n <pre\n style={{\n margin: \"0 0 16px\",\n padding: 12,\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n borderRadius: 8,\n fontSize: 12,\n overflow: \"auto\",\n maxHeight: 200,\n border: \"1px solid var(--ai-me-border)\",\n }}\n >\n {JSON.stringify(parameters, null, 2)}\n </pre>\n )}\n\n <div style={{ display: \"flex\", gap: 8, justifyContent: \"flex-end\" }}>\n {/* Cancel is focused first — avoids accidental confirmation */}\n <button\n ref={cancelButtonRef}\n type=\"button\"\n onClick={onReject}\n style={{\n padding: \"8px 16px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n style={{\n padding: \"8px 16px\",\n border: \"none\",\n borderRadius: 8,\n // #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Confirm\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","srOnly","handleKeyDown","import_react","import_jsx_runtime"]}
|
package/dist/index.js
CHANGED
|
@@ -661,30 +661,34 @@ function AIMeChat({
|
|
|
661
661
|
}
|
|
662
662
|
)
|
|
663
663
|
] }),
|
|
664
|
-
messages.map((m) =>
|
|
665
|
-
"
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
664
|
+
messages.map((m) => {
|
|
665
|
+
const hasTextContent = m.parts.some((p) => p.type === "text");
|
|
666
|
+
if (!hasTextContent && m.role === "assistant") return null;
|
|
667
|
+
return /* @__PURE__ */ jsxs(
|
|
668
|
+
"div",
|
|
669
|
+
{
|
|
670
|
+
style: {
|
|
671
|
+
alignSelf: m.role === "user" ? "flex-end" : "flex-start",
|
|
672
|
+
maxWidth: "85%",
|
|
673
|
+
padding: "8px 12px",
|
|
674
|
+
borderRadius: 8,
|
|
675
|
+
backgroundColor: m.role === "user" ? "var(--ai-me-primary)" : "var(--ai-me-bg-secondary)",
|
|
676
|
+
color: m.role === "user" ? "#fff" : "var(--ai-me-text)",
|
|
677
|
+
fontSize: 14,
|
|
678
|
+
lineHeight: 1.5,
|
|
679
|
+
whiteSpace: "pre-wrap",
|
|
680
|
+
wordBreak: "break-word"
|
|
681
|
+
},
|
|
682
|
+
children: [
|
|
683
|
+
/* @__PURE__ */ jsx3("span", { style: srOnly, children: m.role === "user" ? "You: " : "Assistant: " }),
|
|
684
|
+
m.parts.map(
|
|
685
|
+
(p, i) => p.type === "text" ? /* @__PURE__ */ jsx3("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
686
|
+
)
|
|
687
|
+
]
|
|
678
688
|
},
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
(p, i) => p.type === "text" ? /* @__PURE__ */ jsx3("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
683
|
-
)
|
|
684
|
-
]
|
|
685
|
-
},
|
|
686
|
-
m.id
|
|
687
|
-
)),
|
|
689
|
+
m.id
|
|
690
|
+
);
|
|
691
|
+
}),
|
|
688
692
|
status === "submitted" && /* @__PURE__ */ jsx3(
|
|
689
693
|
"div",
|
|
690
694
|
{
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/provider.tsx","../src/chat.tsx","../src/use-ai-me.ts","../src/styles.ts","../src/markdown.tsx","../src/command-palette.tsx","../src/confirm.tsx"],"sourcesContent":["import { createContext, useContext } from \"react\";\n\n/** Payload passed to the `onAction` callback */\nexport interface AIMeAction {\n /** Action type — e.g. \"navigate\", \"prefill\", \"open-modal\" */\n type: string;\n /** Flexible additional payload supplied by the AI tool */\n [key: string]: unknown;\n}\n\nexport interface AIMeContextValue {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n * Use this to handle navigation, form pre-fill, modal opening, etc.\n * without the AI making an API call directly.\n */\n onAction?: (action: AIMeAction) => void;\n}\n\nexport const AIMeContext = createContext<AIMeContextValue | null>(null);\n\nexport function useAIMeContext(): AIMeContextValue {\n const ctx = useContext(AIMeContext);\n if (!ctx) {\n throw new Error(\"useAIMe must be used within an <AIMeProvider>\");\n }\n return ctx;\n}\n","import type { ReactNode } from \"react\";\nimport { AIMeContext } from \"./context.js\";\nimport type { AIMeAction } from \"./context.js\";\n\nexport interface AIMeProviderProps {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Optional: additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n *\n * The AI can emit structured actions (e.g. \"navigate\", \"prefill\",\n * \"open-modal\") that your app handles without making an API call.\n * Wire the corresponding `__navigate` / `__prefill` tools in your\n * AI-Me handler to produce these actions, then consume them here.\n *\n * @example\n * ```tsx\n * <AIMeProvider\n * endpoint=\"/api/ai-me\"\n * onAction={(action) => {\n * if (action.type === \"navigate\") {\n * router.push(action.href as string);\n * }\n * }}\n * >\n * {children}\n * </AIMeProvider>\n * ```\n */\n onAction?: (action: AIMeAction) => void;\n /** Child components */\n children: ReactNode;\n}\n\nexport function AIMeProvider({ endpoint, headers, onAction, children }: AIMeProviderProps) {\n return (\n <AIMeContext value={{ endpoint, headers, onAction }}>\n {children}\n </AIMeContext>\n );\n}\n","import { useState, useRef, useEffect, useCallback, useId } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useAIMe } from \"./use-ai-me.js\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { renderMarkdown } from \"./markdown.js\";\n\n/** Tool execution result passed to onToolComplete */\nexport interface ToolCompleteEvent {\n /** Tool (function) name */\n name: string;\n /** HTTP method used, if available from the tool result */\n httpMethod?: string;\n /** API path called, if available from the tool result */\n path?: string;\n /** Raw result returned by the tool */\n result: unknown;\n /** Whether the tool required user confirmation */\n requiresConfirmation?: boolean;\n}\n\n/** Completed assistant message passed to onMessageComplete */\nexport interface MessageCompleteEvent {\n role: string;\n content: string;\n toolCalls?: unknown[];\n}\n\nexport interface AIMeChatProps {\n /** Position of chat panel */\n position?: \"bottom-right\" | \"bottom-left\" | \"inline\";\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Welcome message shown on empty chat */\n welcomeMessage?: string;\n /** Suggested prompts shown on empty chat */\n suggestedPrompts?: string[];\n /** Whether chat starts open */\n defaultOpen?: boolean;\n /** Callback when chat opens/closes */\n onToggle?: (open: boolean) => void;\n /**\n * Fired after each tool execution completes (after the API call returns).\n * Use this to trigger client-side data refreshes when the AI mutates data.\n */\n onToolComplete?: (tool: ToolCompleteEvent) => void;\n /**\n * Fired when the assistant finishes a full response (status transitions\n * from \"streaming\" to \"ready\").\n */\n onMessageComplete?: (message: MessageCompleteEvent) => void;\n /**\n * Custom renderer for the tool confirmation dialog.\n *\n * When provided, AI-Me will call this function instead of showing the\n * default confirmation UI. Return any React node — a modal, an inline\n * card, a drawer, etc.\n *\n * If not provided, the built-in `<AIMeConfirm>` dialog is used.\n *\n * @example\n * ```tsx\n * <AIMeChat\n * renderConfirmation={({ tool, params, onConfirm, onCancel }) => (\n * <MyCustomConfirmDialog\n * title={`Run ${tool.name}?`}\n * description={tool.description}\n * params={params}\n * onConfirm={onConfirm}\n * onCancel={onCancel}\n * />\n * )}\n * />\n * ```\n */\n renderConfirmation?: (props: {\n /** Metadata about the tool that is about to be executed */\n tool: {\n /** Tool (function) name */\n name: string;\n /** HTTP method the tool maps to, e.g. \"POST\" */\n httpMethod: string;\n /** API path the tool will call, e.g. \"/api/projects\" */\n path: string;\n /** Human-readable description of what the tool does */\n description: string;\n };\n /** Resolved parameters the tool will be called with */\n params: Record<string, unknown>;\n /** Call to proceed with the tool execution */\n onConfirm: () => void;\n /** Call to abort without executing the tool */\n onCancel: () => void;\n }) => ReactNode;\n}\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeChat({\n position = \"bottom-right\",\n theme,\n welcomeMessage = \"Hi! I can help you navigate and use this app. What would you like to do?\",\n suggestedPrompts,\n defaultOpen = false,\n onToggle,\n onToolComplete,\n onMessageComplete,\n}: AIMeChatProps) {\n const [open, setOpen] = useState(defaultOpen);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // Track tool-result part IDs that have already fired onToolComplete\n const firedToolResults = useRef<Set<string>>(new Set());\n // Track the previous status to detect the streaming → ready transition\n const prevStatus = useRef<string | null>(null);\n const {\n messages,\n input,\n handleInputChange,\n handleSubmit,\n status,\n error,\n setInput,\n } = useAIMe();\n\n // Stable IDs for aria-labelledby / aria-describedby\n const titleId = useId();\n const messagesId = useId();\n\n const isInline = position === \"inline\";\n\n const toggleOpen = useCallback(() => {\n const next = !open;\n setOpen(next);\n onToggle?.(next);\n }, [open, onToggle]);\n\n // Keyboard shortcut: Cmd+. to toggle\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \".\") {\n e.preventDefault();\n toggleOpen();\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleOpen]);\n\n // Scroll to bottom on new messages\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n // Fire onToolComplete for each new tool-result part observed in messages.\n // We deduplicate by tracking the tool-call ID so the callback fires exactly\n // once per tool execution, even across re-renders during streaming.\n useEffect(() => {\n if (!onToolComplete) return;\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type !== \"tool-result\") continue;\n // Each tool-result part has a stable toolCallId\n const id = (part as { toolCallId?: string }).toolCallId;\n const dedupeKey = id ?? `${message.id}:${part.type}`;\n if (firedToolResults.current.has(dedupeKey)) continue;\n firedToolResults.current.add(dedupeKey);\n onToolComplete({\n name: (part as { toolName?: string }).toolName ?? \"\",\n result: (part as { result?: unknown }).result,\n });\n }\n }\n }, [messages, onToolComplete]);\n\n // Fire onMessageComplete when status transitions from streaming → ready.\n // prevStatus tracks the last seen status so we only fire on the transition.\n useEffect(() => {\n const prev = prevStatus.current;\n prevStatus.current = status;\n\n if (!onMessageComplete) return;\n // Only fire on the transition away from an active streaming state\n if (status !== \"ready\") return;\n if (prev !== \"streaming\" && prev !== \"submitted\") return;\n\n // Find the last assistant message\n // Walk backwards to find the most recent assistant message without copying the array\n let lastAssistant: (typeof messages)[number] | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"assistant\") { lastAssistant = messages[i]; break; }\n }\n if (!lastAssistant) return;\n\n const textContent = lastAssistant.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n\n const toolCalls: unknown[] = lastAssistant.parts.filter((p) => p.type === \"tool-call\");\n\n onMessageComplete({\n role: lastAssistant.role,\n content: textContent,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n });\n }, [status, messages, onMessageComplete]);\n\n // Focus panel when opened; return focus to trigger when closed\n useEffect(() => {\n if (open) {\n // Shift focus into the panel so screen readers announce the dialog\n panelRef.current?.focus();\n // Then move focus to the input after a tick so the panel focus is set first\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to the trigger that opened the panel\n triggerRef.current?.focus();\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the panel while open\n useEffect(() => {\n if (!open || isInline) return;\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n toggleOpen();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const panel = panelRef.current;\n if (!panel) return;\n\n const focusable = panel.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, isInline, toggleOpen]);\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n const panelStyle: CSSProperties = isInline\n ? {\n ...themeVars,\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n }\n : {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 380,\n height: \"70vh\",\n maxHeight: 600,\n display: open ? \"flex\" : \"none\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n boxShadow: \"var(--ai-me-shadow)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n zIndex: 9999,\n };\n\n const triggerStyle: CSSProperties = {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n cursor: \"pointer\",\n display: isInline || open ? \"none\" : \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"var(--ai-me-shadow)\",\n fontSize: 24,\n zIndex: 9999,\n };\n\n const isStreaming = status === \"submitted\" || status === \"streaming\";\n\n return (\n <>\n {/* Floating trigger button */}\n <button\n ref={triggerRef}\n onClick={toggleOpen}\n style={triggerStyle}\n aria-label=\"Open AI chat\"\n aria-expanded={open}\n aria-controls={isInline ? undefined : \"ai-me-chat-panel\"}\n type=\"button\"\n >\n {/* Icon is decorative; label is on the button */}\n <span aria-hidden=\"true\">💬</span>\n </button>\n\n {/* Chat panel */}\n <div\n id=\"ai-me-chat-panel\"\n ref={panelRef}\n style={panelStyle}\n role=\"dialog\"\n aria-modal={isInline ? undefined : \"true\"}\n aria-labelledby={titleId}\n aria-busy={isStreaming}\n // tabIndex={-1} allows programmatic focus on the panel element itself\n tabIndex={-1}\n >\n {/* Header */}\n <div\n style={{\n padding: \"12px 16px\",\n borderBottom: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n }}\n >\n <span id={titleId} style={{ fontWeight: 600, fontSize: 14 }}>\n AI Assistant\n </span>\n {!isInline && (\n <button\n onClick={toggleOpen}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: 18,\n color: \"var(--ai-me-text-secondary)\",\n padding: 4,\n borderRadius: 4,\n // Visible focus indicator without outline:none\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Close chat\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">✕</span>\n </button>\n )}\n </div>\n\n {/* Skip link: jump straight to the input */}\n <a\n href=\"#ai-me-chat-input\"\n style={{\n ...srOnly,\n // Reveal on focus so keyboard users can see it\n }}\n onFocus={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, {\n position: \"static\",\n width: \"auto\",\n height: \"auto\",\n padding: \"4px 8px\",\n margin: 0,\n overflow: \"visible\",\n clip: \"auto\",\n whiteSpace: \"normal\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n fontSize: 12,\n borderRadius: 4,\n });\n }}\n onBlur={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, srOnly);\n }}\n >\n Skip to message input\n </a>\n\n {/* Messages — live region so screen readers announce new content */}\n <div\n id={messagesId}\n aria-live=\"polite\"\n aria-label=\"Conversation\"\n aria-relevant=\"additions\"\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n }}\n >\n {messages.length === 0 && (\n <div style={{ color: \"var(--ai-me-text-secondary)\", fontSize: 14 }}>\n <p>{welcomeMessage}</p>\n {suggestedPrompts && suggestedPrompts.length > 0 && (\n <div\n style={{\n marginTop: 12,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 8,\n }}\n >\n <p style={{ margin: \"0 0 4px\", fontSize: 12, fontWeight: 500 }}>\n Suggested questions:\n </p>\n {suggestedPrompts.map((prompt) => (\n <button\n key={prompt}\n type=\"button\"\n onClick={() => {\n setInput(prompt);\n inputRef.current?.focus();\n }}\n style={{\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n background: \"var(--ai-me-bg)\",\n cursor: \"pointer\",\n textAlign: \"left\",\n fontSize: 13,\n color: \"var(--ai-me-text)\",\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {prompt}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {messages.map((m) => (\n <div\n key={m.id}\n style={{\n alignSelf: m.role === \"user\" ? \"flex-end\" : \"flex-start\",\n maxWidth: \"85%\",\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor:\n m.role === \"user\"\n ? \"var(--ai-me-primary)\"\n : \"var(--ai-me-bg-secondary)\",\n color: m.role === \"user\" ? \"#fff\" : \"var(--ai-me-text)\",\n fontSize: 14,\n lineHeight: 1.5,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n }}\n >\n {/* Screen reader role prefix */}\n <span style={srOnly}>\n {m.role === \"user\" ? \"You: \" : \"Assistant: \"}\n </span>\n {m.parts.map((p, i) =>\n p.type === \"text\" ? (\n <span key={i}>\n {m.role === \"assistant\"\n ? renderMarkdown(p.text)\n : p.text}\n </span>\n ) : null,\n )}\n </div>\n ))}\n\n {/* \"Thinking\" indicator — announced by the live region above */}\n {status === \"submitted\" && (\n <div\n aria-label=\"Assistant is thinking\"\n style={{\n alignSelf: \"flex-start\",\n color: \"var(--ai-me-text-secondary)\",\n fontSize: 13,\n }}\n >\n <span aria-hidden=\"true\">Thinking…</span>\n </div>\n )}\n\n {/* Error — role=\"alert\" ensures immediate announcement */}\n {error && (\n <div\n role=\"alert\"\n style={{\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor: \"#fef2f2\",\n // #dc2626 on #fef2f2 ≈ 5.1:1 — passes AA for normal text\n color: \"#dc2626\",\n fontSize: 13,\n border: \"1px solid #fca5a5\",\n }}\n >\n Something went wrong. Please try again.\n </div>\n )}\n\n <div ref={messagesEndRef} aria-hidden=\"true\" />\n </div>\n\n {/* Input */}\n <form\n onSubmit={handleSubmit}\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n gap: 8,\n }}\n >\n {/* Visible label for the input (positioned absolutely so only visible on focus for compact layout) */}\n <label\n htmlFor=\"ai-me-chat-input\"\n style={srOnly}\n >\n Message to AI Assistant\n </label>\n <input\n id=\"ai-me-chat-input\"\n ref={inputRef}\n value={input}\n onChange={handleInputChange}\n placeholder=\"Ask anything…\"\n disabled={status !== \"ready\"}\n aria-disabled={status !== \"ready\"}\n style={{\n flex: 1,\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n // Do NOT use outline:none — use outline with transparent color + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n />\n <button\n type=\"submit\"\n disabled={status !== \"ready\" || !input.trim()}\n aria-disabled={status !== \"ready\" || !input.trim()}\n style={{\n padding: \"8px 16px\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 8,\n cursor: status === \"ready\" && input.trim() ? \"pointer\" : \"not-allowed\",\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n opacity: status === \"ready\" && input.trim() ? 1 : 0.5,\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n (e.currentTarget as HTMLButtonElement).style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Send message\"\n >\n Send\n </button>\n </form>\n </div>\n </>\n );\n}\n","import { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useState, useCallback, useEffect, useRef } from \"react\";\nimport { useAIMeContext } from \"./context.js\";\n\nconst STORAGE_KEY = \"ai-me-messages\";\n\n/**\n * Hook wrapping AI SDK's useChat with AI-Me configuration.\n * Provides chat state, message handling, confirmation support,\n * and session persistence (survives page navigation within the same tab).\n */\nexport function useAIMe() {\n const { endpoint, headers } = useAIMeContext();\n const [input, setInput] = useState(\"\");\n const initialized = useRef(false);\n\n const chat = useChat({\n transport: new DefaultChatTransport({\n api: endpoint,\n headers,\n }),\n });\n\n // Restore messages from sessionStorage on mount\n useEffect(() => {\n if (initialized.current) return;\n initialized.current = true;\n\n try {\n const stored = sessionStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (Array.isArray(parsed) && parsed.length > 0) {\n chat.setMessages(parsed);\n }\n }\n } catch {\n // ignore — sessionStorage may be unavailable or corrupted\n }\n }, []);\n\n // Persist messages to sessionStorage on change\n useEffect(() => {\n if (!initialized.current) return;\n try {\n if (chat.messages.length > 0) {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(chat.messages));\n } else {\n sessionStorage.removeItem(STORAGE_KEY);\n }\n } catch {\n // ignore\n }\n }, [chat.messages]);\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setInput(e.target.value);\n },\n [],\n );\n\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n if (!input.trim()) return;\n chat.sendMessage({ text: input });\n setInput(\"\");\n },\n [input, chat],\n );\n\n const clearMessages = useCallback(() => {\n chat.setMessages([]);\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n }, [chat]);\n\n return {\n /** Conversation messages */\n messages: chat.messages,\n /** Current input value */\n input,\n /** Set input value */\n setInput,\n /** Handle input change */\n handleInputChange,\n /** Submit the current message */\n handleSubmit,\n /** Send a message directly */\n sendMessage: chat.sendMessage,\n /** Chat status: \"ready\" | \"submitted\" | \"streaming\" */\n status: chat.status,\n /** Error if any */\n error: chat.error,\n /** Stop streaming */\n stop: chat.stop,\n /** Set messages */\n setMessages: chat.setMessages,\n /** Clear all messages and session storage */\n clearMessages,\n };\n}\n","/**\n * CSS custom properties for AI-Me theming.\n * All prefixed with --ai-me- to avoid conflicts with host app styles.\n */\nexport const defaultThemeVars = {\n \"--ai-me-primary\": \"#6366f1\",\n \"--ai-me-primary-hover\": \"#4f46e5\",\n \"--ai-me-bg\": \"#ffffff\",\n \"--ai-me-bg-secondary\": \"#f9fafb\",\n \"--ai-me-text\": \"#111827\",\n \"--ai-me-text-secondary\": \"#6b7280\",\n \"--ai-me-border\": \"#e5e7eb\",\n \"--ai-me-radius\": \"12px\",\n \"--ai-me-font\": \"system-ui, -apple-system, sans-serif\",\n \"--ai-me-shadow\": \"0 4px 24px rgba(0, 0, 0, 0.12)\",\n} as const;\n\nexport interface AIMeTheme {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n}\n\nexport function themeToVars(theme?: AIMeTheme): Record<string, string> {\n if (!theme) return {};\n const vars: Record<string, string> = {};\n if (theme.primaryColor) vars[\"--ai-me-primary\"] = theme.primaryColor;\n if (theme.backgroundColor) vars[\"--ai-me-bg\"] = theme.backgroundColor;\n if (theme.textColor) vars[\"--ai-me-text\"] = theme.textColor;\n if (theme.borderRadius) vars[\"--ai-me-radius\"] = theme.borderRadius;\n if (theme.fontFamily) vars[\"--ai-me-font\"] = theme.fontFamily;\n return vars;\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\n/**\n * Lightweight inline markdown renderer for chat messages.\n * Supports: **bold**, *italic*, `code`, ```code blocks```, [links](url), - lists\n * No external dependencies — renders to React elements with inline styles.\n */\nexport function renderMarkdown(text: string): ReactNode[] {\n const lines = text.split(\"\\n\");\n const result: ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Fenced code block\n if (line.trimStart().startsWith(\"```\")) {\n const lang = line.trimStart().slice(3).trim();\n const codeLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].trimStart().startsWith(\"```\")) {\n codeLines.push(lines[i]);\n i++;\n }\n i++; // skip closing ```\n result.push(\n <pre\n key={`code-${result.length}`}\n style={codeBlockStyle}\n data-lang={lang || undefined}\n >\n <code>{codeLines.join(\"\\n\")}</code>\n </pre>,\n );\n continue;\n }\n\n // Unordered list item\n if (/^[\\s]*[-*]\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*[-*]\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*[-*]\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ul\n key={`ul-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20, listStyleType: \"disc\" }}\n >\n {listItems}\n </ul>,\n );\n continue;\n }\n\n // Ordered list item\n if (/^[\\s]*\\d+\\.\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*\\d+\\.\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*\\d+\\.\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ol\n key={`ol-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20 }}\n >\n {listItems}\n </ol>,\n );\n continue;\n }\n\n // Heading (clamp to h3+ in chat context)\n const headingMatch = /^(#{1,6})\\s+(.+)$/.exec(line);\n if (headingMatch) {\n const level = Math.max(headingMatch[1].length, 3);\n const fontSize =\n ({ 3: 15, 4: 14, 5: 13, 6: 13 } as Record<number, number>)[level] ??\n 14;\n result.push(\n <p\n key={`h-${result.length}`}\n style={{ fontWeight: 600, fontSize, margin: \"8px 0 4px\" }}\n >\n {renderInline(headingMatch[2])}\n </p>,\n );\n i++;\n continue;\n }\n\n // Empty line\n if (line.trim() === \"\") {\n i++;\n continue;\n }\n\n // Regular text\n result.push(\n <span\n key={`p-${result.length}`}\n style={{ display: \"block\", marginBottom: 2 }}\n >\n {renderInline(line)}\n </span>,\n );\n i++;\n }\n\n return result;\n}\n\n/** Parse inline markdown: bold, italic, code, links */\nfunction renderInline(text: string): ReactNode[] {\n const result: ReactNode[] = [];\n const pattern = /(`[^`]+`|\\*\\*[^*]+\\*\\*|\\*[^*]+\\*|\\[[^\\]]+\\]\\([^)]+\\))/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n if (match.index > lastIndex) {\n result.push(text.slice(lastIndex, match.index));\n }\n\n const token = match[0];\n\n if (token.startsWith(\"`\")) {\n result.push(\n <code key={result.length} style={inlineCodeStyle}>\n {token.slice(1, -1)}\n </code>,\n );\n } else if (token.startsWith(\"**\")) {\n result.push(\n <strong key={result.length}>{token.slice(2, -2)}</strong>,\n );\n } else if (token.startsWith(\"*\")) {\n result.push(<em key={result.length}>{token.slice(1, -1)}</em>);\n } else if (token.startsWith(\"[\")) {\n const linkMatch = /\\[([^\\]]+)\\]\\(([^)]+)\\)/.exec(token);\n if (linkMatch) {\n result.push(\n <a\n key={result.length}\n href={linkMatch[2]}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={linkStyle}\n >\n {linkMatch[1]}\n </a>,\n );\n }\n }\n\n lastIndex = match.index + token.length;\n }\n\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return result;\n}\n\nconst codeBlockStyle: CSSProperties = {\n margin: \"6px 0\",\n padding: \"10px 12px\",\n borderRadius: 6,\n backgroundColor: \"rgba(0,0,0,0.15)\",\n fontSize: 12,\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n overflow: \"auto\",\n whiteSpace: \"pre\",\n lineHeight: 1.5,\n};\n\nconst inlineCodeStyle: CSSProperties = {\n padding: \"1px 5px\",\n borderRadius: 3,\n backgroundColor: \"rgba(0,0,0,0.12)\",\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: \"0.9em\",\n};\n\nconst linkStyle: CSSProperties = {\n color: \"var(--ai-me-primary, #6366f1)\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n};\n","import { useState, useEffect, useRef, useCallback, useId } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { useAIMe } from \"./use-ai-me.js\";\n\nexport interface AIMeCommandPaletteProps {\n /** List of available commands/actions */\n commands?: CommandItem[];\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Custom keyboard shortcut (default: Cmd+K / Ctrl+K) */\n shortcut?: { key: string; meta?: boolean; ctrl?: boolean };\n /** Callback when palette opens/closes */\n onToggle?: (open: boolean) => void;\n}\n\nexport interface CommandItem {\n /** Unique command ID */\n id: string;\n /** Display label */\n label: string;\n /** Description shown below label */\n description?: string;\n /** Category for grouping */\n category?: string;\n /** Icon (emoji or text) */\n icon?: string;\n /** Action to run — either a callback or a prompt to send to AI */\n action: (() => void) | string;\n}\n\nconst defaultCommands: CommandItem[] = [\n {\n id: \"help\",\n label: \"Ask AI for help\",\n description: \"Get assistance with any task\",\n category: \"AI\",\n icon: \"💡\",\n action: \"What can you help me with?\",\n },\n {\n id: \"list-actions\",\n label: \"List available actions\",\n description: \"Show all API actions the AI can perform\",\n category: \"AI\",\n icon: \"📋\",\n action: \"What actions can you perform? List them all.\",\n },\n {\n id: \"recent-activity\",\n label: \"Show recent activity\",\n description: \"Summarize recent actions and changes\",\n category: \"AI\",\n icon: \"🕐\",\n action: \"What has happened recently? Summarize recent activity.\",\n },\n];\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeCommandPalette({\n commands = defaultCommands,\n theme,\n shortcut = { key: \"k\", meta: true },\n onToggle,\n}: AIMeCommandPaletteProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n // Remember what had focus before the palette opened so we can restore it\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const { sendMessage } = useAIMe();\n\n // Stable IDs\n const titleId = useId();\n const inputId = useId();\n\n const toggle = useCallback(\n (next: boolean) => {\n setOpen(next);\n setQuery(\"\");\n setSelectedIndex(0);\n onToggle?.(next);\n },\n [onToggle],\n );\n\n // Keyboard shortcut to open\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n const metaMatch = shortcut.meta ? e.metaKey : true;\n const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;\n if ((metaMatch || ctrlMatch) && e.key === shortcut.key) {\n e.preventDefault();\n // Capture current focus before opening\n if (!open) {\n previousFocusRef.current = document.activeElement as HTMLElement;\n }\n toggle(!open);\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, shortcut, toggle]);\n\n // Focus the search input when opened; restore focus when closed\n useEffect(() => {\n if (open) {\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to whatever had it before the palette opened\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n previousFocusRef.current = null;\n }\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the palette while open\n useEffect(() => {\n if (!open) return;\n\n function handleFocusTrap(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleFocusTrap);\n return () => window.removeEventListener(\"keydown\", handleFocusTrap);\n }, [open]);\n\n // Filter commands by query\n const filtered = query.trim()\n ? commands.filter(\n (cmd) =>\n cmd.label.toLowerCase().includes(query.toLowerCase()) ||\n cmd.description?.toLowerCase().includes(query.toLowerCase()) ||\n cmd.category?.toLowerCase().includes(query.toLowerCase()),\n )\n : commands;\n\n // Clamp selected index\n useEffect(() => {\n if (selectedIndex >= filtered.length) {\n setSelectedIndex(Math.max(0, filtered.length - 1));\n }\n }, [filtered.length, selectedIndex]);\n\n // Scroll selected item into view\n useEffect(() => {\n const list = listRef.current;\n if (!list) return;\n const selected = list.children[selectedIndex] as HTMLElement | undefined;\n selected?.scrollIntoView({ block: \"nearest\" });\n }, [selectedIndex]);\n\n function executeCommand(cmd: CommandItem) {\n toggle(false);\n if (typeof cmd.action === \"string\") {\n sendMessage({ text: cmd.action });\n } else {\n cmd.action();\n }\n }\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.min(prev + 1, filtered.length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.max(prev - 1, 0));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (filtered[selectedIndex]) {\n executeCommand(filtered[selectedIndex]);\n } else if (query.trim()) {\n // Send raw query as AI prompt\n toggle(false);\n sendMessage({ text: query });\n }\n } else if (e.key === \"Escape\") {\n toggle(false);\n }\n }\n\n if (!open) return null;\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n // Group by category\n const grouped = new Map<string, CommandItem[]>();\n for (const cmd of filtered) {\n const cat = cmd.category ?? \"Actions\";\n if (!grouped.has(cat)) grouped.set(cat, []);\n grouped.get(cat)!.push(cmd);\n }\n\n let flatIndex = 0;\n\n return (\n <>\n {/* Backdrop — keyboard-dismissable via Escape (handled in handleKeyDown) */}\n <div\n onClick={() => toggle(false)}\n style={{\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n zIndex: 99998,\n }}\n // aria-hidden so screen readers go straight to the dialog\n aria-hidden=\"true\"\n />\n\n {/* Palette dialog */}\n <div\n ref={dialogRef}\n style={{\n ...themeVars,\n position: \"fixed\",\n top: \"20%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n width: \"min(520px, 90vw)\",\n maxHeight: \"60vh\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n boxShadow: \"0 24px 48px rgba(0,0,0,0.3)\",\n overflow: \"hidden\",\n zIndex: 99999,\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n // tabIndex={-1} so the dialog element itself can receive programmatic focus\n tabIndex={-1}\n >\n {/* Visually hidden dialog title for screen readers */}\n <h2 id={titleId} style={srOnly}>\n Command Palette\n </h2>\n\n {/* Search input */}\n <div style={{ padding: \"12px 16px\", borderBottom: \"1px solid var(--ai-me-border)\" }}>\n <label htmlFor={inputId} style={srOnly}>\n Search commands or ask AI\n </label>\n <input\n id={inputId}\n ref={inputRef}\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setSelectedIndex(0);\n }}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a command or ask AI...\"\n style={{\n width: \"100%\",\n padding: \"8px 0\",\n border: \"none\",\n // Do NOT suppress the outline entirely — use transparent + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n fontSize: 15,\n fontFamily: \"var(--ai-me-font)\",\n backgroundColor: \"transparent\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"ai-me-cmd-listbox\"\n aria-activedescendant={\n filtered[selectedIndex]\n ? `cmd-${filtered[selectedIndex].id}`\n : undefined\n }\n />\n </div>\n\n {/* Results listbox */}\n <div\n id=\"ai-me-cmd-listbox\"\n ref={listRef}\n style={{ overflowY: \"auto\", padding: \"8px 0\" }}\n role=\"listbox\"\n aria-label=\"Commands\"\n >\n {filtered.length === 0 && query.trim() && (\n <div\n role=\"option\"\n aria-selected=\"false\"\n style={{\n padding: \"16px\",\n textAlign: \"center\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n Press Enter to ask AI: “{query}”\n </div>\n )}\n\n {Array.from(grouped.entries()).map(([category, items]) => (\n // role=\"group\" with aria-label for the category heading\n <div key={category} role=\"group\" aria-label={category}>\n {/* Category heading — aria-hidden because role=\"group\" aria-label carries the name */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"6px 16px 4px\",\n fontSize: 11,\n fontWeight: 500,\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {category}\n </div>\n {items.map((cmd) => {\n const idx = flatIndex++;\n const isSelected = idx === selectedIndex;\n return (\n <div\n key={cmd.id}\n id={`cmd-${cmd.id}`}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => executeCommand(cmd)}\n onMouseEnter={() => setSelectedIndex(idx)}\n // Allow keyboard activation of each option when it has focus\n tabIndex={isSelected ? 0 : -1}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n executeCommand(cmd);\n }\n }}\n style={{\n padding: \"8px 16px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: isSelected\n ? \"var(--ai-me-bg-secondary)\"\n : \"transparent\",\n outline: \"2px solid transparent\",\n outlineOffset: -2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {cmd.icon && (\n // Icon is decorative — label comes from cmd.label\n <span aria-hidden=\"true\" style={{ fontSize: 16, flexShrink: 0 }}>\n {cmd.icon}\n </span>\n )}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontSize: 14, fontWeight: 500 }}>\n {cmd.label}\n </div>\n {cmd.description && (\n <div\n style={{\n fontSize: 12,\n color: \"var(--ai-me-text-secondary)\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {cmd.description}\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n\n {/* Footer keyboard hints — aria-hidden because these are redundant for screen readers\n (keyboard shortcuts are announced via aria-keyshortcuts on the input) */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"8px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n fontSize: 11,\n color: \"var(--ai-me-text-secondary)\",\n display: \"flex\",\n gap: 16,\n }}\n >\n <span>↑↓ Navigate</span>\n <span>↵ Select</span>\n <span>Esc Close</span>\n </div>\n </div>\n </>\n );\n}\n","import { useRef, useEffect, useId, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars } from \"./styles.js\";\n\nexport interface AIMeConfirmProps {\n /** Tool/action name */\n action: string;\n /** Description of what will happen */\n description: string;\n /** Parameters being sent */\n parameters?: Record<string, unknown>;\n /** Callback when user confirms */\n onConfirm: () => void;\n /** Callback when user rejects */\n onReject: () => void;\n}\n\nexport function AIMeConfirm({\n action,\n description,\n parameters,\n onConfirm,\n onReject,\n}: AIMeConfirmProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n\n // Stable IDs for ARIA associations\n const titleId = useId();\n const descriptionId = useId();\n\n // Close on Escape and focus-trap within the dialog\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onReject();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onReject],\n );\n\n // Auto-focus the Cancel button when the dialog mounts (safe default for\n // destructive confirmations — avoids accidental confirmation on Enter).\n // Also wire up Escape / focus-trap and restore focus on unmount.\n useEffect(() => {\n const previousFocus = document.activeElement as HTMLElement | null;\n\n cancelButtonRef.current?.focus();\n window.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n // Restore focus to whatever triggered the dialog\n previousFocus?.focus();\n };\n }, [handleKeyDown]);\n\n const overlayStyle: CSSProperties = {\n ...defaultThemeVars,\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.4)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10000,\n fontFamily: \"var(--ai-me-font)\",\n } as CSSProperties;\n\n const dialogStyle: CSSProperties = {\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n padding: 24,\n maxWidth: 420,\n width: \"90%\",\n boxShadow: \"var(--ai-me-shadow)\",\n color: \"var(--ai-me-text)\",\n };\n\n const focusStyle: CSSProperties = {\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n };\n\n function applyFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid var(--ai-me-primary)\";\n el.style.outlineOffset = \"2px\";\n }\n\n function removeFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid transparent\";\n el.style.outlineOffset = \"2px\";\n }\n\n return (\n // Overlay is presentational — role and aria go on the inner dialog\n <div\n style={overlayStyle}\n // Clicking outside the dialog rejects (same as pressing Escape)\n onClick={(e) => {\n if (e.target === e.currentTarget) onReject();\n }}\n aria-hidden=\"false\"\n >\n <div\n ref={dialogRef}\n style={dialogStyle}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n // tabIndex={-1} allows programmatic focus on the dialog element itself\n tabIndex={-1}\n // Prevent clicks inside the dialog from bubbling to the overlay\n onClick={(e) => e.stopPropagation()}\n >\n <h3 id={titleId} style={{ margin: \"0 0 8px\", fontSize: 16 }}>\n Confirm Action\n </h3>\n <p style={{ margin: \"0 0 4px\", fontSize: 14, fontWeight: 600 }}>\n {action}\n </p>\n <p\n id={descriptionId}\n style={{\n margin: \"0 0 16px\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {description}\n </p>\n\n {parameters && Object.keys(parameters).length > 0 && (\n <pre\n style={{\n margin: \"0 0 16px\",\n padding: 12,\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n borderRadius: 8,\n fontSize: 12,\n overflow: \"auto\",\n maxHeight: 200,\n border: \"1px solid var(--ai-me-border)\",\n }}\n >\n {JSON.stringify(parameters, null, 2)}\n </pre>\n )}\n\n <div style={{ display: \"flex\", gap: 8, justifyContent: \"flex-end\" }}>\n {/* Cancel is focused first — avoids accidental confirmation */}\n <button\n ref={cancelButtonRef}\n type=\"button\"\n onClick={onReject}\n style={{\n padding: \"8px 16px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n style={{\n padding: \"8px 16px\",\n border: \"none\",\n borderRadius: 8,\n // #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Confirm\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useState","useRef","useEffect","useCallback","jsx","jsx","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","useId","Fragment","jsx","jsxs","srOnly","useState","useRef","useId","useCallback","useEffect","handleKeyDown","useRef","useEffect","useId","useCallback","jsx","jsxs","useRef","useId","useCallback","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/provider.tsx","../src/chat.tsx","../src/use-ai-me.ts","../src/styles.ts","../src/markdown.tsx","../src/command-palette.tsx","../src/confirm.tsx"],"sourcesContent":["import { createContext, useContext } from \"react\";\n\n/** Payload passed to the `onAction` callback */\nexport interface AIMeAction {\n /** Action type — e.g. \"navigate\", \"prefill\", \"open-modal\" */\n type: string;\n /** Flexible additional payload supplied by the AI tool */\n [key: string]: unknown;\n}\n\nexport interface AIMeContextValue {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n * Use this to handle navigation, form pre-fill, modal opening, etc.\n * without the AI making an API call directly.\n */\n onAction?: (action: AIMeAction) => void;\n}\n\nexport const AIMeContext = createContext<AIMeContextValue | null>(null);\n\nexport function useAIMeContext(): AIMeContextValue {\n const ctx = useContext(AIMeContext);\n if (!ctx) {\n throw new Error(\"useAIMe must be used within an <AIMeProvider>\");\n }\n return ctx;\n}\n","import type { ReactNode } from \"react\";\nimport { AIMeContext } from \"./context.js\";\nimport type { AIMeAction } from \"./context.js\";\n\nexport interface AIMeProviderProps {\n /** API endpoint for AI-Me handler */\n endpoint: string;\n /** Optional: additional headers to send with requests */\n headers?: Record<string, string>;\n /**\n * Optional callback for client-side action intents emitted by the AI.\n *\n * The AI can emit structured actions (e.g. \"navigate\", \"prefill\",\n * \"open-modal\") that your app handles without making an API call.\n * Wire the corresponding `__navigate` / `__prefill` tools in your\n * AI-Me handler to produce these actions, then consume them here.\n *\n * @example\n * ```tsx\n * <AIMeProvider\n * endpoint=\"/api/ai-me\"\n * onAction={(action) => {\n * if (action.type === \"navigate\") {\n * router.push(action.href as string);\n * }\n * }}\n * >\n * {children}\n * </AIMeProvider>\n * ```\n */\n onAction?: (action: AIMeAction) => void;\n /** Child components */\n children: ReactNode;\n}\n\nexport function AIMeProvider({ endpoint, headers, onAction, children }: AIMeProviderProps) {\n return (\n <AIMeContext value={{ endpoint, headers, onAction }}>\n {children}\n </AIMeContext>\n );\n}\n","import { useState, useRef, useEffect, useCallback, useId } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useAIMe } from \"./use-ai-me.js\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { renderMarkdown } from \"./markdown.js\";\n\n/** Tool execution result passed to onToolComplete */\nexport interface ToolCompleteEvent {\n /** Tool (function) name */\n name: string;\n /** HTTP method used, if available from the tool result */\n httpMethod?: string;\n /** API path called, if available from the tool result */\n path?: string;\n /** Raw result returned by the tool */\n result: unknown;\n /** Whether the tool required user confirmation */\n requiresConfirmation?: boolean;\n}\n\n/** Completed assistant message passed to onMessageComplete */\nexport interface MessageCompleteEvent {\n role: string;\n content: string;\n toolCalls?: unknown[];\n}\n\nexport interface AIMeChatProps {\n /** Position of chat panel */\n position?: \"bottom-right\" | \"bottom-left\" | \"inline\";\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Welcome message shown on empty chat */\n welcomeMessage?: string;\n /** Suggested prompts shown on empty chat */\n suggestedPrompts?: string[];\n /** Whether chat starts open */\n defaultOpen?: boolean;\n /** Callback when chat opens/closes */\n onToggle?: (open: boolean) => void;\n /**\n * Fired after each tool execution completes (after the API call returns).\n * Use this to trigger client-side data refreshes when the AI mutates data.\n */\n onToolComplete?: (tool: ToolCompleteEvent) => void;\n /**\n * Fired when the assistant finishes a full response (status transitions\n * from \"streaming\" to \"ready\").\n */\n onMessageComplete?: (message: MessageCompleteEvent) => void;\n /**\n * Custom renderer for the tool confirmation dialog.\n *\n * When provided, AI-Me will call this function instead of showing the\n * default confirmation UI. Return any React node — a modal, an inline\n * card, a drawer, etc.\n *\n * If not provided, the built-in `<AIMeConfirm>` dialog is used.\n *\n * @example\n * ```tsx\n * <AIMeChat\n * renderConfirmation={({ tool, params, onConfirm, onCancel }) => (\n * <MyCustomConfirmDialog\n * title={`Run ${tool.name}?`}\n * description={tool.description}\n * params={params}\n * onConfirm={onConfirm}\n * onCancel={onCancel}\n * />\n * )}\n * />\n * ```\n */\n renderConfirmation?: (props: {\n /** Metadata about the tool that is about to be executed */\n tool: {\n /** Tool (function) name */\n name: string;\n /** HTTP method the tool maps to, e.g. \"POST\" */\n httpMethod: string;\n /** API path the tool will call, e.g. \"/api/projects\" */\n path: string;\n /** Human-readable description of what the tool does */\n description: string;\n };\n /** Resolved parameters the tool will be called with */\n params: Record<string, unknown>;\n /** Call to proceed with the tool execution */\n onConfirm: () => void;\n /** Call to abort without executing the tool */\n onCancel: () => void;\n }) => ReactNode;\n}\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeChat({\n position = \"bottom-right\",\n theme,\n welcomeMessage = \"Hi! I can help you navigate and use this app. What would you like to do?\",\n suggestedPrompts,\n defaultOpen = false,\n onToggle,\n onToolComplete,\n onMessageComplete,\n}: AIMeChatProps) {\n const [open, setOpen] = useState(defaultOpen);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // Track tool-result part IDs that have already fired onToolComplete\n const firedToolResults = useRef<Set<string>>(new Set());\n // Track the previous status to detect the streaming → ready transition\n const prevStatus = useRef<string | null>(null);\n const {\n messages,\n input,\n handleInputChange,\n handleSubmit,\n status,\n error,\n setInput,\n } = useAIMe();\n\n // Stable IDs for aria-labelledby / aria-describedby\n const titleId = useId();\n const messagesId = useId();\n\n const isInline = position === \"inline\";\n\n const toggleOpen = useCallback(() => {\n const next = !open;\n setOpen(next);\n onToggle?.(next);\n }, [open, onToggle]);\n\n // Keyboard shortcut: Cmd+. to toggle\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.metaKey || e.ctrlKey) && e.key === \".\") {\n e.preventDefault();\n toggleOpen();\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleOpen]);\n\n // Scroll to bottom on new messages\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n // Fire onToolComplete for each new tool-result part observed in messages.\n // We deduplicate by tracking the tool-call ID so the callback fires exactly\n // once per tool execution, even across re-renders during streaming.\n useEffect(() => {\n if (!onToolComplete) return;\n for (const message of messages) {\n for (const part of message.parts) {\n if (part.type !== \"tool-result\") continue;\n // Each tool-result part has a stable toolCallId\n const id = (part as { toolCallId?: string }).toolCallId;\n const dedupeKey = id ?? `${message.id}:${part.type}`;\n if (firedToolResults.current.has(dedupeKey)) continue;\n firedToolResults.current.add(dedupeKey);\n onToolComplete({\n name: (part as { toolName?: string }).toolName ?? \"\",\n result: (part as { result?: unknown }).result,\n });\n }\n }\n }, [messages, onToolComplete]);\n\n // Fire onMessageComplete when status transitions from streaming → ready.\n // prevStatus tracks the last seen status so we only fire on the transition.\n useEffect(() => {\n const prev = prevStatus.current;\n prevStatus.current = status;\n\n if (!onMessageComplete) return;\n // Only fire on the transition away from an active streaming state\n if (status !== \"ready\") return;\n if (prev !== \"streaming\" && prev !== \"submitted\") return;\n\n // Find the last assistant message\n // Walk backwards to find the most recent assistant message without copying the array\n let lastAssistant: (typeof messages)[number] | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"assistant\") { lastAssistant = messages[i]; break; }\n }\n if (!lastAssistant) return;\n\n const textContent = lastAssistant.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n\n const toolCalls: unknown[] = lastAssistant.parts.filter((p) => p.type === \"tool-call\");\n\n onMessageComplete({\n role: lastAssistant.role,\n content: textContent,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n });\n }, [status, messages, onMessageComplete]);\n\n // Focus panel when opened; return focus to trigger when closed\n useEffect(() => {\n if (open) {\n // Shift focus into the panel so screen readers announce the dialog\n panelRef.current?.focus();\n // Then move focus to the input after a tick so the panel focus is set first\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to the trigger that opened the panel\n triggerRef.current?.focus();\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the panel while open\n useEffect(() => {\n if (!open || isInline) return;\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n toggleOpen();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const panel = panelRef.current;\n if (!panel) return;\n\n const focusable = panel.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, isInline, toggleOpen]);\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n const panelStyle: CSSProperties = isInline\n ? {\n ...themeVars,\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n }\n : {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 380,\n height: \"70vh\",\n maxHeight: 600,\n display: open ? \"flex\" : \"none\",\n flexDirection: \"column\",\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n boxShadow: \"var(--ai-me-shadow)\",\n border: \"1px solid var(--ai-me-border)\",\n overflow: \"hidden\",\n zIndex: 9999,\n };\n\n const triggerStyle: CSSProperties = {\n ...themeVars,\n position: \"fixed\",\n bottom: 24,\n ...(position === \"bottom-right\" ? { right: 24 } : { left: 24 }),\n width: 56,\n height: 56,\n borderRadius: \"50%\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n cursor: \"pointer\",\n display: isInline || open ? \"none\" : \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"var(--ai-me-shadow)\",\n fontSize: 24,\n zIndex: 9999,\n };\n\n const isStreaming = status === \"submitted\" || status === \"streaming\";\n\n return (\n <>\n {/* Floating trigger button */}\n <button\n ref={triggerRef}\n onClick={toggleOpen}\n style={triggerStyle}\n aria-label=\"Open AI chat\"\n aria-expanded={open}\n aria-controls={isInline ? undefined : \"ai-me-chat-panel\"}\n type=\"button\"\n >\n {/* Icon is decorative; label is on the button */}\n <span aria-hidden=\"true\">💬</span>\n </button>\n\n {/* Chat panel */}\n <div\n id=\"ai-me-chat-panel\"\n ref={panelRef}\n style={panelStyle}\n role=\"dialog\"\n aria-modal={isInline ? undefined : \"true\"}\n aria-labelledby={titleId}\n aria-busy={isStreaming}\n // tabIndex={-1} allows programmatic focus on the panel element itself\n tabIndex={-1}\n >\n {/* Header */}\n <div\n style={{\n padding: \"12px 16px\",\n borderBottom: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n }}\n >\n <span id={titleId} style={{ fontWeight: 600, fontSize: 14 }}>\n AI Assistant\n </span>\n {!isInline && (\n <button\n onClick={toggleOpen}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n fontSize: 18,\n color: \"var(--ai-me-text-secondary)\",\n padding: 4,\n borderRadius: 4,\n // Visible focus indicator without outline:none\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Close chat\"\n type=\"button\"\n >\n <span aria-hidden=\"true\">✕</span>\n </button>\n )}\n </div>\n\n {/* Skip link: jump straight to the input */}\n <a\n href=\"#ai-me-chat-input\"\n style={{\n ...srOnly,\n // Reveal on focus so keyboard users can see it\n }}\n onFocus={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, {\n position: \"static\",\n width: \"auto\",\n height: \"auto\",\n padding: \"4px 8px\",\n margin: 0,\n overflow: \"visible\",\n clip: \"auto\",\n whiteSpace: \"normal\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n fontSize: 12,\n borderRadius: 4,\n });\n }}\n onBlur={(e) => {\n Object.assign((e.currentTarget as HTMLAnchorElement).style, srOnly);\n }}\n >\n Skip to message input\n </a>\n\n {/* Messages — live region so screen readers announce new content */}\n <div\n id={messagesId}\n aria-live=\"polite\"\n aria-label=\"Conversation\"\n aria-relevant=\"additions\"\n style={{\n flex: 1,\n overflowY: \"auto\",\n padding: 16,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 12,\n }}\n >\n {messages.length === 0 && (\n <div style={{ color: \"var(--ai-me-text-secondary)\", fontSize: 14 }}>\n <p>{welcomeMessage}</p>\n {suggestedPrompts && suggestedPrompts.length > 0 && (\n <div\n style={{\n marginTop: 12,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 8,\n }}\n >\n <p style={{ margin: \"0 0 4px\", fontSize: 12, fontWeight: 500 }}>\n Suggested questions:\n </p>\n {suggestedPrompts.map((prompt) => (\n <button\n key={prompt}\n type=\"button\"\n onClick={() => {\n setInput(prompt);\n inputRef.current?.focus();\n }}\n style={{\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n background: \"var(--ai-me-bg)\",\n cursor: \"pointer\",\n textAlign: \"left\",\n fontSize: 13,\n color: \"var(--ai-me-text)\",\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {prompt}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n\n {messages.map((m) => {\n // Skip messages that have no renderable content (e.g. reasoning-only messages\n // from providers like Groq that emit reasoning tokens).\n const hasTextContent = m.parts.some((p) => p.type === \"text\");\n if (!hasTextContent && m.role === \"assistant\") return null;\n\n return (\n <div\n key={m.id}\n style={{\n alignSelf: m.role === \"user\" ? \"flex-end\" : \"flex-start\",\n maxWidth: \"85%\",\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor:\n m.role === \"user\"\n ? \"var(--ai-me-primary)\"\n : \"var(--ai-me-bg-secondary)\",\n color: m.role === \"user\" ? \"#fff\" : \"var(--ai-me-text)\",\n fontSize: 14,\n lineHeight: 1.5,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n }}\n >\n {/* Screen reader role prefix */}\n <span style={srOnly}>\n {m.role === \"user\" ? \"You: \" : \"Assistant: \"}\n </span>\n {m.parts.map((p, i) =>\n p.type === \"text\" ? (\n <span key={i}>\n {m.role === \"assistant\"\n ? renderMarkdown(p.text)\n : p.text}\n </span>\n ) : null,\n )}\n </div>\n );\n })}\n\n {/* \"Thinking\" indicator — announced by the live region above */}\n {status === \"submitted\" && (\n <div\n aria-label=\"Assistant is thinking\"\n style={{\n alignSelf: \"flex-start\",\n color: \"var(--ai-me-text-secondary)\",\n fontSize: 13,\n }}\n >\n <span aria-hidden=\"true\">Thinking…</span>\n </div>\n )}\n\n {/* Error — role=\"alert\" ensures immediate announcement */}\n {error && (\n <div\n role=\"alert\"\n style={{\n padding: \"8px 12px\",\n borderRadius: 8,\n backgroundColor: \"#fef2f2\",\n // #dc2626 on #fef2f2 ≈ 5.1:1 — passes AA for normal text\n color: \"#dc2626\",\n fontSize: 13,\n border: \"1px solid #fca5a5\",\n }}\n >\n Something went wrong. Please try again.\n </div>\n )}\n\n <div ref={messagesEndRef} aria-hidden=\"true\" />\n </div>\n\n {/* Input */}\n <form\n onSubmit={handleSubmit}\n style={{\n padding: \"12px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n display: \"flex\",\n gap: 8,\n }}\n >\n {/* Visible label for the input (positioned absolutely so only visible on focus for compact layout) */}\n <label\n htmlFor=\"ai-me-chat-input\"\n style={srOnly}\n >\n Message to AI Assistant\n </label>\n <input\n id=\"ai-me-chat-input\"\n ref={inputRef}\n value={input}\n onChange={handleInputChange}\n placeholder=\"Ask anything…\"\n disabled={status !== \"ready\"}\n aria-disabled={status !== \"ready\"}\n style={{\n flex: 1,\n padding: \"8px 12px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n // Do NOT use outline:none — use outline with transparent color + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n />\n <button\n type=\"submit\"\n disabled={status !== \"ready\" || !input.trim()}\n aria-disabled={status !== \"ready\" || !input.trim()}\n style={{\n padding: \"8px 16px\",\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 8,\n cursor: status === \"ready\" && input.trim() ? \"pointer\" : \"not-allowed\",\n fontSize: 14,\n fontFamily: \"var(--ai-me-font)\",\n opacity: status === \"ready\" && input.trim() ? 1 : 0.5,\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n (e.currentTarget as HTMLButtonElement).style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLButtonElement).style.outline =\n \"2px solid transparent\";\n }}\n aria-label=\"Send message\"\n >\n Send\n </button>\n </form>\n </div>\n </>\n );\n}\n","import { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { useState, useCallback, useEffect, useRef } from \"react\";\nimport { useAIMeContext } from \"./context.js\";\n\nconst STORAGE_KEY = \"ai-me-messages\";\n\n/**\n * Hook wrapping AI SDK's useChat with AI-Me configuration.\n * Provides chat state, message handling, confirmation support,\n * and session persistence (survives page navigation within the same tab).\n */\nexport function useAIMe() {\n const { endpoint, headers } = useAIMeContext();\n const [input, setInput] = useState(\"\");\n const initialized = useRef(false);\n\n const chat = useChat({\n transport: new DefaultChatTransport({\n api: endpoint,\n headers,\n }),\n });\n\n // Restore messages from sessionStorage on mount\n useEffect(() => {\n if (initialized.current) return;\n initialized.current = true;\n\n try {\n const stored = sessionStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (Array.isArray(parsed) && parsed.length > 0) {\n chat.setMessages(parsed);\n }\n }\n } catch {\n // ignore — sessionStorage may be unavailable or corrupted\n }\n }, []);\n\n // Persist messages to sessionStorage on change\n useEffect(() => {\n if (!initialized.current) return;\n try {\n if (chat.messages.length > 0) {\n sessionStorage.setItem(STORAGE_KEY, JSON.stringify(chat.messages));\n } else {\n sessionStorage.removeItem(STORAGE_KEY);\n }\n } catch {\n // ignore\n }\n }, [chat.messages]);\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setInput(e.target.value);\n },\n [],\n );\n\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n if (!input.trim()) return;\n chat.sendMessage({ text: input });\n setInput(\"\");\n },\n [input, chat],\n );\n\n const clearMessages = useCallback(() => {\n chat.setMessages([]);\n try {\n sessionStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n }, [chat]);\n\n return {\n /** Conversation messages */\n messages: chat.messages,\n /** Current input value */\n input,\n /** Set input value */\n setInput,\n /** Handle input change */\n handleInputChange,\n /** Submit the current message */\n handleSubmit,\n /** Send a message directly */\n sendMessage: chat.sendMessage,\n /** Chat status: \"ready\" | \"submitted\" | \"streaming\" */\n status: chat.status,\n /** Error if any */\n error: chat.error,\n /** Stop streaming */\n stop: chat.stop,\n /** Set messages */\n setMessages: chat.setMessages,\n /** Clear all messages and session storage */\n clearMessages,\n };\n}\n","/**\n * CSS custom properties for AI-Me theming.\n * All prefixed with --ai-me- to avoid conflicts with host app styles.\n */\nexport const defaultThemeVars = {\n \"--ai-me-primary\": \"#6366f1\",\n \"--ai-me-primary-hover\": \"#4f46e5\",\n \"--ai-me-bg\": \"#ffffff\",\n \"--ai-me-bg-secondary\": \"#f9fafb\",\n \"--ai-me-text\": \"#111827\",\n \"--ai-me-text-secondary\": \"#6b7280\",\n \"--ai-me-border\": \"#e5e7eb\",\n \"--ai-me-radius\": \"12px\",\n \"--ai-me-font\": \"system-ui, -apple-system, sans-serif\",\n \"--ai-me-shadow\": \"0 4px 24px rgba(0, 0, 0, 0.12)\",\n} as const;\n\nexport interface AIMeTheme {\n primaryColor?: string;\n backgroundColor?: string;\n textColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n}\n\nexport function themeToVars(theme?: AIMeTheme): Record<string, string> {\n if (!theme) return {};\n const vars: Record<string, string> = {};\n if (theme.primaryColor) vars[\"--ai-me-primary\"] = theme.primaryColor;\n if (theme.backgroundColor) vars[\"--ai-me-bg\"] = theme.backgroundColor;\n if (theme.textColor) vars[\"--ai-me-text\"] = theme.textColor;\n if (theme.borderRadius) vars[\"--ai-me-radius\"] = theme.borderRadius;\n if (theme.fontFamily) vars[\"--ai-me-font\"] = theme.fontFamily;\n return vars;\n}\n","import type { CSSProperties, ReactNode } from \"react\";\n\n/**\n * Lightweight inline markdown renderer for chat messages.\n * Supports: **bold**, *italic*, `code`, ```code blocks```, [links](url), - lists\n * No external dependencies — renders to React elements with inline styles.\n */\nexport function renderMarkdown(text: string): ReactNode[] {\n const lines = text.split(\"\\n\");\n const result: ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Fenced code block\n if (line.trimStart().startsWith(\"```\")) {\n const lang = line.trimStart().slice(3).trim();\n const codeLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].trimStart().startsWith(\"```\")) {\n codeLines.push(lines[i]);\n i++;\n }\n i++; // skip closing ```\n result.push(\n <pre\n key={`code-${result.length}`}\n style={codeBlockStyle}\n data-lang={lang || undefined}\n >\n <code>{codeLines.join(\"\\n\")}</code>\n </pre>,\n );\n continue;\n }\n\n // Unordered list item\n if (/^[\\s]*[-*]\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*[-*]\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*[-*]\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ul\n key={`ul-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20, listStyleType: \"disc\" }}\n >\n {listItems}\n </ul>,\n );\n continue;\n }\n\n // Ordered list item\n if (/^[\\s]*\\d+\\.\\s/.test(line)) {\n const listItems: ReactNode[] = [];\n while (i < lines.length && /^[\\s]*\\d+\\.\\s/.test(lines[i])) {\n listItems.push(\n <li key={listItems.length} style={{ marginBottom: 2 }}>\n {renderInline(lines[i].replace(/^[\\s]*\\d+\\.\\s/, \"\"))}\n </li>,\n );\n i++;\n }\n result.push(\n <ol\n key={`ol-${result.length}`}\n style={{ margin: \"4px 0\", paddingLeft: 20 }}\n >\n {listItems}\n </ol>,\n );\n continue;\n }\n\n // Heading (clamp to h3+ in chat context)\n const headingMatch = /^(#{1,6})\\s+(.+)$/.exec(line);\n if (headingMatch) {\n const level = Math.max(headingMatch[1].length, 3);\n const fontSize =\n ({ 3: 15, 4: 14, 5: 13, 6: 13 } as Record<number, number>)[level] ??\n 14;\n result.push(\n <p\n key={`h-${result.length}`}\n style={{ fontWeight: 600, fontSize, margin: \"8px 0 4px\" }}\n >\n {renderInline(headingMatch[2])}\n </p>,\n );\n i++;\n continue;\n }\n\n // Empty line\n if (line.trim() === \"\") {\n i++;\n continue;\n }\n\n // Regular text\n result.push(\n <span\n key={`p-${result.length}`}\n style={{ display: \"block\", marginBottom: 2 }}\n >\n {renderInline(line)}\n </span>,\n );\n i++;\n }\n\n return result;\n}\n\n/** Parse inline markdown: bold, italic, code, links */\nfunction renderInline(text: string): ReactNode[] {\n const result: ReactNode[] = [];\n const pattern = /(`[^`]+`|\\*\\*[^*]+\\*\\*|\\*[^*]+\\*|\\[[^\\]]+\\]\\([^)]+\\))/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n if (match.index > lastIndex) {\n result.push(text.slice(lastIndex, match.index));\n }\n\n const token = match[0];\n\n if (token.startsWith(\"`\")) {\n result.push(\n <code key={result.length} style={inlineCodeStyle}>\n {token.slice(1, -1)}\n </code>,\n );\n } else if (token.startsWith(\"**\")) {\n result.push(\n <strong key={result.length}>{token.slice(2, -2)}</strong>,\n );\n } else if (token.startsWith(\"*\")) {\n result.push(<em key={result.length}>{token.slice(1, -1)}</em>);\n } else if (token.startsWith(\"[\")) {\n const linkMatch = /\\[([^\\]]+)\\]\\(([^)]+)\\)/.exec(token);\n if (linkMatch) {\n result.push(\n <a\n key={result.length}\n href={linkMatch[2]}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={linkStyle}\n >\n {linkMatch[1]}\n </a>,\n );\n }\n }\n\n lastIndex = match.index + token.length;\n }\n\n if (lastIndex < text.length) {\n result.push(text.slice(lastIndex));\n }\n\n return result;\n}\n\nconst codeBlockStyle: CSSProperties = {\n margin: \"6px 0\",\n padding: \"10px 12px\",\n borderRadius: 6,\n backgroundColor: \"rgba(0,0,0,0.15)\",\n fontSize: 12,\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n overflow: \"auto\",\n whiteSpace: \"pre\",\n lineHeight: 1.5,\n};\n\nconst inlineCodeStyle: CSSProperties = {\n padding: \"1px 5px\",\n borderRadius: 3,\n backgroundColor: \"rgba(0,0,0,0.12)\",\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: \"0.9em\",\n};\n\nconst linkStyle: CSSProperties = {\n color: \"var(--ai-me-primary, #6366f1)\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n};\n","import { useState, useEffect, useRef, useCallback, useId } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars, themeToVars } from \"./styles.js\";\nimport type { AIMeTheme } from \"./styles.js\";\nimport { useAIMe } from \"./use-ai-me.js\";\n\nexport interface AIMeCommandPaletteProps {\n /** List of available commands/actions */\n commands?: CommandItem[];\n /** Theme overrides */\n theme?: AIMeTheme;\n /** Custom keyboard shortcut (default: Cmd+K / Ctrl+K) */\n shortcut?: { key: string; meta?: boolean; ctrl?: boolean };\n /** Callback when palette opens/closes */\n onToggle?: (open: boolean) => void;\n}\n\nexport interface CommandItem {\n /** Unique command ID */\n id: string;\n /** Display label */\n label: string;\n /** Description shown below label */\n description?: string;\n /** Category for grouping */\n category?: string;\n /** Icon (emoji or text) */\n icon?: string;\n /** Action to run — either a callback or a prompt to send to AI */\n action: (() => void) | string;\n}\n\nconst defaultCommands: CommandItem[] = [\n {\n id: \"help\",\n label: \"Ask AI for help\",\n description: \"Get assistance with any task\",\n category: \"AI\",\n icon: \"💡\",\n action: \"What can you help me with?\",\n },\n {\n id: \"list-actions\",\n label: \"List available actions\",\n description: \"Show all API actions the AI can perform\",\n category: \"AI\",\n icon: \"📋\",\n action: \"What actions can you perform? List them all.\",\n },\n {\n id: \"recent-activity\",\n label: \"Show recent activity\",\n description: \"Summarize recent actions and changes\",\n category: \"AI\",\n icon: \"🕐\",\n action: \"What has happened recently? Summarize recent activity.\",\n },\n];\n\n/** Visually hidden but accessible to screen readers */\nconst srOnly: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0,0,0,0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n};\n\nexport function AIMeCommandPalette({\n commands = defaultCommands,\n theme,\n shortcut = { key: \"k\", meta: true },\n onToggle,\n}: AIMeCommandPaletteProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n // Remember what had focus before the palette opened so we can restore it\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const { sendMessage } = useAIMe();\n\n // Stable IDs\n const titleId = useId();\n const inputId = useId();\n\n const toggle = useCallback(\n (next: boolean) => {\n setOpen(next);\n setQuery(\"\");\n setSelectedIndex(0);\n onToggle?.(next);\n },\n [onToggle],\n );\n\n // Keyboard shortcut to open\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n const metaMatch = shortcut.meta ? e.metaKey : true;\n const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;\n if ((metaMatch || ctrlMatch) && e.key === shortcut.key) {\n e.preventDefault();\n // Capture current focus before opening\n if (!open) {\n previousFocusRef.current = document.activeElement as HTMLElement;\n }\n toggle(!open);\n }\n }\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, shortcut, toggle]);\n\n // Focus the search input when opened; restore focus when closed\n useEffect(() => {\n if (open) {\n setTimeout(() => inputRef.current?.focus(), 0);\n } else {\n // Return focus to whatever had it before the palette opened\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n previousFocusRef.current = null;\n }\n }\n }, [open]);\n\n // Focus trap: keep Tab/Shift+Tab inside the palette while open\n useEffect(() => {\n if (!open) return;\n\n function handleFocusTrap(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n window.addEventListener(\"keydown\", handleFocusTrap);\n return () => window.removeEventListener(\"keydown\", handleFocusTrap);\n }, [open]);\n\n // Filter commands by query\n const filtered = query.trim()\n ? commands.filter(\n (cmd) =>\n cmd.label.toLowerCase().includes(query.toLowerCase()) ||\n cmd.description?.toLowerCase().includes(query.toLowerCase()) ||\n cmd.category?.toLowerCase().includes(query.toLowerCase()),\n )\n : commands;\n\n // Clamp selected index\n useEffect(() => {\n if (selectedIndex >= filtered.length) {\n setSelectedIndex(Math.max(0, filtered.length - 1));\n }\n }, [filtered.length, selectedIndex]);\n\n // Scroll selected item into view\n useEffect(() => {\n const list = listRef.current;\n if (!list) return;\n const selected = list.children[selectedIndex] as HTMLElement | undefined;\n selected?.scrollIntoView({ block: \"nearest\" });\n }, [selectedIndex]);\n\n function executeCommand(cmd: CommandItem) {\n toggle(false);\n if (typeof cmd.action === \"string\") {\n sendMessage({ text: cmd.action });\n } else {\n cmd.action();\n }\n }\n\n function handleKeyDown(e: React.KeyboardEvent) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.min(prev + 1, filtered.length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setSelectedIndex((prev) => Math.max(prev - 1, 0));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (filtered[selectedIndex]) {\n executeCommand(filtered[selectedIndex]);\n } else if (query.trim()) {\n // Send raw query as AI prompt\n toggle(false);\n sendMessage({ text: query });\n }\n } else if (e.key === \"Escape\") {\n toggle(false);\n }\n }\n\n if (!open) return null;\n\n const themeVars: CSSProperties = {\n ...defaultThemeVars,\n ...themeToVars(theme),\n } as CSSProperties;\n\n // Group by category\n const grouped = new Map<string, CommandItem[]>();\n for (const cmd of filtered) {\n const cat = cmd.category ?? \"Actions\";\n if (!grouped.has(cat)) grouped.set(cat, []);\n grouped.get(cat)!.push(cmd);\n }\n\n let flatIndex = 0;\n\n return (\n <>\n {/* Backdrop — keyboard-dismissable via Escape (handled in handleKeyDown) */}\n <div\n onClick={() => toggle(false)}\n style={{\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0,0,0,0.5)\",\n zIndex: 99998,\n }}\n // aria-hidden so screen readers go straight to the dialog\n aria-hidden=\"true\"\n />\n\n {/* Palette dialog */}\n <div\n ref={dialogRef}\n style={{\n ...themeVars,\n position: \"fixed\",\n top: \"20%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n width: \"min(520px, 90vw)\",\n maxHeight: \"60vh\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n border: \"1px solid var(--ai-me-border)\",\n boxShadow: \"0 24px 48px rgba(0,0,0,0.3)\",\n overflow: \"hidden\",\n zIndex: 99999,\n fontFamily: \"var(--ai-me-font)\",\n color: \"var(--ai-me-text)\",\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n // tabIndex={-1} so the dialog element itself can receive programmatic focus\n tabIndex={-1}\n >\n {/* Visually hidden dialog title for screen readers */}\n <h2 id={titleId} style={srOnly}>\n Command Palette\n </h2>\n\n {/* Search input */}\n <div style={{ padding: \"12px 16px\", borderBottom: \"1px solid var(--ai-me-border)\" }}>\n <label htmlFor={inputId} style={srOnly}>\n Search commands or ask AI\n </label>\n <input\n id={inputId}\n ref={inputRef}\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setSelectedIndex(0);\n }}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a command or ask AI...\"\n style={{\n width: \"100%\",\n padding: \"8px 0\",\n border: \"none\",\n // Do NOT suppress the outline entirely — use transparent + focus handler\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n fontSize: 15,\n fontFamily: \"var(--ai-me-font)\",\n backgroundColor: \"transparent\",\n color: \"var(--ai-me-text)\",\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLInputElement).style.outline =\n \"2px solid transparent\";\n }}\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"ai-me-cmd-listbox\"\n aria-activedescendant={\n filtered[selectedIndex]\n ? `cmd-${filtered[selectedIndex].id}`\n : undefined\n }\n />\n </div>\n\n {/* Results listbox */}\n <div\n id=\"ai-me-cmd-listbox\"\n ref={listRef}\n style={{ overflowY: \"auto\", padding: \"8px 0\" }}\n role=\"listbox\"\n aria-label=\"Commands\"\n >\n {filtered.length === 0 && query.trim() && (\n <div\n role=\"option\"\n aria-selected=\"false\"\n style={{\n padding: \"16px\",\n textAlign: \"center\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n Press Enter to ask AI: “{query}”\n </div>\n )}\n\n {Array.from(grouped.entries()).map(([category, items]) => (\n // role=\"group\" with aria-label for the category heading\n <div key={category} role=\"group\" aria-label={category}>\n {/* Category heading — aria-hidden because role=\"group\" aria-label carries the name */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"6px 16px 4px\",\n fontSize: 11,\n fontWeight: 500,\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {category}\n </div>\n {items.map((cmd) => {\n const idx = flatIndex++;\n const isSelected = idx === selectedIndex;\n return (\n <div\n key={cmd.id}\n id={`cmd-${cmd.id}`}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => executeCommand(cmd)}\n onMouseEnter={() => setSelectedIndex(idx)}\n // Allow keyboard activation of each option when it has focus\n tabIndex={isSelected ? 0 : -1}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n executeCommand(cmd);\n }\n }}\n style={{\n padding: \"8px 16px\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: isSelected\n ? \"var(--ai-me-bg-secondary)\"\n : \"transparent\",\n outline: \"2px solid transparent\",\n outlineOffset: -2,\n }}\n onFocus={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid var(--ai-me-primary)\";\n }}\n onBlur={(e) => {\n (e.currentTarget as HTMLDivElement).style.outline =\n \"2px solid transparent\";\n }}\n >\n {cmd.icon && (\n // Icon is decorative — label comes from cmd.label\n <span aria-hidden=\"true\" style={{ fontSize: 16, flexShrink: 0 }}>\n {cmd.icon}\n </span>\n )}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ fontSize: 14, fontWeight: 500 }}>\n {cmd.label}\n </div>\n {cmd.description && (\n <div\n style={{\n fontSize: 12,\n color: \"var(--ai-me-text-secondary)\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {cmd.description}\n </div>\n )}\n </div>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n\n {/* Footer keyboard hints — aria-hidden because these are redundant for screen readers\n (keyboard shortcuts are announced via aria-keyshortcuts on the input) */}\n <div\n aria-hidden=\"true\"\n style={{\n padding: \"8px 16px\",\n borderTop: \"1px solid var(--ai-me-border)\",\n fontSize: 11,\n color: \"var(--ai-me-text-secondary)\",\n display: \"flex\",\n gap: 16,\n }}\n >\n <span>↑↓ Navigate</span>\n <span>↵ Select</span>\n <span>Esc Close</span>\n </div>\n </div>\n </>\n );\n}\n","import { useRef, useEffect, useId, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { defaultThemeVars } from \"./styles.js\";\n\nexport interface AIMeConfirmProps {\n /** Tool/action name */\n action: string;\n /** Description of what will happen */\n description: string;\n /** Parameters being sent */\n parameters?: Record<string, unknown>;\n /** Callback when user confirms */\n onConfirm: () => void;\n /** Callback when user rejects */\n onReject: () => void;\n}\n\nexport function AIMeConfirm({\n action,\n description,\n parameters,\n onConfirm,\n onReject,\n}: AIMeConfirmProps) {\n const dialogRef = useRef<HTMLDivElement>(null);\n const cancelButtonRef = useRef<HTMLButtonElement>(null);\n\n // Stable IDs for ARIA associations\n const titleId = useId();\n const descriptionId = useId();\n\n // Close on Escape and focus-trap within the dialog\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onReject();\n return;\n }\n\n if (e.key !== \"Tab\") return;\n const dialog = dialogRef.current;\n if (!dialog) return;\n\n const focusable = dialog.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onReject],\n );\n\n // Auto-focus the Cancel button when the dialog mounts (safe default for\n // destructive confirmations — avoids accidental confirmation on Enter).\n // Also wire up Escape / focus-trap and restore focus on unmount.\n useEffect(() => {\n const previousFocus = document.activeElement as HTMLElement | null;\n\n cancelButtonRef.current?.focus();\n window.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n // Restore focus to whatever triggered the dialog\n previousFocus?.focus();\n };\n }, [handleKeyDown]);\n\n const overlayStyle: CSSProperties = {\n ...defaultThemeVars,\n position: \"fixed\",\n inset: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.4)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n zIndex: 10000,\n fontFamily: \"var(--ai-me-font)\",\n } as CSSProperties;\n\n const dialogStyle: CSSProperties = {\n backgroundColor: \"var(--ai-me-bg)\",\n borderRadius: \"var(--ai-me-radius)\",\n padding: 24,\n maxWidth: 420,\n width: \"90%\",\n boxShadow: \"var(--ai-me-shadow)\",\n color: \"var(--ai-me-text)\",\n };\n\n const focusStyle: CSSProperties = {\n outline: \"2px solid transparent\",\n outlineOffset: 2,\n };\n\n function applyFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid var(--ai-me-primary)\";\n el.style.outlineOffset = \"2px\";\n }\n\n function removeFocusRing(el: HTMLElement) {\n el.style.outline = \"2px solid transparent\";\n el.style.outlineOffset = \"2px\";\n }\n\n return (\n // Overlay is presentational — role and aria go on the inner dialog\n <div\n style={overlayStyle}\n // Clicking outside the dialog rejects (same as pressing Escape)\n onClick={(e) => {\n if (e.target === e.currentTarget) onReject();\n }}\n aria-hidden=\"false\"\n >\n <div\n ref={dialogRef}\n style={dialogStyle}\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n // tabIndex={-1} allows programmatic focus on the dialog element itself\n tabIndex={-1}\n // Prevent clicks inside the dialog from bubbling to the overlay\n onClick={(e) => e.stopPropagation()}\n >\n <h3 id={titleId} style={{ margin: \"0 0 8px\", fontSize: 16 }}>\n Confirm Action\n </h3>\n <p style={{ margin: \"0 0 4px\", fontSize: 14, fontWeight: 600 }}>\n {action}\n </p>\n <p\n id={descriptionId}\n style={{\n margin: \"0 0 16px\",\n fontSize: 13,\n color: \"var(--ai-me-text-secondary)\",\n }}\n >\n {description}\n </p>\n\n {parameters && Object.keys(parameters).length > 0 && (\n <pre\n style={{\n margin: \"0 0 16px\",\n padding: 12,\n backgroundColor: \"var(--ai-me-bg-secondary)\",\n borderRadius: 8,\n fontSize: 12,\n overflow: \"auto\",\n maxHeight: 200,\n border: \"1px solid var(--ai-me-border)\",\n }}\n >\n {JSON.stringify(parameters, null, 2)}\n </pre>\n )}\n\n <div style={{ display: \"flex\", gap: 8, justifyContent: \"flex-end\" }}>\n {/* Cancel is focused first — avoids accidental confirmation */}\n <button\n ref={cancelButtonRef}\n type=\"button\"\n onClick={onReject}\n style={{\n padding: \"8px 16px\",\n border: \"1px solid var(--ai-me-border)\",\n borderRadius: 8,\n backgroundColor: \"var(--ai-me-bg)\",\n color: \"var(--ai-me-text)\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n style={{\n padding: \"8px 16px\",\n border: \"none\",\n borderRadius: 8,\n // #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)\n backgroundColor: \"var(--ai-me-primary)\",\n color: \"#fff\",\n cursor: \"pointer\",\n fontSize: 14,\n ...focusStyle,\n }}\n onFocus={(e) => applyFocusRing(e.currentTarget)}\n onBlur={(e) => removeFocusRing(e.currentTarget)}\n >\n Confirm\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useState","useRef","useEffect","useCallback","jsx","jsx","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","useId","Fragment","jsx","jsxs","srOnly","useState","useRef","useId","useCallback","useEffect","handleKeyDown","useRef","useEffect","useId","useCallback","jsx","jsxs","useRef","useId","useCallback","useEffect"]}
|