@ai-me-chat/react 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +399 -299
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -4
- package/dist/index.d.ts +23 -4
- package/dist/index.js +395 -296
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
AIMeCommandPalette: () => AIMeCommandPalette,
|
|
26
26
|
AIMeConfirm: () => AIMeConfirm,
|
|
27
27
|
AIMeProvider: () => AIMeProvider,
|
|
28
|
+
cleanAssistantText: () => cleanAssistantText,
|
|
28
29
|
renderMarkdown: () => renderMarkdown,
|
|
29
30
|
useAIMe: () => useAIMe,
|
|
30
31
|
useAIMeContext: () => useAIMeContext
|
|
@@ -44,20 +45,35 @@ function useAIMeContext() {
|
|
|
44
45
|
|
|
45
46
|
// src/provider.tsx
|
|
46
47
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
47
|
-
function AIMeProvider({ endpoint, headers, onAction, children }) {
|
|
48
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AIMeContext, { value: { endpoint, headers, onAction }, children });
|
|
48
|
+
function AIMeProvider({ endpoint, headers, onAction, stuckTimeout, children }) {
|
|
49
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AIMeContext, { value: { endpoint, headers, onAction, stuckTimeout }, children });
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
// src/chat.tsx
|
|
52
|
-
var
|
|
53
|
+
var import_react5 = require("react");
|
|
53
54
|
|
|
54
55
|
// src/use-ai-me.ts
|
|
55
56
|
var import_react2 = require("@ai-sdk/react");
|
|
56
57
|
var import_ai = require("ai");
|
|
57
58
|
var import_react3 = require("react");
|
|
58
59
|
var STORAGE_KEY = "ai-me-messages";
|
|
60
|
+
function cleanAssistantText(text) {
|
|
61
|
+
return text.replace(/<tools>[\s\S]*?<\/tools>/g, "").trim();
|
|
62
|
+
}
|
|
63
|
+
function trimIncompleteToolCalls(messages) {
|
|
64
|
+
if (messages.length === 0) return messages;
|
|
65
|
+
const last = messages[messages.length - 1];
|
|
66
|
+
if (last.role !== "assistant") return messages;
|
|
67
|
+
const hasToolCall = last.parts.some((p) => p.type === "tool-call");
|
|
68
|
+
const hasToolResult = last.parts.some((p) => p.type === "tool-result");
|
|
69
|
+
if (hasToolCall && !hasToolResult) {
|
|
70
|
+
return messages.slice(0, -1);
|
|
71
|
+
}
|
|
72
|
+
return messages;
|
|
73
|
+
}
|
|
59
74
|
function useAIMe() {
|
|
60
|
-
const { endpoint, headers } = useAIMeContext();
|
|
75
|
+
const { endpoint, headers, stuckTimeout: configuredTimeout } = useAIMeContext();
|
|
76
|
+
const stuckTimeout = configuredTimeout ?? 3e4;
|
|
61
77
|
const [input, setInput] = (0, import_react3.useState)("");
|
|
62
78
|
const initialized = (0, import_react3.useRef)(false);
|
|
63
79
|
const chat = (0, import_react2.useChat)({
|
|
@@ -66,6 +82,24 @@ function useAIMe() {
|
|
|
66
82
|
headers
|
|
67
83
|
})
|
|
68
84
|
});
|
|
85
|
+
const messages = (0, import_react3.useMemo)(() => {
|
|
86
|
+
return chat.messages.map((m) => {
|
|
87
|
+
if (m.role !== "assistant") return m;
|
|
88
|
+
let changed = false;
|
|
89
|
+
const cleanedParts = m.parts.map((p) => {
|
|
90
|
+
if (p.type !== "text") return p;
|
|
91
|
+
const cleaned = cleanAssistantText(p.text);
|
|
92
|
+
if (cleaned === p.text) return p;
|
|
93
|
+
changed = true;
|
|
94
|
+
return { ...p, text: cleaned };
|
|
95
|
+
});
|
|
96
|
+
if (!changed) return m;
|
|
97
|
+
const nonEmptyParts = cleanedParts.filter(
|
|
98
|
+
(p) => p.type !== "text" || p.text.length > 0
|
|
99
|
+
);
|
|
100
|
+
return { ...m, parts: nonEmptyParts };
|
|
101
|
+
});
|
|
102
|
+
}, [chat.messages]);
|
|
69
103
|
(0, import_react3.useEffect)(() => {
|
|
70
104
|
if (initialized.current) return;
|
|
71
105
|
initialized.current = true;
|
|
@@ -74,7 +108,10 @@ function useAIMe() {
|
|
|
74
108
|
if (stored) {
|
|
75
109
|
const parsed = JSON.parse(stored);
|
|
76
110
|
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
77
|
-
|
|
111
|
+
const cleaned = trimIncompleteToolCalls(parsed);
|
|
112
|
+
if (cleaned.length > 0) {
|
|
113
|
+
chat.setMessages(cleaned);
|
|
114
|
+
}
|
|
78
115
|
}
|
|
79
116
|
}
|
|
80
117
|
} catch {
|
|
@@ -91,6 +128,14 @@ function useAIMe() {
|
|
|
91
128
|
} catch {
|
|
92
129
|
}
|
|
93
130
|
}, [chat.messages]);
|
|
131
|
+
(0, import_react3.useEffect)(() => {
|
|
132
|
+
if (stuckTimeout <= 0) return;
|
|
133
|
+
if (chat.status !== "submitted") return;
|
|
134
|
+
const timer = setTimeout(() => {
|
|
135
|
+
chat.stop();
|
|
136
|
+
}, stuckTimeout);
|
|
137
|
+
return () => clearTimeout(timer);
|
|
138
|
+
}, [chat.status, stuckTimeout, chat.stop]);
|
|
94
139
|
const handleInputChange = (0, import_react3.useCallback)(
|
|
95
140
|
(e) => {
|
|
96
141
|
setInput(e.target.value);
|
|
@@ -115,7 +160,7 @@ function useAIMe() {
|
|
|
115
160
|
}, [chat]);
|
|
116
161
|
return {
|
|
117
162
|
/** Conversation messages */
|
|
118
|
-
messages
|
|
163
|
+
messages,
|
|
119
164
|
/** Current input value */
|
|
120
165
|
input,
|
|
121
166
|
/** Set input value */
|
|
@@ -135,7 +180,9 @@ function useAIMe() {
|
|
|
135
180
|
/** Set messages */
|
|
136
181
|
setMessages: chat.setMessages,
|
|
137
182
|
/** Clear all messages and session storage */
|
|
138
|
-
clearMessages
|
|
183
|
+
clearMessages,
|
|
184
|
+
/** Approve or reject a pending tool call (for confirmation flow) */
|
|
185
|
+
addToolApprovalResponse: chat.addToolApprovalResponse
|
|
139
186
|
};
|
|
140
187
|
}
|
|
141
188
|
|
|
@@ -337,8 +384,197 @@ var linkStyle = {
|
|
|
337
384
|
textUnderlineOffset: "2px"
|
|
338
385
|
};
|
|
339
386
|
|
|
340
|
-
// src/
|
|
387
|
+
// src/confirm.tsx
|
|
388
|
+
var import_react4 = require("react");
|
|
341
389
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
390
|
+
function AIMeConfirm({
|
|
391
|
+
action,
|
|
392
|
+
description,
|
|
393
|
+
parameters,
|
|
394
|
+
onConfirm,
|
|
395
|
+
onReject
|
|
396
|
+
}) {
|
|
397
|
+
const dialogRef = (0, import_react4.useRef)(null);
|
|
398
|
+
const cancelButtonRef = (0, import_react4.useRef)(null);
|
|
399
|
+
const titleId = (0, import_react4.useId)();
|
|
400
|
+
const descriptionId = (0, import_react4.useId)();
|
|
401
|
+
const handleKeyDown = (0, import_react4.useCallback)(
|
|
402
|
+
(e) => {
|
|
403
|
+
if (e.key === "Escape") {
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
onReject();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (e.key !== "Tab") return;
|
|
409
|
+
const dialog = dialogRef.current;
|
|
410
|
+
if (!dialog) return;
|
|
411
|
+
const focusable = dialog.querySelectorAll(
|
|
412
|
+
'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
413
|
+
);
|
|
414
|
+
if (focusable.length === 0) return;
|
|
415
|
+
const first = focusable[0];
|
|
416
|
+
const last = focusable[focusable.length - 1];
|
|
417
|
+
if (e.shiftKey) {
|
|
418
|
+
if (document.activeElement === first) {
|
|
419
|
+
e.preventDefault();
|
|
420
|
+
last.focus();
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
if (document.activeElement === last) {
|
|
424
|
+
e.preventDefault();
|
|
425
|
+
first.focus();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
[onReject]
|
|
430
|
+
);
|
|
431
|
+
(0, import_react4.useEffect)(() => {
|
|
432
|
+
const previousFocus = document.activeElement;
|
|
433
|
+
cancelButtonRef.current?.focus();
|
|
434
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
435
|
+
return () => {
|
|
436
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
437
|
+
previousFocus?.focus();
|
|
438
|
+
};
|
|
439
|
+
}, [handleKeyDown]);
|
|
440
|
+
const overlayStyle = {
|
|
441
|
+
...defaultThemeVars,
|
|
442
|
+
position: "fixed",
|
|
443
|
+
inset: 0,
|
|
444
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
445
|
+
display: "flex",
|
|
446
|
+
alignItems: "center",
|
|
447
|
+
justifyContent: "center",
|
|
448
|
+
zIndex: 1e4,
|
|
449
|
+
fontFamily: "var(--ai-me-font)"
|
|
450
|
+
};
|
|
451
|
+
const dialogStyle = {
|
|
452
|
+
backgroundColor: "var(--ai-me-bg)",
|
|
453
|
+
borderRadius: "var(--ai-me-radius)",
|
|
454
|
+
padding: 24,
|
|
455
|
+
maxWidth: 420,
|
|
456
|
+
width: "90%",
|
|
457
|
+
boxShadow: "var(--ai-me-shadow)",
|
|
458
|
+
color: "var(--ai-me-text)"
|
|
459
|
+
};
|
|
460
|
+
const focusStyle = {
|
|
461
|
+
outline: "2px solid transparent",
|
|
462
|
+
outlineOffset: 2
|
|
463
|
+
};
|
|
464
|
+
function applyFocusRing(el) {
|
|
465
|
+
el.style.outline = "2px solid var(--ai-me-primary)";
|
|
466
|
+
el.style.outlineOffset = "2px";
|
|
467
|
+
}
|
|
468
|
+
function removeFocusRing(el) {
|
|
469
|
+
el.style.outline = "2px solid transparent";
|
|
470
|
+
el.style.outlineOffset = "2px";
|
|
471
|
+
}
|
|
472
|
+
return (
|
|
473
|
+
// Overlay is presentational — role and aria go on the inner dialog
|
|
474
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
475
|
+
"div",
|
|
476
|
+
{
|
|
477
|
+
style: overlayStyle,
|
|
478
|
+
onClick: (e) => {
|
|
479
|
+
if (e.target === e.currentTarget) onReject();
|
|
480
|
+
},
|
|
481
|
+
"aria-hidden": "false",
|
|
482
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
483
|
+
"div",
|
|
484
|
+
{
|
|
485
|
+
ref: dialogRef,
|
|
486
|
+
style: dialogStyle,
|
|
487
|
+
role: "alertdialog",
|
|
488
|
+
"aria-modal": "true",
|
|
489
|
+
"aria-labelledby": titleId,
|
|
490
|
+
"aria-describedby": descriptionId,
|
|
491
|
+
tabIndex: -1,
|
|
492
|
+
onClick: (e) => e.stopPropagation(),
|
|
493
|
+
children: [
|
|
494
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { id: titleId, style: { margin: "0 0 8px", fontSize: 16 }, children: "Confirm Action" }),
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { margin: "0 0 4px", fontSize: 14, fontWeight: 600 }, children: action }),
|
|
496
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
497
|
+
"p",
|
|
498
|
+
{
|
|
499
|
+
id: descriptionId,
|
|
500
|
+
style: {
|
|
501
|
+
margin: "0 0 16px",
|
|
502
|
+
fontSize: 13,
|
|
503
|
+
color: "var(--ai-me-text-secondary)"
|
|
504
|
+
},
|
|
505
|
+
children: description
|
|
506
|
+
}
|
|
507
|
+
),
|
|
508
|
+
parameters && Object.keys(parameters).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
509
|
+
"pre",
|
|
510
|
+
{
|
|
511
|
+
style: {
|
|
512
|
+
margin: "0 0 16px",
|
|
513
|
+
padding: 12,
|
|
514
|
+
backgroundColor: "var(--ai-me-bg-secondary)",
|
|
515
|
+
borderRadius: 8,
|
|
516
|
+
fontSize: 12,
|
|
517
|
+
overflow: "auto",
|
|
518
|
+
maxHeight: 200,
|
|
519
|
+
border: "1px solid var(--ai-me-border)"
|
|
520
|
+
},
|
|
521
|
+
children: JSON.stringify(parameters, null, 2)
|
|
522
|
+
}
|
|
523
|
+
),
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
526
|
+
"button",
|
|
527
|
+
{
|
|
528
|
+
ref: cancelButtonRef,
|
|
529
|
+
type: "button",
|
|
530
|
+
onClick: onReject,
|
|
531
|
+
style: {
|
|
532
|
+
padding: "8px 16px",
|
|
533
|
+
border: "1px solid var(--ai-me-border)",
|
|
534
|
+
borderRadius: 8,
|
|
535
|
+
backgroundColor: "var(--ai-me-bg)",
|
|
536
|
+
color: "var(--ai-me-text)",
|
|
537
|
+
cursor: "pointer",
|
|
538
|
+
fontSize: 14,
|
|
539
|
+
...focusStyle
|
|
540
|
+
},
|
|
541
|
+
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
542
|
+
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
543
|
+
children: "Cancel"
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
547
|
+
"button",
|
|
548
|
+
{
|
|
549
|
+
type: "button",
|
|
550
|
+
onClick: onConfirm,
|
|
551
|
+
style: {
|
|
552
|
+
padding: "8px 16px",
|
|
553
|
+
border: "none",
|
|
554
|
+
borderRadius: 8,
|
|
555
|
+
// #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)
|
|
556
|
+
backgroundColor: "var(--ai-me-primary)",
|
|
557
|
+
color: "#fff",
|
|
558
|
+
cursor: "pointer",
|
|
559
|
+
fontSize: 14,
|
|
560
|
+
...focusStyle
|
|
561
|
+
},
|
|
562
|
+
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
563
|
+
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
564
|
+
children: "Confirm"
|
|
565
|
+
}
|
|
566
|
+
)
|
|
567
|
+
] })
|
|
568
|
+
]
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
}
|
|
572
|
+
)
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/chat.tsx
|
|
577
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
342
578
|
var srOnly = {
|
|
343
579
|
position: "absolute",
|
|
344
580
|
width: 1,
|
|
@@ -350,6 +586,12 @@ var srOnly = {
|
|
|
350
586
|
whiteSpace: "nowrap",
|
|
351
587
|
borderWidth: 0
|
|
352
588
|
};
|
|
589
|
+
function DefaultAIIcon() {
|
|
590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
591
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5Z" }),
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M19 11l.75 2.25L22 14l-2.25.75L19 17l-.75-2.25L16 14l2.25-.75Z" })
|
|
593
|
+
] });
|
|
594
|
+
}
|
|
353
595
|
function AIMeChat({
|
|
354
596
|
position = "bottom-right",
|
|
355
597
|
theme,
|
|
@@ -358,15 +600,17 @@ function AIMeChat({
|
|
|
358
600
|
defaultOpen = false,
|
|
359
601
|
onToggle,
|
|
360
602
|
onToolComplete,
|
|
361
|
-
onMessageComplete
|
|
603
|
+
onMessageComplete,
|
|
604
|
+
triggerIcon,
|
|
605
|
+
renderConfirmation
|
|
362
606
|
}) {
|
|
363
|
-
const [open, setOpen] = (0,
|
|
364
|
-
const messagesEndRef = (0,
|
|
365
|
-
const inputRef = (0,
|
|
366
|
-
const panelRef = (0,
|
|
367
|
-
const triggerRef = (0,
|
|
368
|
-
const firedToolResults = (0,
|
|
369
|
-
const prevStatus = (0,
|
|
607
|
+
const [open, setOpen] = (0, import_react5.useState)(defaultOpen);
|
|
608
|
+
const messagesEndRef = (0, import_react5.useRef)(null);
|
|
609
|
+
const inputRef = (0, import_react5.useRef)(null);
|
|
610
|
+
const panelRef = (0, import_react5.useRef)(null);
|
|
611
|
+
const triggerRef = (0, import_react5.useRef)(null);
|
|
612
|
+
const firedToolResults = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
|
|
613
|
+
const prevStatus = (0, import_react5.useRef)(null);
|
|
370
614
|
const {
|
|
371
615
|
messages,
|
|
372
616
|
input,
|
|
@@ -374,17 +618,18 @@ function AIMeChat({
|
|
|
374
618
|
handleSubmit,
|
|
375
619
|
status,
|
|
376
620
|
error,
|
|
377
|
-
setInput
|
|
621
|
+
setInput,
|
|
622
|
+
addToolApprovalResponse
|
|
378
623
|
} = useAIMe();
|
|
379
|
-
const titleId = (0,
|
|
380
|
-
const messagesId = (0,
|
|
624
|
+
const titleId = (0, import_react5.useId)();
|
|
625
|
+
const messagesId = (0, import_react5.useId)();
|
|
381
626
|
const isInline = position === "inline";
|
|
382
|
-
const toggleOpen = (0,
|
|
627
|
+
const toggleOpen = (0, import_react5.useCallback)(() => {
|
|
383
628
|
const next = !open;
|
|
384
629
|
setOpen(next);
|
|
385
630
|
onToggle?.(next);
|
|
386
631
|
}, [open, onToggle]);
|
|
387
|
-
(0,
|
|
632
|
+
(0, import_react5.useEffect)(() => {
|
|
388
633
|
function handleKeyDown(e) {
|
|
389
634
|
if ((e.metaKey || e.ctrlKey) && e.key === ".") {
|
|
390
635
|
e.preventDefault();
|
|
@@ -394,10 +639,10 @@ function AIMeChat({
|
|
|
394
639
|
window.addEventListener("keydown", handleKeyDown);
|
|
395
640
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
396
641
|
}, [toggleOpen]);
|
|
397
|
-
(0,
|
|
642
|
+
(0, import_react5.useEffect)(() => {
|
|
398
643
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
399
644
|
}, [messages]);
|
|
400
|
-
(0,
|
|
645
|
+
(0, import_react5.useEffect)(() => {
|
|
401
646
|
if (!onToolComplete) return;
|
|
402
647
|
for (const message of messages) {
|
|
403
648
|
for (const part of message.parts) {
|
|
@@ -413,7 +658,7 @@ function AIMeChat({
|
|
|
413
658
|
}
|
|
414
659
|
}
|
|
415
660
|
}, [messages, onToolComplete]);
|
|
416
|
-
(0,
|
|
661
|
+
(0, import_react5.useEffect)(() => {
|
|
417
662
|
const prev = prevStatus.current;
|
|
418
663
|
prevStatus.current = status;
|
|
419
664
|
if (!onMessageComplete) return;
|
|
@@ -435,7 +680,7 @@ function AIMeChat({
|
|
|
435
680
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
436
681
|
});
|
|
437
682
|
}, [status, messages, onMessageComplete]);
|
|
438
|
-
(0,
|
|
683
|
+
(0, import_react5.useEffect)(() => {
|
|
439
684
|
if (open) {
|
|
440
685
|
panelRef.current?.focus();
|
|
441
686
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
@@ -443,7 +688,7 @@ function AIMeChat({
|
|
|
443
688
|
triggerRef.current?.focus();
|
|
444
689
|
}
|
|
445
690
|
}, [open]);
|
|
446
|
-
(0,
|
|
691
|
+
(0, import_react5.useEffect)(() => {
|
|
447
692
|
if (!open || isInline) return;
|
|
448
693
|
function handleKeyDown(e) {
|
|
449
694
|
if (e.key === "Escape") {
|
|
@@ -475,6 +720,20 @@ function AIMeChat({
|
|
|
475
720
|
window.addEventListener("keydown", handleKeyDown);
|
|
476
721
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
477
722
|
}, [open, isInline, toggleOpen]);
|
|
723
|
+
const pendingToolCalls = (0, import_react5.useMemo)(() => {
|
|
724
|
+
const resultIds = /* @__PURE__ */ new Set();
|
|
725
|
+
const toolCalls = [];
|
|
726
|
+
for (const m of messages) {
|
|
727
|
+
for (const p of m.parts) {
|
|
728
|
+
if (p.type === "tool-result") {
|
|
729
|
+
resultIds.add(p.toolCallId);
|
|
730
|
+
} else if (p.type === "tool-call") {
|
|
731
|
+
toolCalls.push(p);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return toolCalls.filter((tc) => !resultIds.has(tc.toolCallId));
|
|
736
|
+
}, [messages]);
|
|
478
737
|
const themeVars = {
|
|
479
738
|
...defaultThemeVars,
|
|
480
739
|
...themeToVars(theme)
|
|
@@ -530,8 +789,8 @@ function AIMeChat({
|
|
|
530
789
|
zIndex: 9999
|
|
531
790
|
};
|
|
532
791
|
const isStreaming = status === "submitted" || status === "streaming";
|
|
533
|
-
return /* @__PURE__ */ (0,
|
|
534
|
-
/* @__PURE__ */ (0,
|
|
792
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
793
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
535
794
|
"button",
|
|
536
795
|
{
|
|
537
796
|
ref: triggerRef,
|
|
@@ -541,10 +800,10 @@ function AIMeChat({
|
|
|
541
800
|
"aria-expanded": open,
|
|
542
801
|
"aria-controls": isInline ? void 0 : "ai-me-chat-panel",
|
|
543
802
|
type: "button",
|
|
544
|
-
children: /* @__PURE__ */ (0,
|
|
803
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", children: triggerIcon ?? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DefaultAIIcon, {}) })
|
|
545
804
|
}
|
|
546
805
|
),
|
|
547
|
-
/* @__PURE__ */ (0,
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
548
807
|
"div",
|
|
549
808
|
{
|
|
550
809
|
id: "ai-me-chat-panel",
|
|
@@ -556,7 +815,7 @@ function AIMeChat({
|
|
|
556
815
|
"aria-busy": isStreaming,
|
|
557
816
|
tabIndex: -1,
|
|
558
817
|
children: [
|
|
559
|
-
/* @__PURE__ */ (0,
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
560
819
|
"div",
|
|
561
820
|
{
|
|
562
821
|
style: {
|
|
@@ -568,8 +827,8 @@ function AIMeChat({
|
|
|
568
827
|
backgroundColor: "var(--ai-me-bg-secondary)"
|
|
569
828
|
},
|
|
570
829
|
children: [
|
|
571
|
-
/* @__PURE__ */ (0,
|
|
572
|
-
!isInline && /* @__PURE__ */ (0,
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { id: titleId, style: { fontWeight: 600, fontSize: 14 }, children: "AI Assistant" }),
|
|
831
|
+
!isInline && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
573
832
|
"button",
|
|
574
833
|
{
|
|
575
834
|
onClick: toggleOpen,
|
|
@@ -593,13 +852,13 @@ function AIMeChat({
|
|
|
593
852
|
},
|
|
594
853
|
"aria-label": "Close chat",
|
|
595
854
|
type: "button",
|
|
596
|
-
children: /* @__PURE__ */ (0,
|
|
855
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", children: "\u2715" })
|
|
597
856
|
}
|
|
598
857
|
)
|
|
599
858
|
]
|
|
600
859
|
}
|
|
601
860
|
),
|
|
602
|
-
/* @__PURE__ */ (0,
|
|
861
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
603
862
|
"a",
|
|
604
863
|
{
|
|
605
864
|
href: "#ai-me-chat-input",
|
|
@@ -629,7 +888,7 @@ function AIMeChat({
|
|
|
629
888
|
children: "Skip to message input"
|
|
630
889
|
}
|
|
631
890
|
),
|
|
632
|
-
/* @__PURE__ */ (0,
|
|
891
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
633
892
|
"div",
|
|
634
893
|
{
|
|
635
894
|
id: messagesId,
|
|
@@ -645,9 +904,9 @@ function AIMeChat({
|
|
|
645
904
|
gap: 12
|
|
646
905
|
},
|
|
647
906
|
children: [
|
|
648
|
-
messages.length === 0 && /* @__PURE__ */ (0,
|
|
649
|
-
/* @__PURE__ */ (0,
|
|
650
|
-
suggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */ (0,
|
|
907
|
+
messages.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "var(--ai-me-text-secondary)", fontSize: 14 }, children: [
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: welcomeMessage }),
|
|
909
|
+
suggestedPrompts && suggestedPrompts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
651
910
|
"div",
|
|
652
911
|
{
|
|
653
912
|
style: {
|
|
@@ -657,8 +916,8 @@ function AIMeChat({
|
|
|
657
916
|
gap: 8
|
|
658
917
|
},
|
|
659
918
|
children: [
|
|
660
|
-
/* @__PURE__ */ (0,
|
|
661
|
-
suggestedPrompts.map((prompt) => /* @__PURE__ */ (0,
|
|
919
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { margin: "0 0 4px", fontSize: 12, fontWeight: 500 }, children: "Suggested questions:" }),
|
|
920
|
+
suggestedPrompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
662
921
|
"button",
|
|
663
922
|
{
|
|
664
923
|
type: "button",
|
|
@@ -692,31 +951,35 @@ function AIMeChat({
|
|
|
692
951
|
}
|
|
693
952
|
)
|
|
694
953
|
] }),
|
|
695
|
-
messages.map((m) =>
|
|
696
|
-
"
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
954
|
+
messages.map((m) => {
|
|
955
|
+
const hasTextContent = m.parts.some((p) => p.type === "text");
|
|
956
|
+
if (!hasTextContent && m.role === "assistant") return null;
|
|
957
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
958
|
+
"div",
|
|
959
|
+
{
|
|
960
|
+
style: {
|
|
961
|
+
alignSelf: m.role === "user" ? "flex-end" : "flex-start",
|
|
962
|
+
maxWidth: "85%",
|
|
963
|
+
padding: "8px 12px",
|
|
964
|
+
borderRadius: 8,
|
|
965
|
+
backgroundColor: m.role === "user" ? "var(--ai-me-primary)" : "var(--ai-me-bg-secondary)",
|
|
966
|
+
color: m.role === "user" ? "#fff" : "var(--ai-me-text)",
|
|
967
|
+
fontSize: 14,
|
|
968
|
+
lineHeight: 1.5,
|
|
969
|
+
whiteSpace: "pre-wrap",
|
|
970
|
+
wordBreak: "break-word"
|
|
971
|
+
},
|
|
972
|
+
children: [
|
|
973
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: srOnly, children: m.role === "user" ? "You: " : "Assistant: " }),
|
|
974
|
+
m.parts.map(
|
|
975
|
+
(p, i) => p.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
976
|
+
)
|
|
977
|
+
]
|
|
709
978
|
},
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
)
|
|
715
|
-
]
|
|
716
|
-
},
|
|
717
|
-
m.id
|
|
718
|
-
)),
|
|
719
|
-
status === "submitted" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
979
|
+
m.id
|
|
980
|
+
);
|
|
981
|
+
}),
|
|
982
|
+
status === "submitted" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
720
983
|
"div",
|
|
721
984
|
{
|
|
722
985
|
"aria-label": "Assistant is thinking",
|
|
@@ -725,10 +988,10 @@ function AIMeChat({
|
|
|
725
988
|
color: "var(--ai-me-text-secondary)",
|
|
726
989
|
fontSize: 13
|
|
727
990
|
},
|
|
728
|
-
children: /* @__PURE__ */ (0,
|
|
991
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", children: "Thinking\u2026" })
|
|
729
992
|
}
|
|
730
993
|
),
|
|
731
|
-
error && /* @__PURE__ */ (0,
|
|
994
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
732
995
|
"div",
|
|
733
996
|
{
|
|
734
997
|
role: "alert",
|
|
@@ -744,11 +1007,11 @@ function AIMeChat({
|
|
|
744
1007
|
children: "Something went wrong. Please try again."
|
|
745
1008
|
}
|
|
746
1009
|
),
|
|
747
|
-
/* @__PURE__ */ (0,
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: messagesEndRef, "aria-hidden": "true" })
|
|
748
1011
|
]
|
|
749
1012
|
}
|
|
750
1013
|
),
|
|
751
|
-
/* @__PURE__ */ (0,
|
|
1014
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
752
1015
|
"form",
|
|
753
1016
|
{
|
|
754
1017
|
onSubmit: handleSubmit,
|
|
@@ -759,7 +1022,7 @@ function AIMeChat({
|
|
|
759
1022
|
gap: 8
|
|
760
1023
|
},
|
|
761
1024
|
children: [
|
|
762
|
-
/* @__PURE__ */ (0,
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
763
1026
|
"label",
|
|
764
1027
|
{
|
|
765
1028
|
htmlFor: "ai-me-chat-input",
|
|
@@ -767,7 +1030,7 @@ function AIMeChat({
|
|
|
767
1030
|
children: "Message to AI Assistant"
|
|
768
1031
|
}
|
|
769
1032
|
),
|
|
770
|
-
/* @__PURE__ */ (0,
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
771
1034
|
"input",
|
|
772
1035
|
{
|
|
773
1036
|
id: "ai-me-chat-input",
|
|
@@ -798,7 +1061,7 @@ function AIMeChat({
|
|
|
798
1061
|
}
|
|
799
1062
|
}
|
|
800
1063
|
),
|
|
801
|
-
/* @__PURE__ */ (0,
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
802
1065
|
"button",
|
|
803
1066
|
{
|
|
804
1067
|
type: "submit",
|
|
@@ -833,13 +1096,38 @@ function AIMeChat({
|
|
|
833
1096
|
)
|
|
834
1097
|
]
|
|
835
1098
|
}
|
|
836
|
-
)
|
|
1099
|
+
),
|
|
1100
|
+
pendingToolCalls.map((tc) => {
|
|
1101
|
+
const onConfirm = () => addToolApprovalResponse({ id: tc.toolCallId, approved: true });
|
|
1102
|
+
const onCancel = () => addToolApprovalResponse({ id: tc.toolCallId, approved: false, reason: "User cancelled" });
|
|
1103
|
+
return renderConfirmation ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.Fragment, { children: renderConfirmation({
|
|
1104
|
+
tool: {
|
|
1105
|
+
name: tc.toolName,
|
|
1106
|
+
httpMethod: "",
|
|
1107
|
+
path: "",
|
|
1108
|
+
description: tc.toolName
|
|
1109
|
+
},
|
|
1110
|
+
params: tc.args,
|
|
1111
|
+
onConfirm,
|
|
1112
|
+
onCancel
|
|
1113
|
+
}) }, tc.toolCallId) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1114
|
+
AIMeConfirm,
|
|
1115
|
+
{
|
|
1116
|
+
action: tc.toolName,
|
|
1117
|
+
description: `Execute ${tc.toolName}?`,
|
|
1118
|
+
parameters: tc.args,
|
|
1119
|
+
onConfirm,
|
|
1120
|
+
onReject: onCancel
|
|
1121
|
+
},
|
|
1122
|
+
tc.toolCallId
|
|
1123
|
+
);
|
|
1124
|
+
})
|
|
837
1125
|
] });
|
|
838
1126
|
}
|
|
839
1127
|
|
|
840
1128
|
// src/command-palette.tsx
|
|
841
|
-
var
|
|
842
|
-
var
|
|
1129
|
+
var import_react6 = require("react");
|
|
1130
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
843
1131
|
var defaultCommands = [
|
|
844
1132
|
{
|
|
845
1133
|
id: "help",
|
|
@@ -883,17 +1171,17 @@ function AIMeCommandPalette({
|
|
|
883
1171
|
shortcut = { key: "k", meta: true },
|
|
884
1172
|
onToggle
|
|
885
1173
|
}) {
|
|
886
|
-
const [open, setOpen] = (0,
|
|
887
|
-
const [query, setQuery] = (0,
|
|
888
|
-
const [selectedIndex, setSelectedIndex] = (0,
|
|
889
|
-
const inputRef = (0,
|
|
890
|
-
const listRef = (0,
|
|
891
|
-
const dialogRef = (0,
|
|
892
|
-
const previousFocusRef = (0,
|
|
1174
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
1175
|
+
const [query, setQuery] = (0, import_react6.useState)("");
|
|
1176
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react6.useState)(0);
|
|
1177
|
+
const inputRef = (0, import_react6.useRef)(null);
|
|
1178
|
+
const listRef = (0, import_react6.useRef)(null);
|
|
1179
|
+
const dialogRef = (0, import_react6.useRef)(null);
|
|
1180
|
+
const previousFocusRef = (0, import_react6.useRef)(null);
|
|
893
1181
|
const { sendMessage } = useAIMe();
|
|
894
|
-
const titleId = (0,
|
|
895
|
-
const inputId = (0,
|
|
896
|
-
const toggle = (0,
|
|
1182
|
+
const titleId = (0, import_react6.useId)();
|
|
1183
|
+
const inputId = (0, import_react6.useId)();
|
|
1184
|
+
const toggle = (0, import_react6.useCallback)(
|
|
897
1185
|
(next) => {
|
|
898
1186
|
setOpen(next);
|
|
899
1187
|
setQuery("");
|
|
@@ -902,7 +1190,7 @@ function AIMeCommandPalette({
|
|
|
902
1190
|
},
|
|
903
1191
|
[onToggle]
|
|
904
1192
|
);
|
|
905
|
-
(0,
|
|
1193
|
+
(0, import_react6.useEffect)(() => {
|
|
906
1194
|
function handleKeyDown2(e) {
|
|
907
1195
|
const metaMatch = shortcut.meta ? e.metaKey : true;
|
|
908
1196
|
const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;
|
|
@@ -917,7 +1205,7 @@ function AIMeCommandPalette({
|
|
|
917
1205
|
window.addEventListener("keydown", handleKeyDown2);
|
|
918
1206
|
return () => window.removeEventListener("keydown", handleKeyDown2);
|
|
919
1207
|
}, [open, shortcut, toggle]);
|
|
920
|
-
(0,
|
|
1208
|
+
(0, import_react6.useEffect)(() => {
|
|
921
1209
|
if (open) {
|
|
922
1210
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
923
1211
|
} else {
|
|
@@ -927,7 +1215,7 @@ function AIMeCommandPalette({
|
|
|
927
1215
|
}
|
|
928
1216
|
}
|
|
929
1217
|
}, [open]);
|
|
930
|
-
(0,
|
|
1218
|
+
(0, import_react6.useEffect)(() => {
|
|
931
1219
|
if (!open) return;
|
|
932
1220
|
function handleFocusTrap(e) {
|
|
933
1221
|
if (e.key !== "Tab") return;
|
|
@@ -957,12 +1245,12 @@ function AIMeCommandPalette({
|
|
|
957
1245
|
const filtered = query.trim() ? commands.filter(
|
|
958
1246
|
(cmd) => cmd.label.toLowerCase().includes(query.toLowerCase()) || cmd.description?.toLowerCase().includes(query.toLowerCase()) || cmd.category?.toLowerCase().includes(query.toLowerCase())
|
|
959
1247
|
) : commands;
|
|
960
|
-
(0,
|
|
1248
|
+
(0, import_react6.useEffect)(() => {
|
|
961
1249
|
if (selectedIndex >= filtered.length) {
|
|
962
1250
|
setSelectedIndex(Math.max(0, filtered.length - 1));
|
|
963
1251
|
}
|
|
964
1252
|
}, [filtered.length, selectedIndex]);
|
|
965
|
-
(0,
|
|
1253
|
+
(0, import_react6.useEffect)(() => {
|
|
966
1254
|
const list = listRef.current;
|
|
967
1255
|
if (!list) return;
|
|
968
1256
|
const selected = list.children[selectedIndex];
|
|
@@ -1007,8 +1295,8 @@ function AIMeCommandPalette({
|
|
|
1007
1295
|
grouped.get(cat).push(cmd);
|
|
1008
1296
|
}
|
|
1009
1297
|
let flatIndex = 0;
|
|
1010
|
-
return /* @__PURE__ */ (0,
|
|
1011
|
-
/* @__PURE__ */ (0,
|
|
1298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1012
1300
|
"div",
|
|
1013
1301
|
{
|
|
1014
1302
|
onClick: () => toggle(false),
|
|
@@ -1021,7 +1309,7 @@ function AIMeCommandPalette({
|
|
|
1021
1309
|
"aria-hidden": "true"
|
|
1022
1310
|
}
|
|
1023
1311
|
),
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1025
1313
|
"div",
|
|
1026
1314
|
{
|
|
1027
1315
|
ref: dialogRef,
|
|
@@ -1049,10 +1337,10 @@ function AIMeCommandPalette({
|
|
|
1049
1337
|
"aria-labelledby": titleId,
|
|
1050
1338
|
tabIndex: -1,
|
|
1051
1339
|
children: [
|
|
1052
|
-
/* @__PURE__ */ (0,
|
|
1053
|
-
/* @__PURE__ */ (0,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1055
|
-
/* @__PURE__ */ (0,
|
|
1340
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { id: titleId, style: srOnly2, children: "Command Palette" }),
|
|
1341
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { padding: "12px 16px", borderBottom: "1px solid var(--ai-me-border)" }, children: [
|
|
1342
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: inputId, style: srOnly2, children: "Search commands or ask AI" }),
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1056
1344
|
"input",
|
|
1057
1345
|
{
|
|
1058
1346
|
id: inputId,
|
|
@@ -1090,7 +1378,7 @@ function AIMeCommandPalette({
|
|
|
1090
1378
|
}
|
|
1091
1379
|
)
|
|
1092
1380
|
] }),
|
|
1093
|
-
/* @__PURE__ */ (0,
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1094
1382
|
"div",
|
|
1095
1383
|
{
|
|
1096
1384
|
id: "ai-me-cmd-listbox",
|
|
@@ -1099,7 +1387,7 @@ function AIMeCommandPalette({
|
|
|
1099
1387
|
role: "listbox",
|
|
1100
1388
|
"aria-label": "Commands",
|
|
1101
1389
|
children: [
|
|
1102
|
-
filtered.length === 0 && query.trim() && /* @__PURE__ */ (0,
|
|
1390
|
+
filtered.length === 0 && query.trim() && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1103
1391
|
"div",
|
|
1104
1392
|
{
|
|
1105
1393
|
role: "option",
|
|
@@ -1119,8 +1407,8 @@ function AIMeCommandPalette({
|
|
|
1119
1407
|
),
|
|
1120
1408
|
Array.from(grouped.entries()).map(([category, items]) => (
|
|
1121
1409
|
// role="group" with aria-label for the category heading
|
|
1122
|
-
/* @__PURE__ */ (0,
|
|
1123
|
-
/* @__PURE__ */ (0,
|
|
1410
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "group", "aria-label": category, children: [
|
|
1411
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1124
1412
|
"div",
|
|
1125
1413
|
{
|
|
1126
1414
|
"aria-hidden": "true",
|
|
@@ -1138,7 +1426,7 @@ function AIMeCommandPalette({
|
|
|
1138
1426
|
items.map((cmd) => {
|
|
1139
1427
|
const idx = flatIndex++;
|
|
1140
1428
|
const isSelected = idx === selectedIndex;
|
|
1141
|
-
return /* @__PURE__ */ (0,
|
|
1429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1142
1430
|
"div",
|
|
1143
1431
|
{
|
|
1144
1432
|
id: `cmd-${cmd.id}`,
|
|
@@ -1171,10 +1459,10 @@ function AIMeCommandPalette({
|
|
|
1171
1459
|
},
|
|
1172
1460
|
children: [
|
|
1173
1461
|
cmd.icon && // Icon is decorative — label comes from cmd.label
|
|
1174
|
-
/* @__PURE__ */ (0,
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
1176
|
-
/* @__PURE__ */ (0,
|
|
1177
|
-
cmd.description && /* @__PURE__ */ (0,
|
|
1462
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": "true", style: { fontSize: 16, flexShrink: 0 }, children: cmd.icon }),
|
|
1463
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
1464
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: 14, fontWeight: 500 }, children: cmd.label }),
|
|
1465
|
+
cmd.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1178
1466
|
"div",
|
|
1179
1467
|
{
|
|
1180
1468
|
style: {
|
|
@@ -1198,7 +1486,7 @@ function AIMeCommandPalette({
|
|
|
1198
1486
|
]
|
|
1199
1487
|
}
|
|
1200
1488
|
),
|
|
1201
|
-
/* @__PURE__ */ (0,
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1202
1490
|
"div",
|
|
1203
1491
|
{
|
|
1204
1492
|
"aria-hidden": "true",
|
|
@@ -1211,9 +1499,9 @@ function AIMeCommandPalette({
|
|
|
1211
1499
|
gap: 16
|
|
1212
1500
|
},
|
|
1213
1501
|
children: [
|
|
1214
|
-
/* @__PURE__ */ (0,
|
|
1215
|
-
/* @__PURE__ */ (0,
|
|
1216
|
-
/* @__PURE__ */ (0,
|
|
1502
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u2191\u2193 Navigate" }),
|
|
1503
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u21B5 Select" }),
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Esc Close" })
|
|
1217
1505
|
]
|
|
1218
1506
|
}
|
|
1219
1507
|
)
|
|
@@ -1222,201 +1510,13 @@ function AIMeCommandPalette({
|
|
|
1222
1510
|
)
|
|
1223
1511
|
] });
|
|
1224
1512
|
}
|
|
1225
|
-
|
|
1226
|
-
// src/confirm.tsx
|
|
1227
|
-
var import_react6 = require("react");
|
|
1228
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1229
|
-
function AIMeConfirm({
|
|
1230
|
-
action,
|
|
1231
|
-
description,
|
|
1232
|
-
parameters,
|
|
1233
|
-
onConfirm,
|
|
1234
|
-
onReject
|
|
1235
|
-
}) {
|
|
1236
|
-
const dialogRef = (0, import_react6.useRef)(null);
|
|
1237
|
-
const cancelButtonRef = (0, import_react6.useRef)(null);
|
|
1238
|
-
const titleId = (0, import_react6.useId)();
|
|
1239
|
-
const descriptionId = (0, import_react6.useId)();
|
|
1240
|
-
const handleKeyDown = (0, import_react6.useCallback)(
|
|
1241
|
-
(e) => {
|
|
1242
|
-
if (e.key === "Escape") {
|
|
1243
|
-
e.preventDefault();
|
|
1244
|
-
onReject();
|
|
1245
|
-
return;
|
|
1246
|
-
}
|
|
1247
|
-
if (e.key !== "Tab") return;
|
|
1248
|
-
const dialog = dialogRef.current;
|
|
1249
|
-
if (!dialog) return;
|
|
1250
|
-
const focusable = dialog.querySelectorAll(
|
|
1251
|
-
'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
1252
|
-
);
|
|
1253
|
-
if (focusable.length === 0) return;
|
|
1254
|
-
const first = focusable[0];
|
|
1255
|
-
const last = focusable[focusable.length - 1];
|
|
1256
|
-
if (e.shiftKey) {
|
|
1257
|
-
if (document.activeElement === first) {
|
|
1258
|
-
e.preventDefault();
|
|
1259
|
-
last.focus();
|
|
1260
|
-
}
|
|
1261
|
-
} else {
|
|
1262
|
-
if (document.activeElement === last) {
|
|
1263
|
-
e.preventDefault();
|
|
1264
|
-
first.focus();
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
},
|
|
1268
|
-
[onReject]
|
|
1269
|
-
);
|
|
1270
|
-
(0, import_react6.useEffect)(() => {
|
|
1271
|
-
const previousFocus = document.activeElement;
|
|
1272
|
-
cancelButtonRef.current?.focus();
|
|
1273
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1274
|
-
return () => {
|
|
1275
|
-
window.removeEventListener("keydown", handleKeyDown);
|
|
1276
|
-
previousFocus?.focus();
|
|
1277
|
-
};
|
|
1278
|
-
}, [handleKeyDown]);
|
|
1279
|
-
const overlayStyle = {
|
|
1280
|
-
...defaultThemeVars,
|
|
1281
|
-
position: "fixed",
|
|
1282
|
-
inset: 0,
|
|
1283
|
-
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
1284
|
-
display: "flex",
|
|
1285
|
-
alignItems: "center",
|
|
1286
|
-
justifyContent: "center",
|
|
1287
|
-
zIndex: 1e4,
|
|
1288
|
-
fontFamily: "var(--ai-me-font)"
|
|
1289
|
-
};
|
|
1290
|
-
const dialogStyle = {
|
|
1291
|
-
backgroundColor: "var(--ai-me-bg)",
|
|
1292
|
-
borderRadius: "var(--ai-me-radius)",
|
|
1293
|
-
padding: 24,
|
|
1294
|
-
maxWidth: 420,
|
|
1295
|
-
width: "90%",
|
|
1296
|
-
boxShadow: "var(--ai-me-shadow)",
|
|
1297
|
-
color: "var(--ai-me-text)"
|
|
1298
|
-
};
|
|
1299
|
-
const focusStyle = {
|
|
1300
|
-
outline: "2px solid transparent",
|
|
1301
|
-
outlineOffset: 2
|
|
1302
|
-
};
|
|
1303
|
-
function applyFocusRing(el) {
|
|
1304
|
-
el.style.outline = "2px solid var(--ai-me-primary)";
|
|
1305
|
-
el.style.outlineOffset = "2px";
|
|
1306
|
-
}
|
|
1307
|
-
function removeFocusRing(el) {
|
|
1308
|
-
el.style.outline = "2px solid transparent";
|
|
1309
|
-
el.style.outlineOffset = "2px";
|
|
1310
|
-
}
|
|
1311
|
-
return (
|
|
1312
|
-
// Overlay is presentational — role and aria go on the inner dialog
|
|
1313
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1314
|
-
"div",
|
|
1315
|
-
{
|
|
1316
|
-
style: overlayStyle,
|
|
1317
|
-
onClick: (e) => {
|
|
1318
|
-
if (e.target === e.currentTarget) onReject();
|
|
1319
|
-
},
|
|
1320
|
-
"aria-hidden": "false",
|
|
1321
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1322
|
-
"div",
|
|
1323
|
-
{
|
|
1324
|
-
ref: dialogRef,
|
|
1325
|
-
style: dialogStyle,
|
|
1326
|
-
role: "alertdialog",
|
|
1327
|
-
"aria-modal": "true",
|
|
1328
|
-
"aria-labelledby": titleId,
|
|
1329
|
-
"aria-describedby": descriptionId,
|
|
1330
|
-
tabIndex: -1,
|
|
1331
|
-
onClick: (e) => e.stopPropagation(),
|
|
1332
|
-
children: [
|
|
1333
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { id: titleId, style: { margin: "0 0 8px", fontSize: 16 }, children: "Confirm Action" }),
|
|
1334
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { margin: "0 0 4px", fontSize: 14, fontWeight: 600 }, children: action }),
|
|
1335
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1336
|
-
"p",
|
|
1337
|
-
{
|
|
1338
|
-
id: descriptionId,
|
|
1339
|
-
style: {
|
|
1340
|
-
margin: "0 0 16px",
|
|
1341
|
-
fontSize: 13,
|
|
1342
|
-
color: "var(--ai-me-text-secondary)"
|
|
1343
|
-
},
|
|
1344
|
-
children: description
|
|
1345
|
-
}
|
|
1346
|
-
),
|
|
1347
|
-
parameters && Object.keys(parameters).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1348
|
-
"pre",
|
|
1349
|
-
{
|
|
1350
|
-
style: {
|
|
1351
|
-
margin: "0 0 16px",
|
|
1352
|
-
padding: 12,
|
|
1353
|
-
backgroundColor: "var(--ai-me-bg-secondary)",
|
|
1354
|
-
borderRadius: 8,
|
|
1355
|
-
fontSize: 12,
|
|
1356
|
-
overflow: "auto",
|
|
1357
|
-
maxHeight: 200,
|
|
1358
|
-
border: "1px solid var(--ai-me-border)"
|
|
1359
|
-
},
|
|
1360
|
-
children: JSON.stringify(parameters, null, 2)
|
|
1361
|
-
}
|
|
1362
|
-
),
|
|
1363
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
|
|
1364
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1365
|
-
"button",
|
|
1366
|
-
{
|
|
1367
|
-
ref: cancelButtonRef,
|
|
1368
|
-
type: "button",
|
|
1369
|
-
onClick: onReject,
|
|
1370
|
-
style: {
|
|
1371
|
-
padding: "8px 16px",
|
|
1372
|
-
border: "1px solid var(--ai-me-border)",
|
|
1373
|
-
borderRadius: 8,
|
|
1374
|
-
backgroundColor: "var(--ai-me-bg)",
|
|
1375
|
-
color: "var(--ai-me-text)",
|
|
1376
|
-
cursor: "pointer",
|
|
1377
|
-
fontSize: 14,
|
|
1378
|
-
...focusStyle
|
|
1379
|
-
},
|
|
1380
|
-
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
1381
|
-
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
1382
|
-
children: "Cancel"
|
|
1383
|
-
}
|
|
1384
|
-
),
|
|
1385
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1386
|
-
"button",
|
|
1387
|
-
{
|
|
1388
|
-
type: "button",
|
|
1389
|
-
onClick: onConfirm,
|
|
1390
|
-
style: {
|
|
1391
|
-
padding: "8px 16px",
|
|
1392
|
-
border: "none",
|
|
1393
|
-
borderRadius: 8,
|
|
1394
|
-
// #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)
|
|
1395
|
-
backgroundColor: "var(--ai-me-primary)",
|
|
1396
|
-
color: "#fff",
|
|
1397
|
-
cursor: "pointer",
|
|
1398
|
-
fontSize: 14,
|
|
1399
|
-
...focusStyle
|
|
1400
|
-
},
|
|
1401
|
-
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
1402
|
-
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
1403
|
-
children: "Confirm"
|
|
1404
|
-
}
|
|
1405
|
-
)
|
|
1406
|
-
] })
|
|
1407
|
-
]
|
|
1408
|
-
}
|
|
1409
|
-
)
|
|
1410
|
-
}
|
|
1411
|
-
)
|
|
1412
|
-
);
|
|
1413
|
-
}
|
|
1414
1513
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1415
1514
|
0 && (module.exports = {
|
|
1416
1515
|
AIMeChat,
|
|
1417
1516
|
AIMeCommandPalette,
|
|
1418
1517
|
AIMeConfirm,
|
|
1419
1518
|
AIMeProvider,
|
|
1519
|
+
cleanAssistantText,
|
|
1420
1520
|
renderMarkdown,
|
|
1421
1521
|
useAIMe,
|
|
1422
1522
|
useAIMeContext
|