@agent-native/core 0.82.0 → 0.83.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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/CommandMenu.tsx +34 -12
- package/corpus/templates/analytics/actions/hubspot-deals.ts +64 -4
- package/corpus/templates/content/.env.local.example +6 -0
- package/corpus/templates/content/AGENTS.md +10 -1
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +14 -1
- package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +43 -0
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +79 -7
- package/corpus/templates/content/actions/_database-source-utils.ts +987 -22
- package/corpus/templates/content/actions/_database-utils.ts +41 -0
- package/corpus/templates/content/actions/_local-file-documents.ts +74 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +33 -8
- package/corpus/templates/content/actions/change-content-database-source-role.ts +14 -0
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +3 -0
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +71 -3
- package/corpus/templates/content/actions/list-content-databases.ts +41 -33
- package/corpus/templates/content/actions/process-builder-body-hydration.ts +47 -0
- package/corpus/templates/content/actions/update-document.ts +93 -0
- package/corpus/templates/content/app/blocks/SourceComponentBlock.tsx +277 -0
- package/corpus/templates/content/app/blocks/contentBlockRegistry.tsx +2 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +45 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +5 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +92 -0
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +5 -3
- package/corpus/templates/content/app/components/editor/extensions/registryBlocks.ts +41 -0
- package/corpus/templates/content/app/components/editor/registrySlashItems.ts +4 -0
- package/corpus/templates/content/app/global.css +10 -3
- package/corpus/templates/content/app/hooks/use-content-database.ts +24 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +24 -0
- package/corpus/templates/content/app/i18n-data.ts +212 -0
- package/corpus/templates/content/app/lib/content-command-search.ts +64 -0
- package/corpus/templates/content/app/root.tsx +236 -8
- package/corpus/templates/content/changelog/2026-06-29-builder-cms-sources-now-sync-article-bodies-through-content.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-builder-article-media-now-render-as-images-and-embeds-when-r.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-builder-source-components-now-render-as-preserved-preview-bl.md +6 -0
- package/corpus/templates/content/changelog/2026-06-30-cmd-k-search-now-opens-from-the-editor-and-finds-real-content.md +6 -0
- package/corpus/templates/content/package.json +3 -1
- package/corpus/templates/content/scripts/check-native-deps.mjs +57 -0
- package/corpus/templates/content/scripts/dev-database.mjs +83 -0
- package/corpus/templates/content/scripts/seed-demo-user.mjs +107 -0
- package/corpus/templates/content/server/db/schema.ts +27 -0
- package/corpus/templates/content/server/plugins/db.ts +33 -0
- package/corpus/templates/content/shared/api.ts +45 -0
- package/corpus/templates/content/shared/builder-mdx.ts +905 -5
- package/corpus/templates/content/shared/nfm-registry.ts +2 -0
- package/corpus/templates/content/shared/source-component-block.ts +141 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +5 -1
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +229 -131
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +103 -6
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +6 -3
- package/corpus/templates/design/app/pages/DesignEditor.tsx +382 -72
- package/corpus/templates/design/changelog/2026-06-30-canvas-editing-now-keeps-undo-redo-and-cross-screen-layer-mo.md +6 -0
- package/dist/client/CommandMenu.d.ts +6 -2
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +25 -14
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +8 -8
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/package.json +1 -1
|
@@ -63,6 +63,8 @@ export interface CommandMenuProps {
|
|
|
63
63
|
open: boolean;
|
|
64
64
|
onOpenChange: (open: boolean) => void;
|
|
65
65
|
children: ReactNode;
|
|
66
|
+
/** Render app-specific dynamic results from the current search value. */
|
|
67
|
+
renderResults?: (search: string) => ReactNode;
|
|
66
68
|
/** Placeholder text for the search input */
|
|
67
69
|
placeholder?: string;
|
|
68
70
|
/** Text shown when no results match (before showing agent fallback) */
|
|
@@ -88,7 +90,7 @@ export interface CommandMenuProps {
|
|
|
88
90
|
*/
|
|
89
91
|
changelogKey?: string;
|
|
90
92
|
}
|
|
91
|
-
export declare function CommandMenu({ open, onOpenChange, children, placeholder, emptyText: _emptyText, showAgentFallback, className, changelog, changelogLabel, changelogKey, }: CommandMenuProps): React.JSX.Element;
|
|
93
|
+
export declare function CommandMenu({ open, onOpenChange, children, renderResults, placeholder, emptyText: _emptyText, showAgentFallback, className, changelog, changelogLabel, changelogKey, }: CommandMenuProps): React.JSX.Element;
|
|
92
94
|
export declare namespace CommandMenu {
|
|
93
95
|
export { CommandGroup as Group };
|
|
94
96
|
export { CommandItem as Item };
|
|
@@ -99,6 +101,8 @@ export declare namespace CommandMenu {
|
|
|
99
101
|
/**
|
|
100
102
|
* Hook to handle Cmd+K (or Ctrl+K) to open the command menu
|
|
101
103
|
*/
|
|
102
|
-
export declare function useCommandMenuShortcut(onOpen: () => void
|
|
104
|
+
export declare function useCommandMenuShortcut(onOpen: () => void, options?: {
|
|
105
|
+
allowContentEditable?: boolean;
|
|
106
|
+
}): void;
|
|
103
107
|
export type { CommandDocsGroupProps, CommandGroupProps, CommandItemProps, CommandShortcutProps, };
|
|
104
108
|
//# sourceMappingURL=CommandMenu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandMenu.d.ts","sourceRoot":"","sources":["../../src/client/CommandMenu.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,KAAK,EAAE,EAQZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA0Bf;;GAEG;AACH,wBAAgB,gBAAgB,SAE/B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,MAAM,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,QAa/C;AAED,wBAAgB,cAAc,SAO7B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,QAG5C;AAID,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,iBAAS,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,iBAAiB,qBAW7D;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,iBAAS,WAAW,CAAC,EACnB,QAAQ,EACR,QAAQ,EACR,QAAQ,EAAE,SAAS,EACnB,SAAS,EACT,WAAkB,GACnB,EAAE,gBAAgB,qBAsClB;AAED,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iBAAS,eAAe,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,oBAAoB,qBAWrE;AAED,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAE9D;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuBD,iBAAS,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE,EAAE,qBAAqB,4BA2B1E;AAID,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,WAA2C,EAC3C,SAAS,EAAE,UAAiC,EAC5C,iBAAwB,EACxB,SAAS,EACT,SAAS,EACT,cAA6B,EAC7B,YAAY,GACb,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"CommandMenu.d.ts","sourceRoot":"","sources":["../../src/client/CommandMenu.tsx"],"names":[],"mappings":"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"}
|
|
@@ -113,7 +113,7 @@ function CommandDocsGroup({ docs, heading = "Docs" }) {
|
|
|
113
113
|
return null;
|
|
114
114
|
return (_jsx(CommandGroup, { heading: heading, children: docs.map((doc) => (_jsxs(CommandItem, { onSelect: () => openDocsHref(doc.href), keywords: [doc.title, doc.description ?? "", ...(doc.keywords ?? [])], deferSelect: false, className: "items-start py-2", children: [_jsx(IconBook2, { className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-medium", children: doc.title }), doc.description ? (_jsx("span", { className: "mt-0.5 block line-clamp-2 text-xs leading-snug text-muted-foreground", children: doc.description })) : null] }), _jsx(IconExternalLink, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" })] }, doc.href))) }));
|
|
115
115
|
}
|
|
116
|
-
export function CommandMenu({ open, onOpenChange, children, placeholder = "Type a command or ask AI...", emptyText: _emptyText = "No commands found.", showAgentFallback = true, className, changelog, changelogLabel = "What's new", changelogKey, }) {
|
|
116
|
+
export function CommandMenu({ open, onOpenChange, children, renderResults, placeholder = "Type a command or ask AI...", emptyText: _emptyText = "No commands found.", showAgentFallback = true, className, changelog, changelogLabel = "What's new", changelogKey, }) {
|
|
117
117
|
const [search, setSearch] = useState("");
|
|
118
118
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
119
119
|
const inputRef = useRef(null);
|
|
@@ -132,8 +132,14 @@ export function CommandMenu({ open, onOpenChange, children, placeholder = "Type
|
|
|
132
132
|
// Let the menu close before the dialog opens (avoids overlay flicker).
|
|
133
133
|
setTimeout(() => setChangelogOpen(true), 50);
|
|
134
134
|
}, [onOpenChange, markChangelogSeen]);
|
|
135
|
-
// Focus input when opening
|
|
135
|
+
// Focus input when opening; clear search while closed so reopen never renders
|
|
136
|
+
// dynamic results for the previous query.
|
|
136
137
|
useEffect(() => {
|
|
138
|
+
if (!open) {
|
|
139
|
+
setSearch("");
|
|
140
|
+
setSelectedIndex(0);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
137
143
|
if (open) {
|
|
138
144
|
setSearch("");
|
|
139
145
|
setSelectedIndex(0);
|
|
@@ -292,14 +298,16 @@ export function CommandMenu({ open, onOpenChange, children, placeholder = "Type
|
|
|
292
298
|
const filteredChildren = filterChildren(children);
|
|
293
299
|
const hasResults = React.Children.toArray(filteredChildren).some((child) => React.isValidElement(child) &&
|
|
294
300
|
(child.type === CommandGroup || child.type === CommandDocsGroup));
|
|
295
|
-
|
|
301
|
+
const dynamicResults = open ? renderResults?.(search) : null;
|
|
302
|
+
const hasDynamicResults = Boolean(dynamicResults);
|
|
303
|
+
return (_jsxs(_Fragment, { children: [open && (_jsx("div", { className: "fixed inset-0 z-50 bg-black/50", children: _jsx("div", { ref: containerRef, className: cn("fixed left-1/2 top-[15vh] -translate-x-1/2 w-full max-w-lg", "rounded-lg border border-border bg-popover text-popover-foreground shadow-lg", className), children: _jsxs(CommandMenuContext.Provider, { value: { search, onOpenChange, containerRef, setSelectedIndex }, children: [_jsxs("div", { className: "flex items-center border-b px-3", children: [_jsx(IconSearch, { className: "me-2 h-4 w-4 shrink-0 opacity-50" }), _jsx("input", { ref: inputRef, value: search, onChange: (e) => setSearch(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, className: "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" })] }), _jsxs("div", { className: "max-h-[300px] overflow-y-auto overflow-x-hidden", children: [dynamicResults, hasResults && filteredChildren, showChangelogRow && (_jsxs(_Fragment, { children: [hasResults && _jsx(CommandSeparator, {}), _jsx("div", { className: "p-1", children: _jsxs("div", { className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none", onClick: openChangelog, onMouseEnter: (e) => {
|
|
296
304
|
const items = containerRef.current?.querySelectorAll('[role="option"]');
|
|
297
305
|
if (!items)
|
|
298
306
|
return;
|
|
299
307
|
const index = Array.from(items).indexOf(e.currentTarget);
|
|
300
308
|
if (index >= 0)
|
|
301
309
|
setSelectedIndex(index);
|
|
302
|
-
}, role: "option", children: [_jsx(IconHistory, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: changelogLabel }), changelogUnseen && (_jsx("span", { className: "ms-auto h-2 w-2 rounded-full bg-primary", "aria-label": "New updates available" }))] }) })] })), showAgentFallback && (_jsxs(_Fragment, { children: [(hasResults || showChangelogRow) && _jsx(CommandSeparator, {}), _jsx("div", { className: "p-1", children: _jsxs("div", { className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none", onClick: handleSubmitToAgent, onMouseEnter: (e) => {
|
|
310
|
+
}, role: "option", children: [_jsx(IconHistory, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: changelogLabel }), changelogUnseen && (_jsx("span", { className: "ms-auto h-2 w-2 rounded-full bg-primary", "aria-label": "New updates available" }))] }) })] })), showAgentFallback && (_jsxs(_Fragment, { children: [(hasResults || showChangelogRow || hasDynamicResults) && (_jsx(CommandSeparator, {})), _jsx("div", { className: "p-1", children: _jsxs("div", { className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none", onClick: handleSubmitToAgent, onMouseEnter: (e) => {
|
|
303
311
|
const items = containerRef.current?.querySelectorAll('[role="option"]');
|
|
304
312
|
if (!items)
|
|
305
313
|
return;
|
|
@@ -335,23 +343,26 @@ CommandMenu.Separator = CommandSeparator;
|
|
|
335
343
|
/**
|
|
336
344
|
* Hook to handle Cmd+K (or Ctrl+K) to open the command menu
|
|
337
345
|
*/
|
|
338
|
-
export function useCommandMenuShortcut(onOpen) {
|
|
346
|
+
export function useCommandMenuShortcut(onOpen, options = {}) {
|
|
339
347
|
useEffect(() => {
|
|
340
348
|
const handleKeyDown = (e) => {
|
|
341
|
-
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
342
|
-
// Don't trigger if user is typing in
|
|
343
|
-
const target = e.target;
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
target
|
|
349
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
|
|
350
|
+
// Don't trigger if user is typing in a native form control.
|
|
351
|
+
const target = e.target instanceof HTMLElement ? e.target : null;
|
|
352
|
+
const isContentEditable = target?.isContentEditable;
|
|
353
|
+
if (target?.tagName === "INPUT" ||
|
|
354
|
+
target?.tagName === "TEXTAREA" ||
|
|
355
|
+
target?.tagName === "SELECT" ||
|
|
356
|
+
(!options.allowContentEditable && isContentEditable)) {
|
|
347
357
|
return;
|
|
348
358
|
}
|
|
349
359
|
e.preventDefault();
|
|
350
360
|
onOpen();
|
|
351
361
|
}
|
|
352
362
|
};
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
363
|
+
const useCapture = Boolean(options.allowContentEditable);
|
|
364
|
+
document.addEventListener("keydown", handleKeyDown, useCapture);
|
|
365
|
+
return () => document.removeEventListener("keydown", handleKeyDown, useCapture);
|
|
366
|
+
}, [onOpen, options.allowContentEditable]);
|
|
356
367
|
}
|
|
357
368
|
//# sourceMappingURL=CommandMenu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandMenu.js","sourceRoot":"","sources":["../../src/client/CommandMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * CommandMenu — reusable command palette with agent chat fallback.\n *\n * Features:\n * - Anchored to top of viewport (not centered)\n * - Falls back to agent chat when no command matches\n * - Opens agent sidebar automatically when sending prompts\n * - Customizable commands via children\n *\n * Usage:\n * <CommandMenu open={open} onOpenChange={setOpen}>\n * <CommandMenu.Group heading=\"Actions\">\n * <CommandMenu.Item onSelect={() => doThing()}>Do thing</CommandMenu.Item>\n * </CommandMenu.Group>\n * </CommandMenu>\n */\n\nimport {\n IconBook2,\n IconExternalLink,\n IconSearch,\n IconMessage,\n IconHistory,\n} from \"@tabler/icons-react\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\n\nimport { parseChangelog } from \"../changelog/parse.js\";\nimport { sendToAgentChat } from \"./agent-chat.js\";\nimport { ChangelogDialog, useChangelogSeen } from \"./changelog/Changelog.js\";\nimport { cn } from \"./utils.js\";\n\n// ─── Context ────────────────────────────────────────────────────────────────\n\ninterface CommandMenuContextValue {\n search: string;\n onOpenChange: (open: boolean) => void;\n containerRef: React.RefObject<HTMLDivElement | null>;\n setSelectedIndex: (index: number) => void;\n}\n\nconst CommandMenuContext = createContext<CommandMenuContextValue | null>(null);\n\nfunction useCommandMenuContext() {\n const ctx = useContext(CommandMenuContext);\n if (!ctx) throw new Error(\"CommandMenu.* must be used inside <CommandMenu>\");\n return ctx;\n}\n\n// ─── Hooks ──────────────────────────────────────────────────────────────────\n\n/**\n * Opens the agent sidebar (dispatches event that AgentSidebar listens for)\n */\nexport function openAgentSidebar() {\n window.dispatchEvent(new Event(\"agent-panel:open\"));\n}\n\nexport function openAgentSettings(\n section?: string | { section?: string | null },\n) {\n if (typeof window === \"undefined\") return;\n\n const normalizedSection =\n typeof section === \"string\" ? section : section?.section;\n\n openAgentSidebar();\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:open-settings\", {\n detail: normalizedSection ? { section: normalizedSection } : undefined,\n }),\n );\n}\n\nexport function focusAgentChat() {\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:set-mode\", {\n detail: { mode: \"chat\" },\n }),\n );\n openAgentSidebar();\n}\n\n/**\n * Sends a prompt to the agent and opens the sidebar\n */\nexport function submitToAgent(message: string) {\n focusAgentChat();\n sendToAgentChat({ message, submit: true });\n}\n\n// ─── Sub-components ─────────────────────────────────────────────────────────\n\ninterface CommandGroupProps {\n heading?: string;\n children: ReactNode;\n}\n\nfunction CommandGroup({ heading, children }: CommandGroupProps) {\n return (\n <div className=\"overflow-hidden p-1 text-foreground\">\n {heading && (\n <div className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {heading}\n </div>\n )}\n {children}\n </div>\n );\n}\n\ninterface CommandItemProps {\n onSelect: () => void;\n children: ReactNode;\n keywords?: string[];\n className?: string;\n deferSelect?: boolean;\n}\n\nfunction CommandItem({\n onSelect,\n children,\n keywords: _keywords,\n className,\n deferSelect = true,\n}: CommandItemProps) {\n const { onOpenChange, containerRef, setSelectedIndex } =\n useCommandMenuContext();\n const itemRef = useRef<HTMLDivElement>(null);\n\n const handleSelect = () => {\n if (!deferSelect) {\n onSelect();\n onOpenChange(false);\n return;\n }\n\n onOpenChange(false);\n // Small delay to let dialog close animation start\n setTimeout(onSelect, 50);\n };\n\n const handleMouseEnter = () => {\n if (!containerRef.current || !itemRef.current) return;\n const items = containerRef.current.querySelectorAll('[role=\"option\"]');\n const index = Array.from(items).indexOf(itemRef.current);\n if (index >= 0) setSelectedIndex(index);\n };\n\n return (\n <div\n ref={itemRef}\n className={cn(\n \"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none\",\n className,\n )}\n onClick={handleSelect}\n onMouseEnter={handleMouseEnter}\n role=\"option\"\n >\n {children}\n </div>\n );\n}\n\ninterface CommandShortcutProps {\n children: ReactNode;\n className?: string;\n}\n\nfunction CommandShortcut({ children, className }: CommandShortcutProps) {\n return (\n <span\n className={cn(\n \"ms-auto text-xs tracking-widest text-muted-foreground\",\n className,\n )}\n >\n {children}\n </span>\n );\n}\n\nfunction CommandSeparator({ className }: { className?: string }) {\n return <div className={cn(\"-mx-1 my-1 h-px bg-border\", className)} />;\n}\n\nexport interface CommandMenuDoc {\n title: string;\n href: string;\n description?: string;\n keywords?: string[];\n}\n\ninterface CommandDocsGroupProps {\n docs: CommandMenuDoc[];\n heading?: string;\n}\n\nfunction commandDocSearchText(doc: CommandMenuDoc): string {\n return [doc.title, doc.description, ...(doc.keywords ?? [])]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n}\n\nfunction filterCommandDocs(docs: CommandMenuDoc[], search: string) {\n const searchLower = search.trim().toLowerCase();\n if (!searchLower) return docs;\n return docs.filter((doc) => commandDocSearchText(doc).includes(searchLower));\n}\n\nfunction openDocsHref(href: string) {\n if (/^https?:\\/\\//i.test(href)) {\n window.open(href, \"_blank\", \"noopener,noreferrer\");\n return;\n }\n window.location.assign(href);\n}\n\nfunction CommandDocsGroup({ docs, heading = \"Docs\" }: CommandDocsGroupProps) {\n if (docs.length === 0) return null;\n\n return (\n <CommandGroup heading={heading}>\n {docs.map((doc) => (\n <CommandItem\n key={doc.href}\n onSelect={() => openDocsHref(doc.href)}\n keywords={[doc.title, doc.description ?? \"\", ...(doc.keywords ?? [])]}\n deferSelect={false}\n className=\"items-start py-2\"\n >\n <IconBook2 className=\"mt-0.5 h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate font-medium\">{doc.title}</span>\n {doc.description ? (\n <span className=\"mt-0.5 block line-clamp-2 text-xs leading-snug text-muted-foreground\">\n {doc.description}\n </span>\n ) : null}\n </span>\n <IconExternalLink className=\"mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n </CommandItem>\n ))}\n </CommandGroup>\n );\n}\n\n// ─── Main Component ─────────────────────────────────────────────────────────\n\nexport interface CommandMenuProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n children: ReactNode;\n /** Placeholder text for the search input */\n placeholder?: string;\n /** Text shown when no results match (before showing agent fallback) */\n emptyText?: string;\n /** Whether to show the \"Ask AI\" fallback when no commands match. Default: true */\n showAgentFallback?: boolean;\n /** Custom class for the dialog content */\n className?: string;\n /**\n * Raw CHANGELOG.md contents. When provided, the menu shows a built-in\n * \"What's new\" entry that opens an in-app changelog dialog (with an unseen\n * dot for new releases). Pass your app's own file:\n * import changelog from \"../CHANGELOG.md?raw\";\n * <CommandMenu ... changelog={changelog} />\n */\n changelog?: string;\n /** Label for the built-in changelog entry. Default: \"What's new\". */\n changelogLabel?: string;\n /**\n * Stable key used to remember which release a user has already seen (for the\n * unseen dot). Defaults to the document title's host app; set explicitly when\n * multiple apps share an origin.\n */\n changelogKey?: string;\n}\n\nexport function CommandMenu({\n open,\n onOpenChange,\n children,\n placeholder = \"Type a command or ask AI...\",\n emptyText: _emptyText = \"No commands found.\",\n showAgentFallback = true,\n className,\n changelog,\n changelogLabel = \"What's new\",\n changelogKey,\n}: CommandMenuProps) {\n const [search, setSearch] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Built-in \"What's new\" changelog surface (only active when `changelog` is\n // passed). The dialog is rendered alongside the menu so it survives the menu\n // closing; the unseen dot persists per browser via localStorage.\n const [changelogOpen, setChangelogOpen] = useState(false);\n const hasChangelog =\n typeof changelog === \"string\" && changelog.trim().length > 0;\n const changelogEntries = useMemo(\n () => (hasChangelog ? parseChangelog(changelog as string) : []),\n [hasChangelog, changelog],\n );\n const latestChangelogId = changelogEntries[0]?.id;\n const { unseen: changelogUnseen, markSeen: markChangelogSeen } =\n useChangelogSeen(changelogKey ?? \"app\", latestChangelogId);\n\n const openChangelog = useCallback(() => {\n onOpenChange(false);\n markChangelogSeen();\n // Let the menu close before the dialog opens (avoids overlay flicker).\n setTimeout(() => setChangelogOpen(true), 50);\n }, [onOpenChange, markChangelogSeen]);\n\n // Focus input when opening\n useEffect(() => {\n if (open) {\n setSearch(\"\");\n setSelectedIndex(0);\n // Wait for render then focus\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n }\n }, [open]);\n\n // Reset selection when search changes\n useEffect(() => {\n setSelectedIndex(0);\n }, [search]);\n\n // Keep selected item scrolled into view\n useEffect(() => {\n const items = containerRef.current?.querySelectorAll('[role=\"option\"]');\n if (items && items[selectedIndex]) {\n items[selectedIndex].scrollIntoView({ block: \"nearest\" });\n }\n }, [selectedIndex]);\n\n // Apply selected styling directly (can't rely on Tailwind scanning core package)\n useEffect(() => {\n const items = containerRef.current?.querySelectorAll('[role=\"option\"]');\n if (!items) return;\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n if (i === selectedIndex) {\n el.style.backgroundColor = \"hsl(var(--accent))\";\n el.style.color = \"hsl(var(--accent-foreground))\";\n } else {\n el.style.backgroundColor = \"\";\n el.style.color = \"\";\n }\n });\n });\n\n // Close on escape\n useEffect(() => {\n if (!open) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onOpenChange(false);\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, onOpenChange]);\n\n // Close on click outside\n useEffect(() => {\n if (!open) return;\n const handleClick = (e: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n onOpenChange(false);\n }\n };\n // Use capture to handle clicks before they bubble\n document.addEventListener(\"mousedown\", handleClick, true);\n return () => document.removeEventListener(\"mousedown\", handleClick, true);\n }, [open, onOpenChange]);\n\n const handleSubmitToAgent = useCallback(() => {\n onOpenChange(false);\n if (!search.trim()) {\n focusAgentChat();\n return;\n }\n submitToAgent(search.trim());\n }, [search, onOpenChange]);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n const items = containerRef.current?.querySelectorAll('[role=\"option\"]');\n const itemCount = items?.length ?? 0;\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setSelectedIndex((prev) => (prev + 1) % itemCount || 0);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setSelectedIndex((prev) => (prev - 1 + itemCount) % itemCount || 0);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (items && items[selectedIndex]) {\n (items[selectedIndex] as HTMLElement).click();\n }\n }\n };\n\n // The built-in \"What's new\" row matches changelog-ish search terms.\n const changelogRowMatches =\n !search ||\n [\n changelogLabel,\n \"changelog\",\n \"what's new\",\n \"whats new\",\n \"updates\",\n \"release notes\",\n \"changes\",\n ]\n .join(\" \")\n .toLowerCase()\n .includes(search.toLowerCase());\n const showChangelogRow = hasChangelog && changelogRowMatches;\n\n // Filter children based on search\n const filterChildren = (nodes: ReactNode): ReactNode => {\n return React.Children.map(nodes, (child) => {\n if (!React.isValidElement(child)) return child;\n const props = child.props as Record<string, unknown>;\n\n // If it's a CommandGroup, filter its children\n if (child.type === CommandGroup) {\n const groupChildren = filterChildren(props.children as ReactNode);\n const hasChildren = React.Children.count(groupChildren) > 0;\n if (!hasChildren) return null;\n return React.cloneElement(child, {\n ...props,\n children: groupChildren,\n } as Record<string, unknown>);\n }\n\n if (child.type === CommandDocsGroup) {\n const docs = Array.isArray(props.docs)\n ? (props.docs as CommandMenuDoc[])\n : [];\n const filteredDocs = filterCommandDocs(docs, search);\n if (filteredDocs.length === 0) return null;\n return React.cloneElement(child, {\n ...props,\n docs: filteredDocs,\n } as Record<string, unknown>);\n }\n\n // If it's a CommandItem, check if it matches search\n if (child.type === CommandItem) {\n if (!search) return child;\n const text = getTextContent(props.children as ReactNode).toLowerCase();\n const keywords = ((props.keywords as string[]) || [])\n .join(\" \")\n .toLowerCase();\n const searchLower = search.toLowerCase();\n if (text.includes(searchLower) || keywords.includes(searchLower)) {\n return child;\n }\n return null;\n }\n\n // If it's a separator, keep it (will be cleaned up later if needed)\n if (child.type === CommandSeparator) {\n return search ? null : child; // Hide separators when searching\n }\n\n return child;\n });\n };\n\n const filteredChildren = filterChildren(children);\n const hasResults = React.Children.toArray(filteredChildren).some(\n (child) =>\n React.isValidElement(child) &&\n (child.type === CommandGroup || child.type === CommandDocsGroup),\n );\n\n return (\n <>\n {open && (\n <div className=\"fixed inset-0 z-50 bg-black/50\">\n <div\n ref={containerRef}\n className={cn(\n \"fixed left-1/2 top-[15vh] -translate-x-1/2 w-full max-w-lg\",\n \"rounded-lg border border-border bg-popover text-popover-foreground shadow-lg\",\n className,\n )}\n >\n <CommandMenuContext.Provider\n value={{ search, onOpenChange, containerRef, setSelectedIndex }}\n >\n {/* Search input */}\n <div className=\"flex items-center border-b px-3\">\n <IconSearch className=\"me-2 h-4 w-4 shrink-0 opacity-50\" />\n <input\n ref={inputRef}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n className=\"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n\n {/* Command list */}\n <div className=\"max-h-[300px] overflow-y-auto overflow-x-hidden\">\n {hasResults && filteredChildren}\n\n {/* What's new — built-in changelog entry */}\n {showChangelogRow && (\n <>\n {hasResults && <CommandSeparator />}\n <div className=\"p-1\">\n <div\n className=\"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none\"\n onClick={openChangelog}\n onMouseEnter={(e) => {\n const items =\n containerRef.current?.querySelectorAll(\n '[role=\"option\"]',\n );\n if (!items) return;\n const index = Array.from(items).indexOf(\n e.currentTarget,\n );\n if (index >= 0) setSelectedIndex(index);\n }}\n role=\"option\"\n >\n <IconHistory className=\"h-4 w-4 text-muted-foreground\" />\n <span>{changelogLabel}</span>\n {changelogUnseen && (\n <span\n className=\"ms-auto h-2 w-2 rounded-full bg-primary\"\n aria-label=\"New updates available\"\n />\n )}\n </div>\n </div>\n </>\n )}\n\n {/* Ask AI — always visible at the bottom */}\n {showAgentFallback && (\n <>\n {(hasResults || showChangelogRow) && <CommandSeparator />}\n <div className=\"p-1\">\n <div\n className=\"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none\"\n onClick={handleSubmitToAgent}\n onMouseEnter={(e) => {\n const items =\n containerRef.current?.querySelectorAll(\n '[role=\"option\"]',\n );\n if (!items) return;\n const index = Array.from(items).indexOf(\n e.currentTarget,\n );\n if (index >= 0) setSelectedIndex(index);\n }}\n role=\"option\"\n >\n <IconMessage className=\"h-4 w-4 text-muted-foreground\" />\n <span>\n {search.trim() ? (\n <>\n Ask AI:{\" \"}\n <span className=\"text-muted-foreground\">\n \"{search}\"\n </span>\n </>\n ) : (\n <span className=\"text-muted-foreground\">\n Ask AI anything...\n </span>\n )}\n </span>\n {search.trim() && (\n <span className=\"ms-auto text-xs text-muted-foreground\">\n ↵\n </span>\n )}\n </div>\n </div>\n </>\n )}\n </div>\n </CommandMenuContext.Provider>\n </div>\n </div>\n )}\n\n {hasChangelog && (\n <ChangelogDialog\n open={changelogOpen}\n onOpenChange={setChangelogOpen}\n markdown={changelog as string}\n title={changelogLabel}\n />\n )}\n </>\n );\n}\n\n// Helper to extract text content from React children\nfunction getTextContent(children: ReactNode): string {\n if (typeof children === \"string\") return children;\n if (typeof children === \"number\") return String(children);\n if (!children) return \"\";\n if (Array.isArray(children)) {\n return children.map(getTextContent).join(\" \");\n }\n if (\n React.isValidElement(children) &&\n (children.props as Record<string, unknown>).children\n ) {\n return getTextContent(\n (children.props as Record<string, unknown>).children as ReactNode,\n );\n }\n return \"\";\n}\n\n// Attach sub-components\nCommandMenu.Group = CommandGroup;\nCommandMenu.Item = CommandItem;\nCommandMenu.DocsGroup = CommandDocsGroup;\nCommandMenu.Shortcut = CommandShortcut;\nCommandMenu.Separator = CommandSeparator;\n\n// ─── Keyboard Hook ──────────────────────────────────────────────────────────\n\n/**\n * Hook to handle Cmd+K (or Ctrl+K) to open the command menu\n */\nexport function useCommandMenuShortcut(onOpen: () => void) {\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"k\") {\n // Don't trigger if user is typing in an input/textarea\n const target = e.target as HTMLElement;\n if (\n target.tagName === \"INPUT\" ||\n target.tagName === \"TEXTAREA\" ||\n target.isContentEditable\n ) {\n return;\n }\n e.preventDefault();\n onOpen();\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [onOpen]);\n}\n\nexport type {\n CommandDocsGroupProps,\n CommandGroupProps,\n CommandItemProps,\n CommandShortcutProps,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"CommandMenu.js","sourceRoot":"","sources":["../../src/client/CommandMenu.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * CommandMenu — reusable command palette with agent chat fallback.\n *\n * Features:\n * - Anchored to top of viewport (not centered)\n * - Falls back to agent chat when no command matches\n * - Opens agent sidebar automatically when sending prompts\n * - Customizable commands via children\n *\n * Usage:\n * <CommandMenu open={open} onOpenChange={setOpen}>\n * <CommandMenu.Group heading=\"Actions\">\n * <CommandMenu.Item onSelect={() => doThing()}>Do thing</CommandMenu.Item>\n * </CommandMenu.Group>\n * </CommandMenu>\n */\n\nimport {\n IconBook2,\n IconExternalLink,\n IconSearch,\n IconMessage,\n IconHistory,\n} from \"@tabler/icons-react\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\n\nimport { parseChangelog } from \"../changelog/parse.js\";\nimport { sendToAgentChat } from \"./agent-chat.js\";\nimport { ChangelogDialog, useChangelogSeen } from \"./changelog/Changelog.js\";\nimport { cn } from \"./utils.js\";\n\n// ─── Context ────────────────────────────────────────────────────────────────\n\ninterface CommandMenuContextValue {\n search: string;\n onOpenChange: (open: boolean) => void;\n containerRef: React.RefObject<HTMLDivElement | null>;\n setSelectedIndex: (index: number) => void;\n}\n\nconst CommandMenuContext = createContext<CommandMenuContextValue | null>(null);\n\nfunction useCommandMenuContext() {\n const ctx = useContext(CommandMenuContext);\n if (!ctx) throw new Error(\"CommandMenu.* must be used inside <CommandMenu>\");\n return ctx;\n}\n\n// ─── Hooks ──────────────────────────────────────────────────────────────────\n\n/**\n * Opens the agent sidebar (dispatches event that AgentSidebar listens for)\n */\nexport function openAgentSidebar() {\n window.dispatchEvent(new Event(\"agent-panel:open\"));\n}\n\nexport function openAgentSettings(\n section?: string | { section?: string | null },\n) {\n if (typeof window === \"undefined\") return;\n\n const normalizedSection =\n typeof section === \"string\" ? section : section?.section;\n\n openAgentSidebar();\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:open-settings\", {\n detail: normalizedSection ? { section: normalizedSection } : undefined,\n }),\n );\n}\n\nexport function focusAgentChat() {\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:set-mode\", {\n detail: { mode: \"chat\" },\n }),\n );\n openAgentSidebar();\n}\n\n/**\n * Sends a prompt to the agent and opens the sidebar\n */\nexport function submitToAgent(message: string) {\n focusAgentChat();\n sendToAgentChat({ message, submit: true });\n}\n\n// ─── Sub-components ─────────────────────────────────────────────────────────\n\ninterface CommandGroupProps {\n heading?: string;\n children: ReactNode;\n}\n\nfunction CommandGroup({ heading, children }: CommandGroupProps) {\n return (\n <div className=\"overflow-hidden p-1 text-foreground\">\n {heading && (\n <div className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {heading}\n </div>\n )}\n {children}\n </div>\n );\n}\n\ninterface CommandItemProps {\n onSelect: () => void;\n children: ReactNode;\n keywords?: string[];\n className?: string;\n deferSelect?: boolean;\n}\n\nfunction CommandItem({\n onSelect,\n children,\n keywords: _keywords,\n className,\n deferSelect = true,\n}: CommandItemProps) {\n const { onOpenChange, containerRef, setSelectedIndex } =\n useCommandMenuContext();\n const itemRef = useRef<HTMLDivElement>(null);\n\n const handleSelect = () => {\n if (!deferSelect) {\n onSelect();\n onOpenChange(false);\n return;\n }\n\n onOpenChange(false);\n // Small delay to let dialog close animation start\n setTimeout(onSelect, 50);\n };\n\n const handleMouseEnter = () => {\n if (!containerRef.current || !itemRef.current) return;\n const items = containerRef.current.querySelectorAll('[role=\"option\"]');\n const index = Array.from(items).indexOf(itemRef.current);\n if (index >= 0) setSelectedIndex(index);\n };\n\n return (\n <div\n ref={itemRef}\n className={cn(\n \"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none\",\n className,\n )}\n onClick={handleSelect}\n onMouseEnter={handleMouseEnter}\n role=\"option\"\n >\n {children}\n </div>\n );\n}\n\ninterface CommandShortcutProps {\n children: ReactNode;\n className?: string;\n}\n\nfunction CommandShortcut({ children, className }: CommandShortcutProps) {\n return (\n <span\n className={cn(\n \"ms-auto text-xs tracking-widest text-muted-foreground\",\n className,\n )}\n >\n {children}\n </span>\n );\n}\n\nfunction CommandSeparator({ className }: { className?: string }) {\n return <div className={cn(\"-mx-1 my-1 h-px bg-border\", className)} />;\n}\n\nexport interface CommandMenuDoc {\n title: string;\n href: string;\n description?: string;\n keywords?: string[];\n}\n\ninterface CommandDocsGroupProps {\n docs: CommandMenuDoc[];\n heading?: string;\n}\n\nfunction commandDocSearchText(doc: CommandMenuDoc): string {\n return [doc.title, doc.description, ...(doc.keywords ?? [])]\n .filter(Boolean)\n .join(\" \")\n .toLowerCase();\n}\n\nfunction filterCommandDocs(docs: CommandMenuDoc[], search: string) {\n const searchLower = search.trim().toLowerCase();\n if (!searchLower) return docs;\n return docs.filter((doc) => commandDocSearchText(doc).includes(searchLower));\n}\n\nfunction openDocsHref(href: string) {\n if (/^https?:\\/\\//i.test(href)) {\n window.open(href, \"_blank\", \"noopener,noreferrer\");\n return;\n }\n window.location.assign(href);\n}\n\nfunction CommandDocsGroup({ docs, heading = \"Docs\" }: CommandDocsGroupProps) {\n if (docs.length === 0) return null;\n\n return (\n <CommandGroup heading={heading}>\n {docs.map((doc) => (\n <CommandItem\n key={doc.href}\n onSelect={() => openDocsHref(doc.href)}\n keywords={[doc.title, doc.description ?? \"\", ...(doc.keywords ?? [])]}\n deferSelect={false}\n className=\"items-start py-2\"\n >\n <IconBook2 className=\"mt-0.5 h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate font-medium\">{doc.title}</span>\n {doc.description ? (\n <span className=\"mt-0.5 block line-clamp-2 text-xs leading-snug text-muted-foreground\">\n {doc.description}\n </span>\n ) : null}\n </span>\n <IconExternalLink className=\"mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n </CommandItem>\n ))}\n </CommandGroup>\n );\n}\n\n// ─── Main Component ─────────────────────────────────────────────────────────\n\nexport interface CommandMenuProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n children: ReactNode;\n /** Render app-specific dynamic results from the current search value. */\n renderResults?: (search: string) => ReactNode;\n /** Placeholder text for the search input */\n placeholder?: string;\n /** Text shown when no results match (before showing agent fallback) */\n emptyText?: string;\n /** Whether to show the \"Ask AI\" fallback when no commands match. Default: true */\n showAgentFallback?: boolean;\n /** Custom class for the dialog content */\n className?: string;\n /**\n * Raw CHANGELOG.md contents. When provided, the menu shows a built-in\n * \"What's new\" entry that opens an in-app changelog dialog (with an unseen\n * dot for new releases). Pass your app's own file:\n * import changelog from \"../CHANGELOG.md?raw\";\n * <CommandMenu ... changelog={changelog} />\n */\n changelog?: string;\n /** Label for the built-in changelog entry. Default: \"What's new\". */\n changelogLabel?: string;\n /**\n * Stable key used to remember which release a user has already seen (for the\n * unseen dot). Defaults to the document title's host app; set explicitly when\n * multiple apps share an origin.\n */\n changelogKey?: string;\n}\n\nexport function CommandMenu({\n open,\n onOpenChange,\n children,\n renderResults,\n placeholder = \"Type a command or ask AI...\",\n emptyText: _emptyText = \"No commands found.\",\n showAgentFallback = true,\n className,\n changelog,\n changelogLabel = \"What's new\",\n changelogKey,\n}: CommandMenuProps) {\n const [search, setSearch] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Built-in \"What's new\" changelog surface (only active when `changelog` is\n // passed). The dialog is rendered alongside the menu so it survives the menu\n // closing; the unseen dot persists per browser via localStorage.\n const [changelogOpen, setChangelogOpen] = useState(false);\n const hasChangelog =\n typeof changelog === \"string\" && changelog.trim().length > 0;\n const changelogEntries = useMemo(\n () => (hasChangelog ? parseChangelog(changelog as string) : []),\n [hasChangelog, changelog],\n );\n const latestChangelogId = changelogEntries[0]?.id;\n const { unseen: changelogUnseen, markSeen: markChangelogSeen } =\n useChangelogSeen(changelogKey ?? \"app\", latestChangelogId);\n\n const openChangelog = useCallback(() => {\n onOpenChange(false);\n markChangelogSeen();\n // Let the menu close before the dialog opens (avoids overlay flicker).\n setTimeout(() => setChangelogOpen(true), 50);\n }, [onOpenChange, markChangelogSeen]);\n\n // Focus input when opening; clear search while closed so reopen never renders\n // dynamic results for the previous query.\n useEffect(() => {\n if (!open) {\n setSearch(\"\");\n setSelectedIndex(0);\n return;\n }\n\n if (open) {\n setSearch(\"\");\n setSelectedIndex(0);\n // Wait for render then focus\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n }\n }, [open]);\n\n // Reset selection when search changes\n useEffect(() => {\n setSelectedIndex(0);\n }, [search]);\n\n // Keep selected item scrolled into view\n useEffect(() => {\n const items = containerRef.current?.querySelectorAll('[role=\"option\"]');\n if (items && items[selectedIndex]) {\n items[selectedIndex].scrollIntoView({ block: \"nearest\" });\n }\n }, [selectedIndex]);\n\n // Apply selected styling directly (can't rely on Tailwind scanning core package)\n useEffect(() => {\n const items = containerRef.current?.querySelectorAll('[role=\"option\"]');\n if (!items) return;\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n if (i === selectedIndex) {\n el.style.backgroundColor = \"hsl(var(--accent))\";\n el.style.color = \"hsl(var(--accent-foreground))\";\n } else {\n el.style.backgroundColor = \"\";\n el.style.color = \"\";\n }\n });\n });\n\n // Close on escape\n useEffect(() => {\n if (!open) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onOpenChange(false);\n }\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, onOpenChange]);\n\n // Close on click outside\n useEffect(() => {\n if (!open) return;\n const handleClick = (e: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n onOpenChange(false);\n }\n };\n // Use capture to handle clicks before they bubble\n document.addEventListener(\"mousedown\", handleClick, true);\n return () => document.removeEventListener(\"mousedown\", handleClick, true);\n }, [open, onOpenChange]);\n\n const handleSubmitToAgent = useCallback(() => {\n onOpenChange(false);\n if (!search.trim()) {\n focusAgentChat();\n return;\n }\n submitToAgent(search.trim());\n }, [search, onOpenChange]);\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n const items = containerRef.current?.querySelectorAll('[role=\"option\"]');\n const itemCount = items?.length ?? 0;\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setSelectedIndex((prev) => (prev + 1) % itemCount || 0);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setSelectedIndex((prev) => (prev - 1 + itemCount) % itemCount || 0);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (items && items[selectedIndex]) {\n (items[selectedIndex] as HTMLElement).click();\n }\n }\n };\n\n // The built-in \"What's new\" row matches changelog-ish search terms.\n const changelogRowMatches =\n !search ||\n [\n changelogLabel,\n \"changelog\",\n \"what's new\",\n \"whats new\",\n \"updates\",\n \"release notes\",\n \"changes\",\n ]\n .join(\" \")\n .toLowerCase()\n .includes(search.toLowerCase());\n const showChangelogRow = hasChangelog && changelogRowMatches;\n\n // Filter children based on search\n const filterChildren = (nodes: ReactNode): ReactNode => {\n return React.Children.map(nodes, (child) => {\n if (!React.isValidElement(child)) return child;\n const props = child.props as Record<string, unknown>;\n\n // If it's a CommandGroup, filter its children\n if (child.type === CommandGroup) {\n const groupChildren = filterChildren(props.children as ReactNode);\n const hasChildren = React.Children.count(groupChildren) > 0;\n if (!hasChildren) return null;\n return React.cloneElement(child, {\n ...props,\n children: groupChildren,\n } as Record<string, unknown>);\n }\n\n if (child.type === CommandDocsGroup) {\n const docs = Array.isArray(props.docs)\n ? (props.docs as CommandMenuDoc[])\n : [];\n const filteredDocs = filterCommandDocs(docs, search);\n if (filteredDocs.length === 0) return null;\n return React.cloneElement(child, {\n ...props,\n docs: filteredDocs,\n } as Record<string, unknown>);\n }\n\n // If it's a CommandItem, check if it matches search\n if (child.type === CommandItem) {\n if (!search) return child;\n const text = getTextContent(props.children as ReactNode).toLowerCase();\n const keywords = ((props.keywords as string[]) || [])\n .join(\" \")\n .toLowerCase();\n const searchLower = search.toLowerCase();\n if (text.includes(searchLower) || keywords.includes(searchLower)) {\n return child;\n }\n return null;\n }\n\n // If it's a separator, keep it (will be cleaned up later if needed)\n if (child.type === CommandSeparator) {\n return search ? null : child; // Hide separators when searching\n }\n\n return child;\n });\n };\n\n const filteredChildren = filterChildren(children);\n const hasResults = React.Children.toArray(filteredChildren).some(\n (child) =>\n React.isValidElement(child) &&\n (child.type === CommandGroup || child.type === CommandDocsGroup),\n );\n const dynamicResults = open ? renderResults?.(search) : null;\n const hasDynamicResults = Boolean(dynamicResults);\n\n return (\n <>\n {open && (\n <div className=\"fixed inset-0 z-50 bg-black/50\">\n <div\n ref={containerRef}\n className={cn(\n \"fixed left-1/2 top-[15vh] -translate-x-1/2 w-full max-w-lg\",\n \"rounded-lg border border-border bg-popover text-popover-foreground shadow-lg\",\n className,\n )}\n >\n <CommandMenuContext.Provider\n value={{ search, onOpenChange, containerRef, setSelectedIndex }}\n >\n {/* Search input */}\n <div className=\"flex items-center border-b px-3\">\n <IconSearch className=\"me-2 h-4 w-4 shrink-0 opacity-50\" />\n <input\n ref={inputRef}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n className=\"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\"\n />\n </div>\n\n {/* Command list */}\n <div className=\"max-h-[300px] overflow-y-auto overflow-x-hidden\">\n {dynamicResults}\n {hasResults && filteredChildren}\n\n {/* What's new — built-in changelog entry */}\n {showChangelogRow && (\n <>\n {hasResults && <CommandSeparator />}\n <div className=\"p-1\">\n <div\n className=\"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none\"\n onClick={openChangelog}\n onMouseEnter={(e) => {\n const items =\n containerRef.current?.querySelectorAll(\n '[role=\"option\"]',\n );\n if (!items) return;\n const index = Array.from(items).indexOf(\n e.currentTarget,\n );\n if (index >= 0) setSelectedIndex(index);\n }}\n role=\"option\"\n >\n <IconHistory className=\"h-4 w-4 text-muted-foreground\" />\n <span>{changelogLabel}</span>\n {changelogUnseen && (\n <span\n className=\"ms-auto h-2 w-2 rounded-full bg-primary\"\n aria-label=\"New updates available\"\n />\n )}\n </div>\n </div>\n </>\n )}\n\n {/* Ask AI — always visible at the bottom */}\n {showAgentFallback && (\n <>\n {(hasResults || showChangelogRow || hasDynamicResults) && (\n <CommandSeparator />\n )}\n <div className=\"p-1\">\n <div\n className=\"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none\"\n onClick={handleSubmitToAgent}\n onMouseEnter={(e) => {\n const items =\n containerRef.current?.querySelectorAll(\n '[role=\"option\"]',\n );\n if (!items) return;\n const index = Array.from(items).indexOf(\n e.currentTarget,\n );\n if (index >= 0) setSelectedIndex(index);\n }}\n role=\"option\"\n >\n <IconMessage className=\"h-4 w-4 text-muted-foreground\" />\n <span>\n {search.trim() ? (\n <>\n Ask AI:{\" \"}\n <span className=\"text-muted-foreground\">\n \"{search}\"\n </span>\n </>\n ) : (\n <span className=\"text-muted-foreground\">\n Ask AI anything...\n </span>\n )}\n </span>\n {search.trim() && (\n <span className=\"ms-auto text-xs text-muted-foreground\">\n ↵\n </span>\n )}\n </div>\n </div>\n </>\n )}\n </div>\n </CommandMenuContext.Provider>\n </div>\n </div>\n )}\n\n {hasChangelog && (\n <ChangelogDialog\n open={changelogOpen}\n onOpenChange={setChangelogOpen}\n markdown={changelog as string}\n title={changelogLabel}\n />\n )}\n </>\n );\n}\n\n// Helper to extract text content from React children\nfunction getTextContent(children: ReactNode): string {\n if (typeof children === \"string\") return children;\n if (typeof children === \"number\") return String(children);\n if (!children) return \"\";\n if (Array.isArray(children)) {\n return children.map(getTextContent).join(\" \");\n }\n if (\n React.isValidElement(children) &&\n (children.props as Record<string, unknown>).children\n ) {\n return getTextContent(\n (children.props as Record<string, unknown>).children as ReactNode,\n );\n }\n return \"\";\n}\n\n// Attach sub-components\nCommandMenu.Group = CommandGroup;\nCommandMenu.Item = CommandItem;\nCommandMenu.DocsGroup = CommandDocsGroup;\nCommandMenu.Shortcut = CommandShortcut;\nCommandMenu.Separator = CommandSeparator;\n\n// ─── Keyboard Hook ──────────────────────────────────────────────────────────\n\n/**\n * Hook to handle Cmd+K (or Ctrl+K) to open the command menu\n */\nexport function useCommandMenuShortcut(\n onOpen: () => void,\n options: { allowContentEditable?: boolean } = {},\n) {\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === \"k\") {\n // Don't trigger if user is typing in a native form control.\n const target = e.target instanceof HTMLElement ? e.target : null;\n const isContentEditable = target?.isContentEditable;\n if (\n target?.tagName === \"INPUT\" ||\n target?.tagName === \"TEXTAREA\" ||\n target?.tagName === \"SELECT\" ||\n (!options.allowContentEditable && isContentEditable)\n ) {\n return;\n }\n e.preventDefault();\n onOpen();\n }\n };\n const useCapture = Boolean(options.allowContentEditable);\n document.addEventListener(\"keydown\", handleKeyDown, useCapture);\n return () =>\n document.removeEventListener(\"keydown\", handleKeyDown, useCapture);\n }, [onOpen, options.allowContentEditable]);\n}\n\nexport type {\n CommandDocsGroupProps,\n CommandGroupProps,\n CommandItemProps,\n CommandShortcutProps,\n};\n"]}
|
|
@@ -3,18 +3,18 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
3
3
|
url?: string;
|
|
4
4
|
filename?: string;
|
|
5
5
|
}, {
|
|
6
|
+
id?: undefined;
|
|
6
7
|
error: string;
|
|
7
8
|
configured?: undefined;
|
|
8
9
|
connectPath?: undefined;
|
|
9
10
|
url?: undefined;
|
|
10
|
-
id?: undefined;
|
|
11
11
|
provider?: undefined;
|
|
12
12
|
} | {
|
|
13
|
+
id?: undefined;
|
|
13
14
|
error: string;
|
|
14
15
|
configured: boolean;
|
|
15
16
|
connectPath: string;
|
|
16
17
|
url?: undefined;
|
|
17
|
-
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
20
|
error?: undefined;
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
14
|
count: number;
|
|
15
15
|
updated?: undefined;
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error?: undefined;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
count?: undefined;
|
|
20
20
|
updated: number;
|
|
21
|
-
ok?: undefined;
|
|
22
21
|
error?: undefined;
|
|
22
|
+
ok?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
count?: undefined;
|
|
25
25
|
updated?: undefined;
|
|
@@ -41,28 +41,28 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
-
|
|
44
|
+
error?: undefined;
|
|
45
45
|
summary: import("./types.js").TraceSummary;
|
|
46
46
|
spans: import("./types.js").TraceSpan[];
|
|
47
|
-
error?: undefined;
|
|
48
47
|
id?: undefined;
|
|
49
|
-
} | {
|
|
50
48
|
ok?: undefined;
|
|
49
|
+
} | {
|
|
50
|
+
error?: undefined;
|
|
51
51
|
summary?: undefined;
|
|
52
52
|
spans?: undefined;
|
|
53
53
|
id: string;
|
|
54
|
-
error?: undefined;
|
|
55
|
-
} | {
|
|
56
54
|
ok?: undefined;
|
|
55
|
+
} | {
|
|
57
56
|
summary?: undefined;
|
|
58
57
|
spans?: undefined;
|
|
59
|
-
error: any;
|
|
60
58
|
id?: undefined;
|
|
59
|
+
error: any;
|
|
60
|
+
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
+
error?: undefined;
|
|
62
63
|
summary?: undefined;
|
|
63
64
|
spans?: undefined;
|
|
64
|
-
ok: boolean;
|
|
65
|
-
error?: undefined;
|
|
66
65
|
id?: undefined;
|
|
66
|
+
ok: boolean;
|
|
67
67
|
}>>;
|
|
68
68
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
+
error?: undefined;
|
|
30
31
|
ok: boolean;
|
|
31
32
|
key: string;
|
|
32
33
|
baseUrlKey?: string;
|
|
33
34
|
scope: AgentEngineApiKeyScope;
|
|
34
|
-
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
|
37
37
|
//# sourceMappingURL=agent-engine-api-key-route.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.83.0",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|