{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-kit",
  "dependencies": [
    "@platejs/ai"
  ],
  "registryDependencies": [
    "https://platejs.org/r/markdown-kit.json",
    "https://platejs.org/r/cursor-overlay-kit.json",
    "https://platejs.org/r/ai-menu.json",
    "https://platejs.org/r/ai-node.json",
    "https://platejs.org/r/ai-toolbar-button.json",
    "https://platejs.org/r/ai-api.json"
  ],
  "files": [
    {
      "path": "src/registry/components/editor/plugins/ai-kit.tsx",
      "content": "'use client';\n\nimport cloneDeep from 'lodash/cloneDeep.js';\nimport { BaseAIPlugin, withAIBatch } from '@platejs/ai';\nimport {\n  AIChatPlugin,\n  AIPlugin,\n  applyAISuggestions,\n  getInsertPreviewStart,\n  streamInsertChunk,\n  useChatChunk,\n} from '@platejs/ai/react';\nimport { ElementApi, getPluginType, KEYS, PathApi } from 'platejs';\nimport { usePluginOption } from 'platejs/react';\n\nimport { AILoadingBar, AIMenu } from '@/registry/ui/ai-menu';\nimport { AIAnchorElement, AILeaf } from '@/registry/ui/ai-node';\n\nimport { useChat } from '../use-chat';\nimport { CursorOverlayKit } from './cursor-overlay-kit';\nimport { MarkdownKit } from './markdown-kit';\n\nexport const aiChatPlugin = AIChatPlugin.extend({\n  options: {\n    chatOptions: {\n      api: '/api/ai/command',\n      body: {},\n    },\n  },\n  render: {\n    afterContainer: AILoadingBar,\n    afterEditable: AIMenu,\n    node: AIAnchorElement,\n  },\n  shortcuts: { show: { keys: 'mod+j' } },\n  useHooks: ({ editor, getOption }) => {\n    useChat();\n\n    const mode = usePluginOption(AIChatPlugin, 'mode');\n    const toolName = usePluginOption(AIChatPlugin, 'toolName');\n    useChatChunk({\n      onChunk: ({ chunk, isFirst, nodes, text: content }) => {\n        if (isFirst && mode === 'insert') {\n          const { startBlock, startInEmptyParagraph } =\n            getInsertPreviewStart(editor);\n\n          editor.getTransforms(BaseAIPlugin).ai.beginPreview({\n            originalBlocks:\n              startInEmptyParagraph &&\n              startBlock &&\n              ElementApi.isElement(startBlock)\n                ? [cloneDeep(startBlock)]\n                : [],\n          });\n\n          editor.tf.withoutSaving(() => {\n            editor.tf.insertNodes(\n              {\n                children: [{ text: '' }],\n                type: getPluginType(editor, KEYS.aiChat),\n              },\n              {\n                at: PathApi.next(editor.selection!.focus.path.slice(0, 1)),\n              }\n            );\n          });\n          editor.setOption(AIChatPlugin, 'streaming', true);\n        }\n\n        if (mode === 'insert' && nodes.length > 0) {\n          editor.tf.withoutSaving(() => {\n            if (!getOption('streaming')) return;\n\n            editor.tf.withScrolling(() => {\n              streamInsertChunk(editor, chunk, {\n                textProps: {\n                  [getPluginType(editor, KEYS.ai)]: true,\n                },\n              });\n            });\n          });\n        }\n\n        if (toolName === 'edit' && mode === 'chat') {\n          withAIBatch(\n            editor,\n            () => {\n              applyAISuggestions(editor, content);\n            },\n            {\n              split: isFirst,\n            }\n          );\n        }\n      },\n      onFinish: () => {\n        editor.getApi(AIChatPlugin).aiChat.stop();\n      },\n    });\n  },\n});\n\nexport const AIKit = [\n  ...CursorOverlayKit,\n  ...MarkdownKit,\n  AIPlugin.withComponent(AILeaf),\n  aiChatPlugin,\n];\n",
      "type": "registry:component",
      "target": "@components/editor/plugins/ai-kit.tsx"
    }
  ],
  "type": "registry:component"
}