@ai-me-chat/react 0.2.1 → 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 +375 -279
- 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 +371 -276
- 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",
|
|
@@ -695,7 +954,7 @@ function AIMeChat({
|
|
|
695
954
|
messages.map((m) => {
|
|
696
955
|
const hasTextContent = m.parts.some((p) => p.type === "text");
|
|
697
956
|
if (!hasTextContent && m.role === "assistant") return null;
|
|
698
|
-
return /* @__PURE__ */ (0,
|
|
957
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
699
958
|
"div",
|
|
700
959
|
{
|
|
701
960
|
style: {
|
|
@@ -711,16 +970,16 @@ function AIMeChat({
|
|
|
711
970
|
wordBreak: "break-word"
|
|
712
971
|
},
|
|
713
972
|
children: [
|
|
714
|
-
/* @__PURE__ */ (0,
|
|
973
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: srOnly, children: m.role === "user" ? "You: " : "Assistant: " }),
|
|
715
974
|
m.parts.map(
|
|
716
|
-
(p, i) => p.type === "text" ? /* @__PURE__ */ (0,
|
|
975
|
+
(p, i) => p.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: m.role === "assistant" ? renderMarkdown(p.text) : p.text }, i) : null
|
|
717
976
|
)
|
|
718
977
|
]
|
|
719
978
|
},
|
|
720
979
|
m.id
|
|
721
980
|
);
|
|
722
981
|
}),
|
|
723
|
-
status === "submitted" && /* @__PURE__ */ (0,
|
|
982
|
+
status === "submitted" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
724
983
|
"div",
|
|
725
984
|
{
|
|
726
985
|
"aria-label": "Assistant is thinking",
|
|
@@ -729,10 +988,10 @@ function AIMeChat({
|
|
|
729
988
|
color: "var(--ai-me-text-secondary)",
|
|
730
989
|
fontSize: 13
|
|
731
990
|
},
|
|
732
|
-
children: /* @__PURE__ */ (0,
|
|
991
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", children: "Thinking\u2026" })
|
|
733
992
|
}
|
|
734
993
|
),
|
|
735
|
-
error && /* @__PURE__ */ (0,
|
|
994
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
736
995
|
"div",
|
|
737
996
|
{
|
|
738
997
|
role: "alert",
|
|
@@ -748,11 +1007,11 @@ function AIMeChat({
|
|
|
748
1007
|
children: "Something went wrong. Please try again."
|
|
749
1008
|
}
|
|
750
1009
|
),
|
|
751
|
-
/* @__PURE__ */ (0,
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: messagesEndRef, "aria-hidden": "true" })
|
|
752
1011
|
]
|
|
753
1012
|
}
|
|
754
1013
|
),
|
|
755
|
-
/* @__PURE__ */ (0,
|
|
1014
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
756
1015
|
"form",
|
|
757
1016
|
{
|
|
758
1017
|
onSubmit: handleSubmit,
|
|
@@ -763,7 +1022,7 @@ function AIMeChat({
|
|
|
763
1022
|
gap: 8
|
|
764
1023
|
},
|
|
765
1024
|
children: [
|
|
766
|
-
/* @__PURE__ */ (0,
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
767
1026
|
"label",
|
|
768
1027
|
{
|
|
769
1028
|
htmlFor: "ai-me-chat-input",
|
|
@@ -771,7 +1030,7 @@ function AIMeChat({
|
|
|
771
1030
|
children: "Message to AI Assistant"
|
|
772
1031
|
}
|
|
773
1032
|
),
|
|
774
|
-
/* @__PURE__ */ (0,
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
775
1034
|
"input",
|
|
776
1035
|
{
|
|
777
1036
|
id: "ai-me-chat-input",
|
|
@@ -802,7 +1061,7 @@ function AIMeChat({
|
|
|
802
1061
|
}
|
|
803
1062
|
}
|
|
804
1063
|
),
|
|
805
|
-
/* @__PURE__ */ (0,
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
806
1065
|
"button",
|
|
807
1066
|
{
|
|
808
1067
|
type: "submit",
|
|
@@ -837,13 +1096,38 @@ function AIMeChat({
|
|
|
837
1096
|
)
|
|
838
1097
|
]
|
|
839
1098
|
}
|
|
840
|
-
)
|
|
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
|
+
})
|
|
841
1125
|
] });
|
|
842
1126
|
}
|
|
843
1127
|
|
|
844
1128
|
// src/command-palette.tsx
|
|
845
|
-
var
|
|
846
|
-
var
|
|
1129
|
+
var import_react6 = require("react");
|
|
1130
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
847
1131
|
var defaultCommands = [
|
|
848
1132
|
{
|
|
849
1133
|
id: "help",
|
|
@@ -887,17 +1171,17 @@ function AIMeCommandPalette({
|
|
|
887
1171
|
shortcut = { key: "k", meta: true },
|
|
888
1172
|
onToggle
|
|
889
1173
|
}) {
|
|
890
|
-
const [open, setOpen] = (0,
|
|
891
|
-
const [query, setQuery] = (0,
|
|
892
|
-
const [selectedIndex, setSelectedIndex] = (0,
|
|
893
|
-
const inputRef = (0,
|
|
894
|
-
const listRef = (0,
|
|
895
|
-
const dialogRef = (0,
|
|
896
|
-
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);
|
|
897
1181
|
const { sendMessage } = useAIMe();
|
|
898
|
-
const titleId = (0,
|
|
899
|
-
const inputId = (0,
|
|
900
|
-
const toggle = (0,
|
|
1182
|
+
const titleId = (0, import_react6.useId)();
|
|
1183
|
+
const inputId = (0, import_react6.useId)();
|
|
1184
|
+
const toggle = (0, import_react6.useCallback)(
|
|
901
1185
|
(next) => {
|
|
902
1186
|
setOpen(next);
|
|
903
1187
|
setQuery("");
|
|
@@ -906,7 +1190,7 @@ function AIMeCommandPalette({
|
|
|
906
1190
|
},
|
|
907
1191
|
[onToggle]
|
|
908
1192
|
);
|
|
909
|
-
(0,
|
|
1193
|
+
(0, import_react6.useEffect)(() => {
|
|
910
1194
|
function handleKeyDown2(e) {
|
|
911
1195
|
const metaMatch = shortcut.meta ? e.metaKey : true;
|
|
912
1196
|
const ctrlMatch = shortcut.ctrl ? e.ctrlKey : !shortcut.meta ? e.ctrlKey : true;
|
|
@@ -921,7 +1205,7 @@ function AIMeCommandPalette({
|
|
|
921
1205
|
window.addEventListener("keydown", handleKeyDown2);
|
|
922
1206
|
return () => window.removeEventListener("keydown", handleKeyDown2);
|
|
923
1207
|
}, [open, shortcut, toggle]);
|
|
924
|
-
(0,
|
|
1208
|
+
(0, import_react6.useEffect)(() => {
|
|
925
1209
|
if (open) {
|
|
926
1210
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
927
1211
|
} else {
|
|
@@ -931,7 +1215,7 @@ function AIMeCommandPalette({
|
|
|
931
1215
|
}
|
|
932
1216
|
}
|
|
933
1217
|
}, [open]);
|
|
934
|
-
(0,
|
|
1218
|
+
(0, import_react6.useEffect)(() => {
|
|
935
1219
|
if (!open) return;
|
|
936
1220
|
function handleFocusTrap(e) {
|
|
937
1221
|
if (e.key !== "Tab") return;
|
|
@@ -961,12 +1245,12 @@ function AIMeCommandPalette({
|
|
|
961
1245
|
const filtered = query.trim() ? commands.filter(
|
|
962
1246
|
(cmd) => cmd.label.toLowerCase().includes(query.toLowerCase()) || cmd.description?.toLowerCase().includes(query.toLowerCase()) || cmd.category?.toLowerCase().includes(query.toLowerCase())
|
|
963
1247
|
) : commands;
|
|
964
|
-
(0,
|
|
1248
|
+
(0, import_react6.useEffect)(() => {
|
|
965
1249
|
if (selectedIndex >= filtered.length) {
|
|
966
1250
|
setSelectedIndex(Math.max(0, filtered.length - 1));
|
|
967
1251
|
}
|
|
968
1252
|
}, [filtered.length, selectedIndex]);
|
|
969
|
-
(0,
|
|
1253
|
+
(0, import_react6.useEffect)(() => {
|
|
970
1254
|
const list = listRef.current;
|
|
971
1255
|
if (!list) return;
|
|
972
1256
|
const selected = list.children[selectedIndex];
|
|
@@ -1011,8 +1295,8 @@ function AIMeCommandPalette({
|
|
|
1011
1295
|
grouped.get(cat).push(cmd);
|
|
1012
1296
|
}
|
|
1013
1297
|
let flatIndex = 0;
|
|
1014
|
-
return /* @__PURE__ */ (0,
|
|
1015
|
-
/* @__PURE__ */ (0,
|
|
1298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1016
1300
|
"div",
|
|
1017
1301
|
{
|
|
1018
1302
|
onClick: () => toggle(false),
|
|
@@ -1025,7 +1309,7 @@ function AIMeCommandPalette({
|
|
|
1025
1309
|
"aria-hidden": "true"
|
|
1026
1310
|
}
|
|
1027
1311
|
),
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1029
1313
|
"div",
|
|
1030
1314
|
{
|
|
1031
1315
|
ref: dialogRef,
|
|
@@ -1053,10 +1337,10 @@ function AIMeCommandPalette({
|
|
|
1053
1337
|
"aria-labelledby": titleId,
|
|
1054
1338
|
tabIndex: -1,
|
|
1055
1339
|
children: [
|
|
1056
|
-
/* @__PURE__ */ (0,
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1058
|
-
/* @__PURE__ */ (0,
|
|
1059
|
-
/* @__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)(
|
|
1060
1344
|
"input",
|
|
1061
1345
|
{
|
|
1062
1346
|
id: inputId,
|
|
@@ -1094,7 +1378,7 @@ function AIMeCommandPalette({
|
|
|
1094
1378
|
}
|
|
1095
1379
|
)
|
|
1096
1380
|
] }),
|
|
1097
|
-
/* @__PURE__ */ (0,
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1098
1382
|
"div",
|
|
1099
1383
|
{
|
|
1100
1384
|
id: "ai-me-cmd-listbox",
|
|
@@ -1103,7 +1387,7 @@ function AIMeCommandPalette({
|
|
|
1103
1387
|
role: "listbox",
|
|
1104
1388
|
"aria-label": "Commands",
|
|
1105
1389
|
children: [
|
|
1106
|
-
filtered.length === 0 && query.trim() && /* @__PURE__ */ (0,
|
|
1390
|
+
filtered.length === 0 && query.trim() && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1107
1391
|
"div",
|
|
1108
1392
|
{
|
|
1109
1393
|
role: "option",
|
|
@@ -1123,8 +1407,8 @@ function AIMeCommandPalette({
|
|
|
1123
1407
|
),
|
|
1124
1408
|
Array.from(grouped.entries()).map(([category, items]) => (
|
|
1125
1409
|
// role="group" with aria-label for the category heading
|
|
1126
|
-
/* @__PURE__ */ (0,
|
|
1127
|
-
/* @__PURE__ */ (0,
|
|
1410
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "group", "aria-label": category, children: [
|
|
1411
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1128
1412
|
"div",
|
|
1129
1413
|
{
|
|
1130
1414
|
"aria-hidden": "true",
|
|
@@ -1142,7 +1426,7 @@ function AIMeCommandPalette({
|
|
|
1142
1426
|
items.map((cmd) => {
|
|
1143
1427
|
const idx = flatIndex++;
|
|
1144
1428
|
const isSelected = idx === selectedIndex;
|
|
1145
|
-
return /* @__PURE__ */ (0,
|
|
1429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1146
1430
|
"div",
|
|
1147
1431
|
{
|
|
1148
1432
|
id: `cmd-${cmd.id}`,
|
|
@@ -1175,10 +1459,10 @@ function AIMeCommandPalette({
|
|
|
1175
1459
|
},
|
|
1176
1460
|
children: [
|
|
1177
1461
|
cmd.icon && // Icon is decorative — label comes from cmd.label
|
|
1178
|
-
/* @__PURE__ */ (0,
|
|
1179
|
-
/* @__PURE__ */ (0,
|
|
1180
|
-
/* @__PURE__ */ (0,
|
|
1181
|
-
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)(
|
|
1182
1466
|
"div",
|
|
1183
1467
|
{
|
|
1184
1468
|
style: {
|
|
@@ -1202,7 +1486,7 @@ function AIMeCommandPalette({
|
|
|
1202
1486
|
]
|
|
1203
1487
|
}
|
|
1204
1488
|
),
|
|
1205
|
-
/* @__PURE__ */ (0,
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1206
1490
|
"div",
|
|
1207
1491
|
{
|
|
1208
1492
|
"aria-hidden": "true",
|
|
@@ -1215,9 +1499,9 @@ function AIMeCommandPalette({
|
|
|
1215
1499
|
gap: 16
|
|
1216
1500
|
},
|
|
1217
1501
|
children: [
|
|
1218
|
-
/* @__PURE__ */ (0,
|
|
1219
|
-
/* @__PURE__ */ (0,
|
|
1220
|
-
/* @__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" })
|
|
1221
1505
|
]
|
|
1222
1506
|
}
|
|
1223
1507
|
)
|
|
@@ -1226,201 +1510,13 @@ function AIMeCommandPalette({
|
|
|
1226
1510
|
)
|
|
1227
1511
|
] });
|
|
1228
1512
|
}
|
|
1229
|
-
|
|
1230
|
-
// src/confirm.tsx
|
|
1231
|
-
var import_react6 = require("react");
|
|
1232
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1233
|
-
function AIMeConfirm({
|
|
1234
|
-
action,
|
|
1235
|
-
description,
|
|
1236
|
-
parameters,
|
|
1237
|
-
onConfirm,
|
|
1238
|
-
onReject
|
|
1239
|
-
}) {
|
|
1240
|
-
const dialogRef = (0, import_react6.useRef)(null);
|
|
1241
|
-
const cancelButtonRef = (0, import_react6.useRef)(null);
|
|
1242
|
-
const titleId = (0, import_react6.useId)();
|
|
1243
|
-
const descriptionId = (0, import_react6.useId)();
|
|
1244
|
-
const handleKeyDown = (0, import_react6.useCallback)(
|
|
1245
|
-
(e) => {
|
|
1246
|
-
if (e.key === "Escape") {
|
|
1247
|
-
e.preventDefault();
|
|
1248
|
-
onReject();
|
|
1249
|
-
return;
|
|
1250
|
-
}
|
|
1251
|
-
if (e.key !== "Tab") return;
|
|
1252
|
-
const dialog = dialogRef.current;
|
|
1253
|
-
if (!dialog) return;
|
|
1254
|
-
const focusable = dialog.querySelectorAll(
|
|
1255
|
-
'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
1256
|
-
);
|
|
1257
|
-
if (focusable.length === 0) return;
|
|
1258
|
-
const first = focusable[0];
|
|
1259
|
-
const last = focusable[focusable.length - 1];
|
|
1260
|
-
if (e.shiftKey) {
|
|
1261
|
-
if (document.activeElement === first) {
|
|
1262
|
-
e.preventDefault();
|
|
1263
|
-
last.focus();
|
|
1264
|
-
}
|
|
1265
|
-
} else {
|
|
1266
|
-
if (document.activeElement === last) {
|
|
1267
|
-
e.preventDefault();
|
|
1268
|
-
first.focus();
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
},
|
|
1272
|
-
[onReject]
|
|
1273
|
-
);
|
|
1274
|
-
(0, import_react6.useEffect)(() => {
|
|
1275
|
-
const previousFocus = document.activeElement;
|
|
1276
|
-
cancelButtonRef.current?.focus();
|
|
1277
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1278
|
-
return () => {
|
|
1279
|
-
window.removeEventListener("keydown", handleKeyDown);
|
|
1280
|
-
previousFocus?.focus();
|
|
1281
|
-
};
|
|
1282
|
-
}, [handleKeyDown]);
|
|
1283
|
-
const overlayStyle = {
|
|
1284
|
-
...defaultThemeVars,
|
|
1285
|
-
position: "fixed",
|
|
1286
|
-
inset: 0,
|
|
1287
|
-
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
1288
|
-
display: "flex",
|
|
1289
|
-
alignItems: "center",
|
|
1290
|
-
justifyContent: "center",
|
|
1291
|
-
zIndex: 1e4,
|
|
1292
|
-
fontFamily: "var(--ai-me-font)"
|
|
1293
|
-
};
|
|
1294
|
-
const dialogStyle = {
|
|
1295
|
-
backgroundColor: "var(--ai-me-bg)",
|
|
1296
|
-
borderRadius: "var(--ai-me-radius)",
|
|
1297
|
-
padding: 24,
|
|
1298
|
-
maxWidth: 420,
|
|
1299
|
-
width: "90%",
|
|
1300
|
-
boxShadow: "var(--ai-me-shadow)",
|
|
1301
|
-
color: "var(--ai-me-text)"
|
|
1302
|
-
};
|
|
1303
|
-
const focusStyle = {
|
|
1304
|
-
outline: "2px solid transparent",
|
|
1305
|
-
outlineOffset: 2
|
|
1306
|
-
};
|
|
1307
|
-
function applyFocusRing(el) {
|
|
1308
|
-
el.style.outline = "2px solid var(--ai-me-primary)";
|
|
1309
|
-
el.style.outlineOffset = "2px";
|
|
1310
|
-
}
|
|
1311
|
-
function removeFocusRing(el) {
|
|
1312
|
-
el.style.outline = "2px solid transparent";
|
|
1313
|
-
el.style.outlineOffset = "2px";
|
|
1314
|
-
}
|
|
1315
|
-
return (
|
|
1316
|
-
// Overlay is presentational — role and aria go on the inner dialog
|
|
1317
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1318
|
-
"div",
|
|
1319
|
-
{
|
|
1320
|
-
style: overlayStyle,
|
|
1321
|
-
onClick: (e) => {
|
|
1322
|
-
if (e.target === e.currentTarget) onReject();
|
|
1323
|
-
},
|
|
1324
|
-
"aria-hidden": "false",
|
|
1325
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1326
|
-
"div",
|
|
1327
|
-
{
|
|
1328
|
-
ref: dialogRef,
|
|
1329
|
-
style: dialogStyle,
|
|
1330
|
-
role: "alertdialog",
|
|
1331
|
-
"aria-modal": "true",
|
|
1332
|
-
"aria-labelledby": titleId,
|
|
1333
|
-
"aria-describedby": descriptionId,
|
|
1334
|
-
tabIndex: -1,
|
|
1335
|
-
onClick: (e) => e.stopPropagation(),
|
|
1336
|
-
children: [
|
|
1337
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { id: titleId, style: { margin: "0 0 8px", fontSize: 16 }, children: "Confirm Action" }),
|
|
1338
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { margin: "0 0 4px", fontSize: 14, fontWeight: 600 }, children: action }),
|
|
1339
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1340
|
-
"p",
|
|
1341
|
-
{
|
|
1342
|
-
id: descriptionId,
|
|
1343
|
-
style: {
|
|
1344
|
-
margin: "0 0 16px",
|
|
1345
|
-
fontSize: 13,
|
|
1346
|
-
color: "var(--ai-me-text-secondary)"
|
|
1347
|
-
},
|
|
1348
|
-
children: description
|
|
1349
|
-
}
|
|
1350
|
-
),
|
|
1351
|
-
parameters && Object.keys(parameters).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1352
|
-
"pre",
|
|
1353
|
-
{
|
|
1354
|
-
style: {
|
|
1355
|
-
margin: "0 0 16px",
|
|
1356
|
-
padding: 12,
|
|
1357
|
-
backgroundColor: "var(--ai-me-bg-secondary)",
|
|
1358
|
-
borderRadius: 8,
|
|
1359
|
-
fontSize: 12,
|
|
1360
|
-
overflow: "auto",
|
|
1361
|
-
maxHeight: 200,
|
|
1362
|
-
border: "1px solid var(--ai-me-border)"
|
|
1363
|
-
},
|
|
1364
|
-
children: JSON.stringify(parameters, null, 2)
|
|
1365
|
-
}
|
|
1366
|
-
),
|
|
1367
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", gap: 8, justifyContent: "flex-end" }, children: [
|
|
1368
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1369
|
-
"button",
|
|
1370
|
-
{
|
|
1371
|
-
ref: cancelButtonRef,
|
|
1372
|
-
type: "button",
|
|
1373
|
-
onClick: onReject,
|
|
1374
|
-
style: {
|
|
1375
|
-
padding: "8px 16px",
|
|
1376
|
-
border: "1px solid var(--ai-me-border)",
|
|
1377
|
-
borderRadius: 8,
|
|
1378
|
-
backgroundColor: "var(--ai-me-bg)",
|
|
1379
|
-
color: "var(--ai-me-text)",
|
|
1380
|
-
cursor: "pointer",
|
|
1381
|
-
fontSize: 14,
|
|
1382
|
-
...focusStyle
|
|
1383
|
-
},
|
|
1384
|
-
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
1385
|
-
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
1386
|
-
children: "Cancel"
|
|
1387
|
-
}
|
|
1388
|
-
),
|
|
1389
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1390
|
-
"button",
|
|
1391
|
-
{
|
|
1392
|
-
type: "button",
|
|
1393
|
-
onClick: onConfirm,
|
|
1394
|
-
style: {
|
|
1395
|
-
padding: "8px 16px",
|
|
1396
|
-
border: "none",
|
|
1397
|
-
borderRadius: 8,
|
|
1398
|
-
// #fff on var(--ai-me-primary) = #6366f1 → contrast ≈ 4.6:1 (passes AA)
|
|
1399
|
-
backgroundColor: "var(--ai-me-primary)",
|
|
1400
|
-
color: "#fff",
|
|
1401
|
-
cursor: "pointer",
|
|
1402
|
-
fontSize: 14,
|
|
1403
|
-
...focusStyle
|
|
1404
|
-
},
|
|
1405
|
-
onFocus: (e) => applyFocusRing(e.currentTarget),
|
|
1406
|
-
onBlur: (e) => removeFocusRing(e.currentTarget),
|
|
1407
|
-
children: "Confirm"
|
|
1408
|
-
}
|
|
1409
|
-
)
|
|
1410
|
-
] })
|
|
1411
|
-
]
|
|
1412
|
-
}
|
|
1413
|
-
)
|
|
1414
|
-
}
|
|
1415
|
-
)
|
|
1416
|
-
);
|
|
1417
|
-
}
|
|
1418
1513
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1419
1514
|
0 && (module.exports = {
|
|
1420
1515
|
AIMeChat,
|
|
1421
1516
|
AIMeCommandPalette,
|
|
1422
1517
|
AIMeConfirm,
|
|
1423
1518
|
AIMeProvider,
|
|
1519
|
+
cleanAssistantText,
|
|
1424
1520
|
renderMarkdown,
|
|
1425
1521
|
useAIMe,
|
|
1426
1522
|
useAIMeContext
|