@monaco-ai-editor/core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -463,30 +463,33 @@ function createCursorSpinner(editor, line, col) {
463
463
  collection.clear();
464
464
  };
465
465
  }
466
- async function fetchAiCompletionNonStream(config, context, prefix, signal) {
467
- const response = await fetch(`${config.baseUrl}/chat/completions`, {
468
- method: "POST",
469
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
470
- body: JSON.stringify({
471
- model: config.model,
472
- messages: [
473
- {
474
- role: "system",
475
- content: "\u4F60\u662F\u4E00\u4E2A\u4EE3\u7801\u8865\u5168\u52A9\u624B\u3002\u57FA\u4E8E\u7528\u6237\u63D0\u4F9B\u7684\u4EE3\u7801\u4E0A\u4E0B\u6587\u548C\u524D\u7F00\uFF0C\u751F\u6210\u77ED\u5C0F\u7CBE\u608D\u7684\u4EE3\u7801\u8865\u5168\u3002\u53EA\u8FD4\u56DE\u8865\u5168\u7684\u4EE3\u7801\u7247\u6BB5\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002"
476
- },
477
- {
478
- role: "user",
479
- content: `\u4EE3\u7801\u4E0A\u4E0B\u6587\uFF1A
466
+ var DEFAULT_COMPLETION_SYSTEM = "\u4F60\u662F\u4E00\u4E2A\u4EE3\u7801\u8865\u5168\u52A9\u624B\u3002\u57FA\u4E8E\u7528\u6237\u63D0\u4F9B\u7684\u4EE3\u7801\u4E0A\u4E0B\u6587\u548C\u524D\u7F00\uFF0C\u751F\u6210\u77ED\u5C0F\u7CBE\u608D\u7684\u4EE3\u7801\u8865\u5168\u3002\u53EA\u8FD4\u56DE\u8865\u5168\u7684\u4EE3\u7801\u7247\u6BB5\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002";
467
+ function buildRequestBody(config, context, prefix, stream) {
468
+ const ov = config.completion ?? {};
469
+ const thinking = ov.thinking ?? config.thinking ?? { type: "disabled" };
470
+ const body = {
471
+ model: ov.model ?? config.model,
472
+ messages: [
473
+ { role: "system", content: ov.systemPrompt ?? DEFAULT_COMPLETION_SYSTEM },
474
+ { role: "user", content: `\u4EE3\u7801\u4E0A\u4E0B\u6587\uFF1A
480
475
  ${context}
481
476
 
482
477
  \u524D\u7F00\uFF1A${prefix}
483
478
 
484
- \u8BF7\u7EE7\u7EED\u8865\u5168\u8FD9\u6BB5\u4EE3\u7801\uFF0C\u53EA\u8FD4\u56DE\u8865\u5168\u90E8\u5206\u3002`
485
- }
486
- ],
487
- max_tokens: 1024,
488
- stream: false
489
- }),
479
+ \u8BF7\u7EE7\u7EED\u8865\u5168\u8FD9\u6BB5\u4EE3\u7801\uFF0C\u53EA\u8FD4\u56DE\u8865\u5168\u90E8\u5206\u3002` }
480
+ ],
481
+ max_tokens: ov.maxTokens ?? 512,
482
+ stream
483
+ };
484
+ body.thinking = thinking;
485
+ if (ov.temperature !== void 0) body.temperature = ov.temperature;
486
+ return body;
487
+ }
488
+ async function fetchAiCompletionNonStream(config, context, prefix, signal) {
489
+ const response = await fetch(`${config.baseUrl}/chat/completions`, {
490
+ method: "POST",
491
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
492
+ body: JSON.stringify(buildRequestBody(config, context, prefix, false)),
490
493
  signal
491
494
  });
492
495
  if (!response.ok) {
@@ -499,26 +502,7 @@ async function fetchAiCompletionStream(config, context, prefix, onChunk, signal)
499
502
  const response = await fetch(`${config.baseUrl}/chat/completions`, {
500
503
  method: "POST",
501
504
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
502
- body: JSON.stringify({
503
- model: config.model,
504
- messages: [
505
- {
506
- role: "system",
507
- content: "\u4F60\u662F\u4E00\u4E2A\u4EE3\u7801\u8865\u5168\u52A9\u624B\u3002\u57FA\u4E8E\u7528\u6237\u63D0\u4F9B\u7684\u4EE3\u7801\u4E0A\u4E0B\u6587\u548C\u524D\u7F00\uFF0C\u751F\u6210\u77ED\u5C0F\u7CBE\u608D\u7684\u4EE3\u7801\u8865\u5168\u3002\u53EA\u8FD4\u56DE\u8865\u5168\u7684\u4EE3\u7801\u7247\u6BB5\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002"
508
- },
509
- {
510
- role: "user",
511
- content: `\u4EE3\u7801\u4E0A\u4E0B\u6587\uFF1A
512
- ${context}
513
-
514
- \u524D\u7F00\uFF1A${prefix}
515
-
516
- \u8BF7\u7EE7\u7EED\u8865\u5168\u8FD9\u6BB5\u4EE3\u7801\uFF0C\u53EA\u8FD4\u56DE\u8865\u5168\u90E8\u5206\u3002`
517
- }
518
- ],
519
- max_tokens: 1024,
520
- stream: true
521
- }),
505
+ body: JSON.stringify(buildRequestBody(config, context, prefix, true)),
522
506
  signal
523
507
  });
524
508
  if (!response.ok) {
@@ -907,17 +891,26 @@ var AiChatController = class extends EventEmitter {
907
891
  this.abortController = new AbortController();
908
892
  const systemPrompt = options?.language ? `You are an expert coding assistant. The user is working with ${options.language} code. Respond concisely in the same language as the user's message, defaulting to Chinese.` : "You are an expert coding assistant. Respond concisely in the same language as the user's message, defaulting to Chinese.";
909
893
  const historyForApi = this.messages.filter((m) => m.id !== assistantMsg.id).map((m) => ({ role: m.role, content: m.content }));
894
+ const chatOv = this.apiConfig.chat ?? {};
895
+ const thinking = chatOv.thinking ?? this.apiConfig.thinking ?? { type: "enabled" };
896
+ const chatBody = {
897
+ model: chatOv.model ?? this.apiConfig.model,
898
+ messages: [
899
+ { role: "system", content: chatOv.systemPrompt ?? systemPrompt },
900
+ ...historyForApi
901
+ ],
902
+ max_tokens: chatOv.maxTokens ?? 4096,
903
+ stream: true,
904
+ thinking
905
+ };
906
+ if (chatOv.temperature !== void 0) chatBody.temperature = chatOv.temperature;
910
907
  const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {
911
908
  method: "POST",
912
909
  headers: {
913
910
  "Content-Type": "application/json",
914
911
  Authorization: `Bearer ${this.apiConfig.apiKey}`
915
912
  },
916
- body: JSON.stringify({
917
- model: this.apiConfig.model,
918
- messages: [{ role: "system", content: systemPrompt }, ...historyForApi],
919
- stream: true
920
- }),
913
+ body: JSON.stringify(chatBody),
921
914
  signal: this.abortController.signal
922
915
  });
923
916
  if (!response.ok) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/bus/EventEmitter.ts","../src/completion/sqlCompletion.ts","../src/ai/aiCompletion.ts","../src/controllers/EditorController.ts","../src/controllers/AiChatController.ts","../src/bus/EditorBus.ts"],"sourcesContent":["// ─── 类型 ──────────────────────────────────────────────────────────────\nexport type {\n ApiConfig,\n SqlSchema,\n PendingCompletion,\n ChatMessage,\n EditorSnapshot,\n CompletionContext,\n CompletionProvider,\n} from './types';\n\n// ─── 常量 ──────────────────────────────────────────────────────────────\nexport {\n SQL_KEYWORDS,\n SQL_FUNCTIONS,\n SQL_DATA_TYPES,\n LANGUAGES,\n THEMES,\n AI_INLINE_LANGUAGES,\n LOCALES,\n type Locale,\n} from './constants';\n\n// ─── 控制器 ────────────────────────────────────────────────────────────\nexport {\n EditorController,\n type EditorControllerOptions,\n type EditorControllerEvents,\n} from './controllers/EditorController';\n\nexport {\n AiChatController,\n type AiChatControllerEvents,\n} from './controllers/AiChatController';\n\n// ─── 总线 ──────────────────────────────────────────────────────────────\nexport { EditorBus, type EditorBusEvents } from './bus/EditorBus';\nexport { EventEmitter, type Listener } from './bus/EventEmitter';\n\n// ─── 补全 / AI ────────────────────────────────────────────────────────\nexport { registerSqlCompletion } from './completion/sqlCompletion';\nexport {\n registerAiInlineCompletion,\n registerAiCompletionCommand,\n fetchAiCompletionStream,\n fetchAiCompletionNonStream,\n} from './ai/aiCompletion';\n","export const SQL_KEYWORDS = [\n 'SELECT', 'FROM', 'WHERE', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE',\n 'CREATE', 'TABLE', 'DROP', 'ALTER', 'ADD', 'COLUMN', 'INDEX', 'VIEW', 'DATABASE',\n 'SCHEMA', 'TRUNCATE', 'RENAME', 'AS', 'ON', 'JOIN', 'INNER', 'LEFT', 'RIGHT',\n 'FULL', 'OUTER', 'CROSS', 'NATURAL', 'USING', 'AND', 'OR', 'NOT', 'IN', 'EXISTS',\n 'BETWEEN', 'LIKE', 'IS', 'NULL', 'TRUE', 'FALSE', 'CASE', 'WHEN', 'THEN', 'ELSE',\n 'END', 'IF', 'UNION', 'ALL', 'DISTINCT', 'ORDER', 'BY', 'ASC', 'DESC', 'GROUP',\n 'HAVING', 'LIMIT', 'OFFSET', 'FETCH', 'NEXT', 'ROWS', 'ONLY', 'WITH', 'RECURSIVE',\n 'PRIMARY', 'KEY', 'FOREIGN', 'REFERENCES', 'UNIQUE', 'NOT NULL', 'DEFAULT',\n 'CHECK', 'CONSTRAINT', 'AUTO_INCREMENT', 'IDENTITY', 'SEQUENCE', 'GRANT',\n 'REVOKE', 'COMMIT', 'ROLLBACK', 'TRANSACTION', 'BEGIN', 'SAVEPOINT', 'EXPLAIN',\n];\n\nexport const SQL_FUNCTIONS = [\n 'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'COALESCE', 'NULLIF', 'IFNULL', 'NVL',\n 'CONCAT', 'LENGTH', 'SUBSTR', 'SUBSTRING', 'TRIM', 'LTRIM', 'RTRIM', 'UPPER',\n 'LOWER', 'REPLACE', 'INSTR', 'LPAD', 'RPAD', 'CHAR_LENGTH', 'POSITION',\n 'NOW', 'CURDATE', 'CURTIME', 'DATE', 'TIME', 'YEAR', 'MONTH', 'DAY',\n 'HOUR', 'MINUTE', 'SECOND', 'DATEDIFF', 'DATE_ADD', 'DATE_SUB', 'DATEADD',\n 'DATESUB', 'EXTRACT', 'TO_DATE', 'TO_CHAR', 'DATE_FORMAT', 'TIMESTAMPDIFF',\n 'ROUND', 'CEIL', 'FLOOR', 'ABS', 'MOD', 'POWER', 'SQRT', 'SIGN', 'RAND',\n 'CAST', 'CONVERT', 'ROW_NUMBER', 'RANK', 'DENSE_RANK', 'NTILE', 'LAG', 'LEAD',\n 'FIRST_VALUE', 'LAST_VALUE', 'OVER', 'PARTITION', 'LISTAGG', 'GROUP_CONCAT',\n 'STRING_AGG', 'JSON_OBJECT', 'JSON_ARRAY', 'JSON_EXTRACT', 'ISNULL',\n];\n\nexport const SQL_DATA_TYPES = [\n 'INT', 'INTEGER', 'BIGINT', 'SMALLINT', 'TINYINT', 'DECIMAL', 'NUMERIC',\n 'FLOAT', 'DOUBLE', 'REAL', 'CHAR', 'VARCHAR', 'TEXT', 'NCHAR', 'NVARCHAR',\n 'NTEXT', 'DATE', 'TIME', 'DATETIME', 'TIMESTAMP', 'BOOLEAN', 'BOOL',\n 'BLOB', 'CLOB', 'BINARY', 'VARBINARY', 'JSON', 'UUID', 'SERIAL',\n];\n\nexport const LANGUAGES = [\n 'javascript',\n 'typescript',\n 'python',\n 'json',\n 'css',\n 'html',\n 'markdown',\n 'rust',\n 'go',\n 'sql',\n] as const;\n\n/** Monaco 编辑器支持的 UI 本地化语言 */\nexport const LOCALES = {\n ZH_CN: 'zh-cn',\n EN: 'en',\n DE: 'de',\n ES: 'es',\n FR: 'fr',\n IT: 'it',\n JA: 'ja',\n KO: 'ko',\n RU: 'ru',\n} as const;\n\nexport type Locale = (typeof LOCALES)[keyof typeof LOCALES];\n\nexport const THEMES = [\n { value: 'vs-dark', label: 'Dark' },\n { value: 'light', label: 'Light' },\n { value: 'hc-black', label: 'High Contrast' },\n] as const;\n\nexport const AI_INLINE_LANGUAGES = [\n 'typescript', 'javascript', 'python', 'sql',\n 'java', 'cpp', 'csharp', 'go', 'rust',\n];\n","/**\n * 极简事件发射器,框架无关。\n * 用于 EditorController / AiChatController / EditorBus 之间的事件通信。\n */\nexport type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<EventMap> {\n private listeners: { [K in keyof EventMap]?: Set<Listener<EventMap[K]>> } = {};\n\n on<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): () => void {\n if (!this.listeners[event]) this.listeners[event] = new Set();\n this.listeners[event]!.add(listener);\n return () => this.off(event, listener);\n }\n\n off<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): void {\n this.listeners[event]?.delete(listener);\n }\n\n emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.listeners[event]?.forEach((listener) => {\n try {\n listener(payload);\n } catch (err) {\n console.error(`[EventEmitter] listener for \"${String(event)}\" threw:`, err);\n }\n });\n }\n\n removeAllListeners(): void {\n this.listeners = {};\n }\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { SQL_KEYWORDS, SQL_FUNCTIONS, SQL_DATA_TYPES } from '../constants';\nimport type { SqlSchema } from '../types';\n\n/** 从 SQL 文档中动态解析表名、CTE 别名和变量 */\nfunction parseDynamicItems(sql: string): { tables: string[]; variables: string[] } {\n const tables: string[] = [];\n const variables: string[] = [];\n let m: RegExpExecArray | null;\n\n const tableRe = /\\b(?:FROM|JOIN|UPDATE|INTO|TABLE)\\s+([`\"']?\\w+[`\"']?)/gi;\n while ((m = tableRe.exec(sql)) !== null) {\n const name = m[1].replace(/[`\"']/g, '');\n if (!tables.includes(name)) tables.push(name);\n }\n\n const cteRe = /\\bWITH\\s+(\\w+)\\s+AS\\s*\\(/gi;\n while ((m = cteRe.exec(sql)) !== null) {\n if (!tables.includes(m[1])) tables.push(m[1]);\n }\n\n const declareRe = /\\bDECLARE\\s+(@?\\w+)/gi;\n while ((m = declareRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const setVarRe = /\\bSET\\s+(@\\w+)\\s*=/gi;\n while ((m = setVarRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const atVarRe = /@(\\w+)/g;\n while ((m = atVarRe.exec(sql)) !== null) {\n const v = `@${m[1]}`;\n if (!variables.includes(v)) variables.push(v);\n }\n\n return { tables, variables };\n}\n\n/**\n * 注册 SQL 内置补全提供者。\n * schemaRef 使用 ref 模式以支持动态更新。\n * excludeLabelsRef(可选)使用 ref 模式,提供需要从内置关键字/函数中排除的 label\n * (大写匹配)。用于让使用方的自定义词表覆盖内置同名项,避免重复提示。\n */\nexport function registerSqlCompletion(\n monaco: typeof MonacoType,\n schemaRef: { readonly current: SqlSchema },\n excludeLabelsRef?: { readonly current: Set<string> },\n): MonacoType.IDisposable {\n return monaco.languages.registerCompletionItemProvider('sql', {\n triggerCharacters: ['.'],\n provideCompletionItems(model, position, context) {\n const word = model.getWordUntilPosition(position);\n const range: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: word.startColumn,\n endColumn: word.endColumn,\n };\n\n // 点号触发:提示该表的列名\n if (context.triggerCharacter === '.') {\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforeDot = lineText.substring(0, position.column - 2);\n const tableMatch = textBeforeDot.match(/(\\w+)$/);\n if (tableMatch) {\n const typed = tableMatch[1].toUpperCase();\n const schema = schemaRef.current;\n const tableKey = Object.keys(schema).find((k) => k.toUpperCase() === typed);\n if (tableKey) {\n const colRange: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n };\n return {\n suggestions: schema[tableKey].map((col) => ({\n label: col,\n kind: monaco.languages.CompletionItemKind.Field,\n insertText: col,\n range: colRange,\n detail: `${tableKey} · 列`,\n documentation: `表 ${tableKey} 的字段`,\n })),\n };\n }\n }\n return { suggestions: [] };\n }\n\n // 普通触发:关键字 + 函数 + 类型 + 表名 + 变量\n const fullText = model.getValue();\n const { tables: dynamicTables, variables } = parseDynamicItems(fullText);\n const schema = schemaRef.current;\n const schemaTables = Object.keys(schema);\n const allTables = [...new Set([...schemaTables, ...dynamicTables])];\n\n // 需要排除的内置 label(大写匹配),让使用方自定义词表覆盖同名项\n const exclude = excludeLabelsRef?.current;\n const isExcluded = (label: string) => exclude?.has(label.toUpperCase()) ?? false;\n\n const keywords = SQL_KEYWORDS.filter((kw) => !isExcluded(kw)).map((kw) => ({\n label: kw,\n kind: monaco.languages.CompletionItemKind.Keyword,\n insertText: kw,\n range,\n detail: 'SQL 关键字',\n }));\n\n const functions = SQL_FUNCTIONS.filter((fn) => !isExcluded(fn)).map((fn) => ({\n label: fn,\n kind: monaco.languages.CompletionItemKind.Function,\n insertText: `${fn}($1)`,\n insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n range,\n detail: 'SQL 函数',\n }));\n\n const dataTypes = SQL_DATA_TYPES.map((dt) => ({\n label: dt,\n kind: monaco.languages.CompletionItemKind.TypeParameter,\n insertText: dt,\n range,\n detail: 'SQL 数据类型',\n }));\n\n const tableItems = allTables.map((t) => ({\n label: t,\n kind: monaco.languages.CompletionItemKind.Class,\n insertText: t,\n range,\n detail: schemaTables.includes(t) ? '表名 (Schema)' : '表名 (文档)',\n }));\n\n const variableItems = variables.map((v) => ({\n label: v,\n kind: monaco.languages.CompletionItemKind.Variable,\n insertText: v,\n range,\n detail: 'SQL 变量',\n }));\n\n return {\n suggestions: [...keywords, ...functions, ...dataTypes, ...tableItems, ...variableItems],\n };\n },\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport type { ApiConfig, PendingCompletion } from '../types';\nimport { AI_INLINE_LANGUAGES } from '../constants';\n\n/** 去除模型返回中可能包含的代码围栏(```lang ... ```) */\nfunction stripCodeFence(text: string): string {\n return text.replace(/^```[a-z]*\\n?/, '').replace(/\\n?```$/, '');\n}\n\nconst SPINNER_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'] as const;\n\nfunction ensureSpinnerStyle() {\n const id = 'mae-ai-completion-spinner-style';\n if (typeof document === 'undefined' || document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n const frameCss = SPINNER_FRAMES.map((ch, i) => `.mae-ai-spinner-f${i}::after { content: \" ${ch}\"; }`).join('\\n');\n style.textContent = `\n@keyframes mae-ai-completion-glow {\n 0%, 100% { text-shadow: 0 0 3px rgba(96, 165, 250, 0.35); }\n 50% { text-shadow: 0 0 9px rgba(96, 165, 250, 0.95), 0 0 18px rgba(59, 130, 246, 0.35); }\n}\n${frameCss}\n[class^=\"mae-ai-spinner-f\"]::after {\n color: #60a5fa;\n font-family: \"Segoe UI Symbol\", \"Noto Sans Symbols\", \"Apple Symbols\", monospace;\n display: inline-block;\n margin-left: 2px;\n animation: mae-ai-completion-glow 1s ease-in-out infinite;\n}`;\n document.head.appendChild(style);\n}\n\nfunction createCursorSpinner(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n line: number,\n col: number,\n): () => void {\n ensureSpinnerStyle();\n let frameIdx = 0;\n const makeDecor = () => [{\n range: { startLineNumber: line, startColumn: col, endLineNumber: line, endColumn: col },\n options: { afterContentClassName: `mae-ai-spinner-f${frameIdx}` },\n }];\n const collection = editor.createDecorationsCollection(makeDecor());\n const timer = setInterval(() => {\n frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;\n collection.set(makeDecor());\n }, 80);\n return () => {\n clearInterval(timer);\n collection.clear();\n };\n}\n\n/** 非流式调用 OpenAI 兼容 API(使用原生 fetch,无 axios 依赖) */\nexport async function fetchAiCompletionNonStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n signal?: AbortSignal,\n): Promise<string> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify({\n model: config.model,\n messages: [\n {\n role: 'system',\n content: '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。',\n },\n {\n role: 'user',\n content: `代码上下文:\\n${context}\\n\\n前缀:${prefix}\\n\\n请继续补全这段代码,只返回补全部分。`,\n },\n ],\n max_tokens: 1024,\n stream: false,\n }),\n signal,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n const data = (await response.json()) as { choices?: Array<{ message?: { content?: string } }> };\n return stripCodeFence(data.choices?.[0]?.message?.content?.trim() ?? '');\n}\n\n/** 流式调用(fetch + ReadableStream) */\nexport async function fetchAiCompletionStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n onChunk: (accumulated: string) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify({\n model: config.model,\n messages: [\n {\n role: 'system',\n content: '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。',\n },\n {\n role: 'user',\n content: `代码上下文:\\n${context}\\n\\n前缀:${prefix}\\n\\n请继续补全这段代码,只返回补全部分。`,\n },\n ],\n max_tokens: 1024,\n stream: true,\n }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n if (!response.body) throw new Error('Response body is null');\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let accumulated = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data:')) continue;\n const data = trimmed.slice(5).trim();\n if (data === '[DONE]') return;\n try {\n const parsed = JSON.parse(data) as { choices?: Array<{ delta?: { content?: string } }> };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n accumulated += delta;\n onChunk(accumulated);\n }\n } catch {\n // ignore malformed lines\n }\n }\n }\n}\n\n/** 注册 AI 内联幽灵文本提供者 */\nexport function registerAiInlineCompletion(\n monaco: typeof MonacoType,\n pendingRef: { current: PendingCompletion | null },\n): void {\n AI_INLINE_LANGUAGES.forEach((lang) => {\n monaco.languages.registerInlineCompletionsProvider(lang, {\n provideInlineCompletions: (_model, position) => {\n const pending = pendingRef.current;\n if (!pending) return { items: [] };\n if (pending.lineNumber !== position.lineNumber || pending.column !== position.column) {\n pendingRef.current = null;\n return { items: [] };\n }\n return {\n items: [\n {\n insertText: pending.insertText,\n range: {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n },\n },\n ],\n };\n },\n disposeInlineCompletions: () => {},\n });\n });\n}\n\n/**\n * 注册 AI 补全命令(Ctrl+Alt+L 手动触发,流式更新幽灵文本)。\n * 框架无关:通过函数引用方式读取最新的 apiConfig。\n */\nexport function registerAiCompletionCommand(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n getApiConfig: () => ApiConfig | null,\n pendingRef: { current: PendingCompletion | null },\n onLoadingChange?: (loading: boolean) => void,\n onError?: (message: string) => void,\n): MonacoType.IDisposable {\n let currentAbortController: AbortController | null = null;\n\n const isAbortError = (err: unknown): boolean =>\n err instanceof Error && (err.name === 'AbortError' || err.message?.includes('aborted'));\n\n const triggerAiCompletion = async () => {\n const apiConfig = getApiConfig();\n if (!apiConfig || !apiConfig.apiKey.trim()) {\n onError?.('未配置 API Key,请先配置 AI 服务再使用补全功能。');\n return;\n }\n\n const position = editor.getPosition();\n if (!position) return;\n const model = editor.getModel();\n if (!model) return;\n\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforePosition = lineText.substring(0, position.column - 1);\n if (!textBeforePosition.trim()) return;\n\n const startLine = Math.max(0, position.lineNumber - 5);\n const contextLines: string[] = [];\n for (let i = startLine; i < position.lineNumber; i++) {\n contextLines.push(model.getLineContent(i + 1));\n }\n const contextCode = contextLines.join('\\n');\n\n currentAbortController?.abort();\n currentAbortController = new AbortController();\n pendingRef.current = null;\n\n const stopSpinner = createCursorSpinner(editor, position.lineNumber, position.column);\n onLoadingChange?.(true);\n\n const useStream = apiConfig.streamMode !== false;\n\n try {\n if (useStream) {\n let triggerTimer: ReturnType<typeof setTimeout> | null = null;\n const scheduleTrigger = () => {\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n triggerTimer = setTimeout(() => {\n triggerTimer = null;\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n }, 80);\n };\n\n await fetchAiCompletionStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n (accumulated) => {\n let insertText = stripCodeFence(accumulated);\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n scheduleTrigger();\n },\n currentAbortController.signal,\n );\n\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } else {\n const completion = await fetchAiCompletionNonStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n currentAbortController.signal,\n );\n if (!completion) return;\n let insertText = completion;\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } catch (err) {\n if (isAbortError(err)) return;\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(`AI 补全失败:${msg}`);\n console.error('[AI Completion] Error:', err);\n } finally {\n stopSpinner();\n onLoadingChange?.(false);\n }\n };\n\n return editor.onKeyDown((e) => {\n if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === 'KeyL') {\n e.preventDefault();\n void triggerAiCompletion();\n }\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, PendingCompletion, SqlSchema, CompletionProvider } from '../types';\nimport { registerSqlCompletion } from '../completion/sqlCompletion';\nimport { registerAiInlineCompletion } from '../ai/aiCompletion';\n\nexport interface EditorControllerEvents {\n change: { value: string };\n cursor: { line: number; column: number };\n ready: { editor: MonacoType.editor.IStandaloneCodeEditor };\n languageChange: { language: string };\n focus: void;\n blur: void;\n}\n\nexport interface EditorControllerOptions {\n container: HTMLElement;\n language?: string;\n theme?: string;\n value?: string;\n monaco: typeof MonacoType;\n /** Monaco loader monaco-editor 路径配置 */\n vsPath?: string;\n sqlSchema?: SqlSchema;\n apiConfig?: ApiConfig | null;\n completionProviders?: CompletionProvider[];\n /** Monaco editor options */\n editorOptions?: MonacoType.editor.IStandaloneEditorConstructionOptions;\n}\n\n/**\n * 框架无关的编辑器控制器。\n * 封装 Monaco 实例的生命周期、核心操作、补全注册。\n * 通过 EventEmitter 暴露编辑器事件,不依赖任何 UI 框架。\n */\nexport class EditorController extends EventEmitter<EditorControllerEvents> {\n private editor: MonacoType.editor.IStandaloneCodeEditor | null = null;\n private monaco: typeof MonacoType;\n private sqlProviderRegistered = false;\n private aiProviderRegistered = false;\n private pendingCompletionRef = { current: null as PendingCompletion | null };\n private customProviders: CompletionProvider[] = [];\n private disposables: MonacoType.IDisposable[] = [];\n\n completed = false;\n error: Error | null = null;\n\n constructor(private options: EditorControllerOptions) {\n super();\n this.monaco = options.monaco;\n this.customProviders = options.completionProviders ?? [];\n this.init();\n }\n\n private init(): void {\n const { language, theme, value, sqlSchema, apiConfig, editorOptions } = this.options;\n\n // 注册 SQL 补全(只注册一次)\n if (!this.sqlProviderRegistered) {\n const schemaRef = { current: sqlSchema ?? {} };\n registerSqlCompletion(this.monaco, schemaRef);\n this.sqlProviderRegistered = true;\n }\n\n // 注册 AI 幽灵文本提供者\n if (!this.aiProviderRegistered) {\n registerAiInlineCompletion(this.monaco, this.pendingCompletionRef);\n this.aiProviderRegistered = true;\n }\n\n // 注册自定义补全提供者\n this.registerCustomCompletionProviders();\n\n // 创建编辑器\n this.editor = this.monaco.editor.create(this.options.container, {\n value: value ?? '',\n language: language ?? 'typescript',\n theme: theme ?? 'vs-dark',\n fontSize: 14,\n minimap: { enabled: true },\n scrollBeyondLastLine: false,\n automaticLayout: true,\n lineNumbers: 'on',\n renderLineHighlight: 'all',\n smoothScrolling: true,\n cursorBlinking: 'smooth',\n bracketPairColorization: { enabled: true },\n tabSize: 2,\n wordWrap: 'on',\n folding: true,\n formatOnPaste: true,\n suggestOnTriggerCharacters: true,\n quickSuggestions: { other: true, comments: false, strings: false },\n acceptSuggestionOnCommitCharacter: true,\n acceptSuggestionOnEnter: 'on',\n inlineSuggest: { enabled: true },\n tabCompletion: 'on',\n ...editorOptions,\n });\n\n // 绑定事件\n this.bindEditorEvents();\n this.emit('ready', { editor: this.editor });\n }\n\n private bindEditorEvents(): void {\n const editor = this.editor!;\n\n const d1 = editor.onDidChangeModelContent(() => {\n this.emit('change', { value: editor.getValue() });\n });\n\n const d2 = editor.onDidChangeCursorPosition((e) => {\n this.emit('cursor', {\n line: e.position.lineNumber,\n column: e.position.column,\n });\n });\n\n const d3 = editor.onDidFocusEditorText(() => this.emit('focus', undefined));\n const d4 = editor.onDidBlurEditorText(() => this.emit('blur', undefined));\n\n this.disposables.push(d1, d2, d3, d4);\n }\n\n private registerCustomCompletionProviders(): void {\n if (this.customProviders.length === 0) return;\n\n for (const provider of this.customProviders) {\n const langs = provider.languages ?? ['*'];\n for (const lang of langs) {\n this.monaco.languages.registerCompletionItemProvider(lang, {\n triggerCharacters: provider.triggerCharacters,\n provideCompletionItems: async (model, position, context) => {\n const ctx = {\n monaco: this.monaco,\n model,\n position,\n lineText: model.getLineContent(position.lineNumber),\n currentWord: model.getWordUntilPosition(position).word,\n fullText: model.getValue(),\n triggerCharacter: context.triggerCharacter,\n };\n\n if (provider.shouldTrigger && !provider.shouldTrigger(ctx)) {\n return { suggestions: [] };\n }\n\n const suggestions = await provider.provide(ctx);\n return { suggestions };\n },\n });\n }\n }\n }\n\n // ─── 公开 API ──────────────────────────────────────────────────────────\n\n getEditor(): MonacoType.editor.IStandaloneCodeEditor | null {\n return this.editor;\n }\n\n getValue(): string {\n return this.editor?.getValue() ?? '';\n }\n\n setValue(value: string): void {\n this.editor?.setValue(value);\n }\n\n insertText(text: string, range?: MonacoType.IRange): void {\n const editor = this.editor;\n if (!editor) return;\n const targetRange = range ?? editor.getSelection();\n if (targetRange) {\n editor.executeEdits('controller-insert', [{ range: targetRange, text }]);\n editor.focus();\n }\n }\n\n format(): void {\n this.editor?.getAction('editor.action.formatDocument')?.run();\n }\n\n focus(): void {\n this.editor?.focus();\n }\n\n setLanguage(language: string): void {\n const model = this.editor?.getModel();\n if (model) {\n this.monaco.editor.setModelLanguage(model, language);\n this.emit('languageChange', { language });\n }\n }\n\n setTheme(theme: string): void {\n this.monaco.editor.setTheme(theme);\n }\n\n getCursorPosition(): { line: number; column: number } {\n const pos = this.editor?.getPosition();\n return pos\n ? { line: pos.lineNumber, column: pos.column }\n : { line: 1, column: 1 };\n }\n\n getSelection(): MonacoType.IRange | null {\n return this.editor?.getSelection() ?? null;\n }\n\n /**\n * 触发 AI 行内补全(Ctrl+Alt+L 快捷键)。\n * 需要提前设置 apiConfig(通过 setApiConfig 或构造函数传入)。\n */\n setApiConfig(config: ApiConfig | null): void {\n this.options.apiConfig = config;\n }\n\n getPendingCompletionRef(): { current: PendingCompletion | null } {\n return this.pendingCompletionRef;\n }\n\n dispose(): void {\n for (const d of this.disposables) d.dispose();\n this.disposables = [];\n this.editor?.dispose();\n this.editor = null;\n this.removeAllListeners();\n }\n}","import { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, ChatMessage } from '../types';\n\nexport interface AiChatControllerEvents {\n messageAdded: ChatMessage;\n messageUpdated: ChatMessage;\n cleared: void;\n loadingChange: { loading: boolean };\n error: { message: string };\n}\n\nfunction generateUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * AI 聊天控制器:管理消息列表、API 调用与流式响应。\n * 框架无关:通过事件通知 UI 层更新。\n */\nexport class AiChatController extends EventEmitter<AiChatControllerEvents> {\n private messages: ChatMessage[] = [];\n private abortController: AbortController | null = null;\n private loading = false;\n private apiConfig: ApiConfig;\n\n constructor(apiConfig: ApiConfig) {\n super();\n this.apiConfig = apiConfig;\n }\n\n setApiConfig(config: ApiConfig): void {\n this.apiConfig = config;\n }\n\n getApiConfig(): ApiConfig {\n return this.apiConfig;\n }\n\n getMessages(): readonly ChatMessage[] {\n return this.messages;\n }\n\n isLoading(): boolean {\n return this.loading;\n }\n\n /** 发送消息,可选携带编辑器上下文 */\n async send(\n userInput: string,\n options?: { editorContent?: string; language?: string },\n ): Promise<void> {\n const trimmed = userInput.trim();\n if (!trimmed || this.loading) return;\n\n if (!this.apiConfig.apiKey.trim()) {\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '⚠️ 尚未配置 API Key,请配置 Base URL、API Key 和模型名称后再开始对话。',\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n return;\n }\n\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '',\n isStreaming: true,\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n\n this.loading = true;\n this.emit('loadingChange', { loading: true });\n\n try {\n this.abortController = new AbortController();\n\n const systemPrompt = options?.language\n ? `You are an expert coding assistant. The user is working with ${options.language} code. Respond concisely in the same language as the user's message, defaulting to Chinese.`\n : \"You are an expert coding assistant. Respond concisely in the same language as the user's message, defaulting to Chinese.\";\n\n const historyForApi = this.messages\n .filter((m) => m.id !== assistantMsg.id)\n .map((m) => ({ role: m.role, content: m.content }));\n\n const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiConfig.apiKey}`,\n },\n body: JSON.stringify({\n model: this.apiConfig.model,\n messages: [{ role: 'system', content: systemPrompt }, ...historyForApi],\n stream: true,\n }),\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n let errText = '';\n try {\n errText = await response.text();\n } catch {\n /* ignore */\n }\n let hint = '';\n if (response.status === 401) hint = '(API Key 无效或已过期)';\n else if (response.status === 403) hint = '(无访问权限,请检查 API Key 和 Base URL)';\n else if (response.status === 429) hint = '(请求过于频繁,请稍后再试)';\n else if (response.status >= 500) hint = '(服务端错误)';\n throw new Error(`HTTP ${response.status}${hint}${errText ? `\\n${errText}` : ''}`);\n }\n\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let fullContent = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6).trim();\n if (data === '[DONE]') break;\n try {\n const parsed = JSON.parse(data) as {\n choices?: Array<{ delta?: { content?: string } }>;\n };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n fullContent += delta;\n assistantMsg.content = fullContent;\n this.emit('messageUpdated', { ...assistantMsg });\n }\n } catch {\n /* ignore */\n }\n }\n }\n\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n } catch (err: unknown) {\n const isAbort = err instanceof Error && err.name === 'AbortError';\n const errMsg = err instanceof Error ? err.message : String(err);\n const isNetworkErr = err instanceof TypeError && errMsg.toLowerCase().includes('fetch');\n const errorContent = isAbort\n ? '⏹ 请求已取消'\n : isNetworkErr\n ? `⚠️ 网络错误,请检查 Base URL 和网络。\\n\\n${errMsg}`\n : `⚠️ 请求失败:${errMsg}`;\n assistantMsg.content = errorContent;\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n if (!isAbort) this.emit('error', { message: errMsg });\n } finally {\n this.loading = false;\n this.emit('loadingChange', { loading: false });\n }\n }\n\n stop(): void {\n this.abortController?.abort();\n }\n\n clear(): void {\n this.messages = [];\n this.emit('cleared', undefined);\n }\n\n dispose(): void {\n this.abortController?.abort();\n this.removeAllListeners();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport type { EditorController } from '../controllers/EditorController';\nimport type { AiChatController } from '../controllers/AiChatController';\n\nexport interface EditorBusEvents {\n /** 编辑器已注册 */\n 'editor:ready': EditorController;\n /** 编辑器即将卸载 */\n 'editor:dispose': void;\n /** 编辑器内容变化 */\n 'editor:change': { value: string };\n /** 编辑器光标变化 */\n 'editor:cursor': { line: number; column: number };\n /** 编辑器语言变化 */\n 'editor:languageChange': { language: string };\n\n /** 聊天面板已注册 */\n 'chat:ready': AiChatController;\n /** 聊天面板卸载 */\n 'chat:dispose': void;\n /** 聊天面板请求向编辑器插入代码 */\n 'chat:insertCode': { code: string };\n /** 聊天面板请求替换编辑器全部内容 */\n 'chat:replaceCode': { code: string };\n}\n\n/**\n * 编辑器与聊天面板的通信总线。\n * 在两个组件都引入时由协调器(Coordinator)创建并共享,实现自动联动。\n * 当只引入其中一个组件时,bus 可为 null,组件正常独立工作。\n */\nexport class EditorBus extends EventEmitter<EditorBusEvents> {\n private editor: EditorController | null = null;\n private chat: AiChatController | null = null;\n\n registerEditor(controller: EditorController): () => void {\n this.editor = controller;\n\n // 桥接:编辑器事件 → bus 事件\n const offChange = controller.on('change', (data) => this.emit('editor:change', data));\n const offCursor = controller.on('cursor', (data) => this.emit('editor:cursor', data));\n const offLang = controller.on('languageChange', (data) => this.emit('editor:languageChange', data));\n\n // 桥接:bus 上的 chat 命令 → 编辑器操作\n const offInsert = this.on('chat:insertCode', ({ code }) => controller.insertText(code));\n const offReplace = this.on('chat:replaceCode', ({ code }) => controller.setValue(code));\n\n this.emit('editor:ready', controller);\n\n return () => {\n offChange();\n offCursor();\n offLang();\n offInsert();\n offReplace();\n if (this.editor === controller) {\n this.editor = null;\n this.emit('editor:dispose', undefined);\n }\n };\n }\n\n registerChat(controller: AiChatController): () => void {\n this.chat = controller;\n this.emit('chat:ready', controller);\n return () => {\n if (this.chat === controller) {\n this.chat = null;\n this.emit('chat:dispose', undefined);\n }\n };\n }\n\n getEditor(): EditorController | null {\n return this.editor;\n }\n\n getChat(): AiChatController | null {\n return this.chat;\n }\n\n /** 让聊天面板向编辑器请求当前内容 */\n getEditorContent(): string {\n return this.editor?.getValue() ?? '';\n }\n\n /** 让聊天面板向编辑器请求当前语言 */\n getEditorLanguage(): string | undefined {\n const editor = this.editor?.getEditor();\n return editor?.getModel()?.getLanguageId();\n }\n\n /** 让聊天面板请求向编辑器插入代码 */\n insertToEditor(code: string): void {\n this.emit('chat:insertCode', { code });\n }\n\n /** 让聊天面板请求替换编辑器全部内容 */\n replaceEditor(code: string): void {\n this.emit('chat:replaceCode', { code });\n }\n}\n"],"mappings":"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","names":["schema","userMsg","assistantMsg"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/bus/EventEmitter.ts","../src/completion/sqlCompletion.ts","../src/ai/aiCompletion.ts","../src/controllers/EditorController.ts","../src/controllers/AiChatController.ts","../src/bus/EditorBus.ts"],"sourcesContent":["// ─── 类型 ──────────────────────────────────────────────────────────────\nexport type {\n ApiConfig,\n ScenarioOverrides,\n SqlSchema,\n PendingCompletion,\n ChatMessage,\n EditorSnapshot,\n CompletionContext,\n CompletionProvider,\n} from './types';\n\n// ─── 常量 ──────────────────────────────────────────────────────────────\nexport {\n SQL_KEYWORDS,\n SQL_FUNCTIONS,\n SQL_DATA_TYPES,\n LANGUAGES,\n THEMES,\n AI_INLINE_LANGUAGES,\n LOCALES,\n type Locale,\n} from './constants';\n\n// ─── 控制器 ────────────────────────────────────────────────────────────\nexport {\n EditorController,\n type EditorControllerOptions,\n type EditorControllerEvents,\n} from './controllers/EditorController';\n\nexport {\n AiChatController,\n type AiChatControllerEvents,\n} from './controllers/AiChatController';\n\n// ─── 总线 ──────────────────────────────────────────────────────────────\nexport { EditorBus, type EditorBusEvents } from './bus/EditorBus';\nexport { EventEmitter, type Listener } from './bus/EventEmitter';\n\n// ─── 补全 / AI ────────────────────────────────────────────────────────\nexport { registerSqlCompletion } from './completion/sqlCompletion';\nexport {\n registerAiInlineCompletion,\n registerAiCompletionCommand,\n fetchAiCompletionStream,\n fetchAiCompletionNonStream,\n} from './ai/aiCompletion';\n","export const SQL_KEYWORDS = [\n 'SELECT', 'FROM', 'WHERE', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE',\n 'CREATE', 'TABLE', 'DROP', 'ALTER', 'ADD', 'COLUMN', 'INDEX', 'VIEW', 'DATABASE',\n 'SCHEMA', 'TRUNCATE', 'RENAME', 'AS', 'ON', 'JOIN', 'INNER', 'LEFT', 'RIGHT',\n 'FULL', 'OUTER', 'CROSS', 'NATURAL', 'USING', 'AND', 'OR', 'NOT', 'IN', 'EXISTS',\n 'BETWEEN', 'LIKE', 'IS', 'NULL', 'TRUE', 'FALSE', 'CASE', 'WHEN', 'THEN', 'ELSE',\n 'END', 'IF', 'UNION', 'ALL', 'DISTINCT', 'ORDER', 'BY', 'ASC', 'DESC', 'GROUP',\n 'HAVING', 'LIMIT', 'OFFSET', 'FETCH', 'NEXT', 'ROWS', 'ONLY', 'WITH', 'RECURSIVE',\n 'PRIMARY', 'KEY', 'FOREIGN', 'REFERENCES', 'UNIQUE', 'NOT NULL', 'DEFAULT',\n 'CHECK', 'CONSTRAINT', 'AUTO_INCREMENT', 'IDENTITY', 'SEQUENCE', 'GRANT',\n 'REVOKE', 'COMMIT', 'ROLLBACK', 'TRANSACTION', 'BEGIN', 'SAVEPOINT', 'EXPLAIN',\n];\n\nexport const SQL_FUNCTIONS = [\n 'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'COALESCE', 'NULLIF', 'IFNULL', 'NVL',\n 'CONCAT', 'LENGTH', 'SUBSTR', 'SUBSTRING', 'TRIM', 'LTRIM', 'RTRIM', 'UPPER',\n 'LOWER', 'REPLACE', 'INSTR', 'LPAD', 'RPAD', 'CHAR_LENGTH', 'POSITION',\n 'NOW', 'CURDATE', 'CURTIME', 'DATE', 'TIME', 'YEAR', 'MONTH', 'DAY',\n 'HOUR', 'MINUTE', 'SECOND', 'DATEDIFF', 'DATE_ADD', 'DATE_SUB', 'DATEADD',\n 'DATESUB', 'EXTRACT', 'TO_DATE', 'TO_CHAR', 'DATE_FORMAT', 'TIMESTAMPDIFF',\n 'ROUND', 'CEIL', 'FLOOR', 'ABS', 'MOD', 'POWER', 'SQRT', 'SIGN', 'RAND',\n 'CAST', 'CONVERT', 'ROW_NUMBER', 'RANK', 'DENSE_RANK', 'NTILE', 'LAG', 'LEAD',\n 'FIRST_VALUE', 'LAST_VALUE', 'OVER', 'PARTITION', 'LISTAGG', 'GROUP_CONCAT',\n 'STRING_AGG', 'JSON_OBJECT', 'JSON_ARRAY', 'JSON_EXTRACT', 'ISNULL',\n];\n\nexport const SQL_DATA_TYPES = [\n 'INT', 'INTEGER', 'BIGINT', 'SMALLINT', 'TINYINT', 'DECIMAL', 'NUMERIC',\n 'FLOAT', 'DOUBLE', 'REAL', 'CHAR', 'VARCHAR', 'TEXT', 'NCHAR', 'NVARCHAR',\n 'NTEXT', 'DATE', 'TIME', 'DATETIME', 'TIMESTAMP', 'BOOLEAN', 'BOOL',\n 'BLOB', 'CLOB', 'BINARY', 'VARBINARY', 'JSON', 'UUID', 'SERIAL',\n];\n\nexport const LANGUAGES = [\n 'javascript',\n 'typescript',\n 'python',\n 'json',\n 'css',\n 'html',\n 'markdown',\n 'rust',\n 'go',\n 'sql',\n] as const;\n\n/** Monaco 编辑器支持的 UI 本地化语言 */\nexport const LOCALES = {\n ZH_CN: 'zh-cn',\n EN: 'en',\n DE: 'de',\n ES: 'es',\n FR: 'fr',\n IT: 'it',\n JA: 'ja',\n KO: 'ko',\n RU: 'ru',\n} as const;\n\nexport type Locale = (typeof LOCALES)[keyof typeof LOCALES];\n\nexport const THEMES = [\n { value: 'vs-dark', label: 'Dark' },\n { value: 'light', label: 'Light' },\n { value: 'hc-black', label: 'High Contrast' },\n] as const;\n\nexport const AI_INLINE_LANGUAGES = [\n 'typescript', 'javascript', 'python', 'sql',\n 'java', 'cpp', 'csharp', 'go', 'rust',\n];\n","/**\n * 极简事件发射器,框架无关。\n * 用于 EditorController / AiChatController / EditorBus 之间的事件通信。\n */\nexport type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<EventMap> {\n private listeners: { [K in keyof EventMap]?: Set<Listener<EventMap[K]>> } = {};\n\n on<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): () => void {\n if (!this.listeners[event]) this.listeners[event] = new Set();\n this.listeners[event]!.add(listener);\n return () => this.off(event, listener);\n }\n\n off<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): void {\n this.listeners[event]?.delete(listener);\n }\n\n emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.listeners[event]?.forEach((listener) => {\n try {\n listener(payload);\n } catch (err) {\n console.error(`[EventEmitter] listener for \"${String(event)}\" threw:`, err);\n }\n });\n }\n\n removeAllListeners(): void {\n this.listeners = {};\n }\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { SQL_KEYWORDS, SQL_FUNCTIONS, SQL_DATA_TYPES } from '../constants';\nimport type { SqlSchema } from '../types';\n\n/** 从 SQL 文档中动态解析表名、CTE 别名和变量 */\nfunction parseDynamicItems(sql: string): { tables: string[]; variables: string[] } {\n const tables: string[] = [];\n const variables: string[] = [];\n let m: RegExpExecArray | null;\n\n const tableRe = /\\b(?:FROM|JOIN|UPDATE|INTO|TABLE)\\s+([`\"']?\\w+[`\"']?)/gi;\n while ((m = tableRe.exec(sql)) !== null) {\n const name = m[1].replace(/[`\"']/g, '');\n if (!tables.includes(name)) tables.push(name);\n }\n\n const cteRe = /\\bWITH\\s+(\\w+)\\s+AS\\s*\\(/gi;\n while ((m = cteRe.exec(sql)) !== null) {\n if (!tables.includes(m[1])) tables.push(m[1]);\n }\n\n const declareRe = /\\bDECLARE\\s+(@?\\w+)/gi;\n while ((m = declareRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const setVarRe = /\\bSET\\s+(@\\w+)\\s*=/gi;\n while ((m = setVarRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const atVarRe = /@(\\w+)/g;\n while ((m = atVarRe.exec(sql)) !== null) {\n const v = `@${m[1]}`;\n if (!variables.includes(v)) variables.push(v);\n }\n\n return { tables, variables };\n}\n\n/**\n * 注册 SQL 内置补全提供者。\n * schemaRef 使用 ref 模式以支持动态更新。\n * excludeLabelsRef(可选)使用 ref 模式,提供需要从内置关键字/函数中排除的 label\n * (大写匹配)。用于让使用方的自定义词表覆盖内置同名项,避免重复提示。\n */\nexport function registerSqlCompletion(\n monaco: typeof MonacoType,\n schemaRef: { readonly current: SqlSchema },\n excludeLabelsRef?: { readonly current: Set<string> },\n): MonacoType.IDisposable {\n return monaco.languages.registerCompletionItemProvider('sql', {\n triggerCharacters: ['.'],\n provideCompletionItems(model, position, context) {\n const word = model.getWordUntilPosition(position);\n const range: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: word.startColumn,\n endColumn: word.endColumn,\n };\n\n // 点号触发:提示该表的列名\n if (context.triggerCharacter === '.') {\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforeDot = lineText.substring(0, position.column - 2);\n const tableMatch = textBeforeDot.match(/(\\w+)$/);\n if (tableMatch) {\n const typed = tableMatch[1].toUpperCase();\n const schema = schemaRef.current;\n const tableKey = Object.keys(schema).find((k) => k.toUpperCase() === typed);\n if (tableKey) {\n const colRange: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n };\n return {\n suggestions: schema[tableKey].map((col) => ({\n label: col,\n kind: monaco.languages.CompletionItemKind.Field,\n insertText: col,\n range: colRange,\n detail: `${tableKey} · 列`,\n documentation: `表 ${tableKey} 的字段`,\n })),\n };\n }\n }\n return { suggestions: [] };\n }\n\n // 普通触发:关键字 + 函数 + 类型 + 表名 + 变量\n const fullText = model.getValue();\n const { tables: dynamicTables, variables } = parseDynamicItems(fullText);\n const schema = schemaRef.current;\n const schemaTables = Object.keys(schema);\n const allTables = [...new Set([...schemaTables, ...dynamicTables])];\n\n // 需要排除的内置 label(大写匹配),让使用方自定义词表覆盖同名项\n const exclude = excludeLabelsRef?.current;\n const isExcluded = (label: string) => exclude?.has(label.toUpperCase()) ?? false;\n\n const keywords = SQL_KEYWORDS.filter((kw) => !isExcluded(kw)).map((kw) => ({\n label: kw,\n kind: monaco.languages.CompletionItemKind.Keyword,\n insertText: kw,\n range,\n detail: 'SQL 关键字',\n }));\n\n const functions = SQL_FUNCTIONS.filter((fn) => !isExcluded(fn)).map((fn) => ({\n label: fn,\n kind: monaco.languages.CompletionItemKind.Function,\n insertText: `${fn}($1)`,\n insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n range,\n detail: 'SQL 函数',\n }));\n\n const dataTypes = SQL_DATA_TYPES.map((dt) => ({\n label: dt,\n kind: monaco.languages.CompletionItemKind.TypeParameter,\n insertText: dt,\n range,\n detail: 'SQL 数据类型',\n }));\n\n const tableItems = allTables.map((t) => ({\n label: t,\n kind: monaco.languages.CompletionItemKind.Class,\n insertText: t,\n range,\n detail: schemaTables.includes(t) ? '表名 (Schema)' : '表名 (文档)',\n }));\n\n const variableItems = variables.map((v) => ({\n label: v,\n kind: monaco.languages.CompletionItemKind.Variable,\n insertText: v,\n range,\n detail: 'SQL 变量',\n }));\n\n return {\n suggestions: [...keywords, ...functions, ...dataTypes, ...tableItems, ...variableItems],\n };\n },\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport type { ApiConfig, PendingCompletion } from '../types';\nimport { AI_INLINE_LANGUAGES } from '../constants';\n\n/** 去除模型返回中可能包含的代码围栏(```lang ... ```) */\nfunction stripCodeFence(text: string): string {\n return text.replace(/^```[a-z]*\\n?/, '').replace(/\\n?```$/, '');\n}\n\nconst SPINNER_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'] as const;\n\nfunction ensureSpinnerStyle() {\n const id = 'mae-ai-completion-spinner-style';\n if (typeof document === 'undefined' || document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n const frameCss = SPINNER_FRAMES.map((ch, i) => `.mae-ai-spinner-f${i}::after { content: \" ${ch}\"; }`).join('\\n');\n style.textContent = `\n@keyframes mae-ai-completion-glow {\n 0%, 100% { text-shadow: 0 0 3px rgba(96, 165, 250, 0.35); }\n 50% { text-shadow: 0 0 9px rgba(96, 165, 250, 0.95), 0 0 18px rgba(59, 130, 246, 0.35); }\n}\n${frameCss}\n[class^=\"mae-ai-spinner-f\"]::after {\n color: #60a5fa;\n font-family: \"Segoe UI Symbol\", \"Noto Sans Symbols\", \"Apple Symbols\", monospace;\n display: inline-block;\n margin-left: 2px;\n animation: mae-ai-completion-glow 1s ease-in-out infinite;\n}`;\n document.head.appendChild(style);\n}\n\nfunction createCursorSpinner(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n line: number,\n col: number,\n): () => void {\n ensureSpinnerStyle();\n let frameIdx = 0;\n const makeDecor = () => [{\n range: { startLineNumber: line, startColumn: col, endLineNumber: line, endColumn: col },\n options: { afterContentClassName: `mae-ai-spinner-f${frameIdx}` },\n }];\n const collection = editor.createDecorationsCollection(makeDecor());\n const timer = setInterval(() => {\n frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;\n collection.set(makeDecor());\n }, 80);\n return () => {\n clearInterval(timer);\n collection.clear();\n };\n}\n\n/** 默认 system prompt:行内补全 */\nconst DEFAULT_COMPLETION_SYSTEM = '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。';\n\n/** 构建行内补全请求体:读 config.completion 覆盖,默认思考关闭、max_tokens 512 */\nfunction buildRequestBody(\n config: ApiConfig,\n context: string,\n prefix: string,\n stream: boolean,\n): Record<string, unknown> {\n const ov = config.completion ?? {};\n // 思考开关优先级:completion.thinking > 顶层 thinking > 默认 disabled\n const thinking = ov.thinking ?? config.thinking ?? { type: 'disabled' as const };\n const body: Record<string, unknown> = {\n model: ov.model ?? config.model,\n messages: [\n { role: 'system', content: ov.systemPrompt ?? DEFAULT_COMPLETION_SYSTEM },\n { role: 'user', content: `代码上下文:\\n${context}\\n\\n前缀:${prefix}\\n\\n请继续补全这段代码,只返回补全部分。` },\n ],\n max_tokens: ov.maxTokens ?? 512,\n stream,\n };\n body.thinking = thinking;\n if (ov.temperature !== undefined) body.temperature = ov.temperature;\n return body;\n}\n\n/** 非流式调用 OpenAI 兼容 API(使用原生 fetch,无 axios 依赖) */\nexport async function fetchAiCompletionNonStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n signal?: AbortSignal,\n): Promise<string> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify(buildRequestBody(config, context, prefix, false)),\n signal,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n const data = (await response.json()) as { choices?: Array<{ message?: { content?: string } }> };\n return stripCodeFence(data.choices?.[0]?.message?.content?.trim() ?? '');\n}\n\n/** 流式调用(fetch + ReadableStream) */\nexport async function fetchAiCompletionStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n onChunk: (accumulated: string) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify(buildRequestBody(config, context, prefix, true)),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n if (!response.body) throw new Error('Response body is null');\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let accumulated = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data:')) continue;\n const data = trimmed.slice(5).trim();\n if (data === '[DONE]') return;\n try {\n const parsed = JSON.parse(data) as { choices?: Array<{ delta?: { content?: string } }> };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n accumulated += delta;\n onChunk(accumulated);\n }\n } catch {\n // ignore malformed lines\n }\n }\n }\n}\n\n/** 注册 AI 内联幽灵文本提供者 */\nexport function registerAiInlineCompletion(\n monaco: typeof MonacoType,\n pendingRef: { current: PendingCompletion | null },\n): void {\n AI_INLINE_LANGUAGES.forEach((lang) => {\n monaco.languages.registerInlineCompletionsProvider(lang, {\n provideInlineCompletions: (_model, position) => {\n const pending = pendingRef.current;\n if (!pending) return { items: [] };\n if (pending.lineNumber !== position.lineNumber || pending.column !== position.column) {\n pendingRef.current = null;\n return { items: [] };\n }\n return {\n items: [\n {\n insertText: pending.insertText,\n range: {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n },\n },\n ],\n };\n },\n disposeInlineCompletions: () => {},\n });\n });\n}\n\n/**\n * 注册 AI 补全命令(Ctrl+Alt+L 手动触发,流式更新幽灵文本)。\n * 框架无关:通过函数引用方式读取最新的 apiConfig。\n */\nexport function registerAiCompletionCommand(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n getApiConfig: () => ApiConfig | null,\n pendingRef: { current: PendingCompletion | null },\n onLoadingChange?: (loading: boolean) => void,\n onError?: (message: string) => void,\n): MonacoType.IDisposable {\n let currentAbortController: AbortController | null = null;\n\n const isAbortError = (err: unknown): boolean =>\n err instanceof Error && (err.name === 'AbortError' || err.message?.includes('aborted'));\n\n const triggerAiCompletion = async () => {\n const apiConfig = getApiConfig();\n if (!apiConfig || !apiConfig.apiKey.trim()) {\n onError?.('未配置 API Key,请先配置 AI 服务再使用补全功能。');\n return;\n }\n\n const position = editor.getPosition();\n if (!position) return;\n const model = editor.getModel();\n if (!model) return;\n\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforePosition = lineText.substring(0, position.column - 1);\n if (!textBeforePosition.trim()) return;\n\n const startLine = Math.max(0, position.lineNumber - 5);\n const contextLines: string[] = [];\n for (let i = startLine; i < position.lineNumber; i++) {\n contextLines.push(model.getLineContent(i + 1));\n }\n const contextCode = contextLines.join('\\n');\n\n currentAbortController?.abort();\n currentAbortController = new AbortController();\n pendingRef.current = null;\n\n const stopSpinner = createCursorSpinner(editor, position.lineNumber, position.column);\n onLoadingChange?.(true);\n\n const useStream = apiConfig.streamMode !== false;\n\n try {\n if (useStream) {\n let triggerTimer: ReturnType<typeof setTimeout> | null = null;\n const scheduleTrigger = () => {\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n triggerTimer = setTimeout(() => {\n triggerTimer = null;\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n }, 80);\n };\n\n await fetchAiCompletionStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n (accumulated) => {\n let insertText = stripCodeFence(accumulated);\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n scheduleTrigger();\n },\n currentAbortController.signal,\n );\n\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } else {\n const completion = await fetchAiCompletionNonStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n currentAbortController.signal,\n );\n if (!completion) return;\n let insertText = completion;\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } catch (err) {\n if (isAbortError(err)) return;\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(`AI 补全失败:${msg}`);\n console.error('[AI Completion] Error:', err);\n } finally {\n stopSpinner();\n onLoadingChange?.(false);\n }\n };\n\n return editor.onKeyDown((e) => {\n if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === 'KeyL') {\n e.preventDefault();\n void triggerAiCompletion();\n }\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, PendingCompletion, SqlSchema, CompletionProvider } from '../types';\nimport { registerSqlCompletion } from '../completion/sqlCompletion';\nimport { registerAiInlineCompletion } from '../ai/aiCompletion';\n\nexport interface EditorControllerEvents {\n change: { value: string };\n cursor: { line: number; column: number };\n ready: { editor: MonacoType.editor.IStandaloneCodeEditor };\n languageChange: { language: string };\n focus: void;\n blur: void;\n}\n\nexport interface EditorControllerOptions {\n container: HTMLElement;\n language?: string;\n theme?: string;\n value?: string;\n monaco: typeof MonacoType;\n /** Monaco loader monaco-editor 路径配置 */\n vsPath?: string;\n sqlSchema?: SqlSchema;\n apiConfig?: ApiConfig | null;\n completionProviders?: CompletionProvider[];\n /** Monaco editor options */\n editorOptions?: MonacoType.editor.IStandaloneEditorConstructionOptions;\n}\n\n/**\n * 框架无关的编辑器控制器。\n * 封装 Monaco 实例的生命周期、核心操作、补全注册。\n * 通过 EventEmitter 暴露编辑器事件,不依赖任何 UI 框架。\n */\nexport class EditorController extends EventEmitter<EditorControllerEvents> {\n private editor: MonacoType.editor.IStandaloneCodeEditor | null = null;\n private monaco: typeof MonacoType;\n private sqlProviderRegistered = false;\n private aiProviderRegistered = false;\n private pendingCompletionRef = { current: null as PendingCompletion | null };\n private customProviders: CompletionProvider[] = [];\n private disposables: MonacoType.IDisposable[] = [];\n\n completed = false;\n error: Error | null = null;\n\n constructor(private options: EditorControllerOptions) {\n super();\n this.monaco = options.monaco;\n this.customProviders = options.completionProviders ?? [];\n this.init();\n }\n\n private init(): void {\n const { language, theme, value, sqlSchema, apiConfig, editorOptions } = this.options;\n\n // 注册 SQL 补全(只注册一次)\n if (!this.sqlProviderRegistered) {\n const schemaRef = { current: sqlSchema ?? {} };\n registerSqlCompletion(this.monaco, schemaRef);\n this.sqlProviderRegistered = true;\n }\n\n // 注册 AI 幽灵文本提供者\n if (!this.aiProviderRegistered) {\n registerAiInlineCompletion(this.monaco, this.pendingCompletionRef);\n this.aiProviderRegistered = true;\n }\n\n // 注册自定义补全提供者\n this.registerCustomCompletionProviders();\n\n // 创建编辑器\n this.editor = this.monaco.editor.create(this.options.container, {\n value: value ?? '',\n language: language ?? 'typescript',\n theme: theme ?? 'vs-dark',\n fontSize: 14,\n minimap: { enabled: true },\n scrollBeyondLastLine: false,\n automaticLayout: true,\n lineNumbers: 'on',\n renderLineHighlight: 'all',\n smoothScrolling: true,\n cursorBlinking: 'smooth',\n bracketPairColorization: { enabled: true },\n tabSize: 2,\n wordWrap: 'on',\n folding: true,\n formatOnPaste: true,\n suggestOnTriggerCharacters: true,\n quickSuggestions: { other: true, comments: false, strings: false },\n acceptSuggestionOnCommitCharacter: true,\n acceptSuggestionOnEnter: 'on',\n inlineSuggest: { enabled: true },\n tabCompletion: 'on',\n ...editorOptions,\n });\n\n // 绑定事件\n this.bindEditorEvents();\n this.emit('ready', { editor: this.editor });\n }\n\n private bindEditorEvents(): void {\n const editor = this.editor!;\n\n const d1 = editor.onDidChangeModelContent(() => {\n this.emit('change', { value: editor.getValue() });\n });\n\n const d2 = editor.onDidChangeCursorPosition((e) => {\n this.emit('cursor', {\n line: e.position.lineNumber,\n column: e.position.column,\n });\n });\n\n const d3 = editor.onDidFocusEditorText(() => this.emit('focus', undefined));\n const d4 = editor.onDidBlurEditorText(() => this.emit('blur', undefined));\n\n this.disposables.push(d1, d2, d3, d4);\n }\n\n private registerCustomCompletionProviders(): void {\n if (this.customProviders.length === 0) return;\n\n for (const provider of this.customProviders) {\n const langs = provider.languages ?? ['*'];\n for (const lang of langs) {\n this.monaco.languages.registerCompletionItemProvider(lang, {\n triggerCharacters: provider.triggerCharacters,\n provideCompletionItems: async (model, position, context) => {\n const ctx = {\n monaco: this.monaco,\n model,\n position,\n lineText: model.getLineContent(position.lineNumber),\n currentWord: model.getWordUntilPosition(position).word,\n fullText: model.getValue(),\n triggerCharacter: context.triggerCharacter,\n };\n\n if (provider.shouldTrigger && !provider.shouldTrigger(ctx)) {\n return { suggestions: [] };\n }\n\n const suggestions = await provider.provide(ctx);\n return { suggestions };\n },\n });\n }\n }\n }\n\n // ─── 公开 API ──────────────────────────────────────────────────────────\n\n getEditor(): MonacoType.editor.IStandaloneCodeEditor | null {\n return this.editor;\n }\n\n getValue(): string {\n return this.editor?.getValue() ?? '';\n }\n\n setValue(value: string): void {\n this.editor?.setValue(value);\n }\n\n insertText(text: string, range?: MonacoType.IRange): void {\n const editor = this.editor;\n if (!editor) return;\n const targetRange = range ?? editor.getSelection();\n if (targetRange) {\n editor.executeEdits('controller-insert', [{ range: targetRange, text }]);\n editor.focus();\n }\n }\n\n format(): void {\n this.editor?.getAction('editor.action.formatDocument')?.run();\n }\n\n focus(): void {\n this.editor?.focus();\n }\n\n setLanguage(language: string): void {\n const model = this.editor?.getModel();\n if (model) {\n this.monaco.editor.setModelLanguage(model, language);\n this.emit('languageChange', { language });\n }\n }\n\n setTheme(theme: string): void {\n this.monaco.editor.setTheme(theme);\n }\n\n getCursorPosition(): { line: number; column: number } {\n const pos = this.editor?.getPosition();\n return pos\n ? { line: pos.lineNumber, column: pos.column }\n : { line: 1, column: 1 };\n }\n\n getSelection(): MonacoType.IRange | null {\n return this.editor?.getSelection() ?? null;\n }\n\n /**\n * 触发 AI 行内补全(Ctrl+Alt+L 快捷键)。\n * 需要提前设置 apiConfig(通过 setApiConfig 或构造函数传入)。\n */\n setApiConfig(config: ApiConfig | null): void {\n this.options.apiConfig = config;\n }\n\n getPendingCompletionRef(): { current: PendingCompletion | null } {\n return this.pendingCompletionRef;\n }\n\n dispose(): void {\n for (const d of this.disposables) d.dispose();\n this.disposables = [];\n this.editor?.dispose();\n this.editor = null;\n this.removeAllListeners();\n }\n}","import { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, ChatMessage } from '../types';\n\nexport interface AiChatControllerEvents {\n messageAdded: ChatMessage;\n messageUpdated: ChatMessage;\n cleared: void;\n loadingChange: { loading: boolean };\n error: { message: string };\n}\n\nfunction generateUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * AI 聊天控制器:管理消息列表、API 调用与流式响应。\n * 框架无关:通过事件通知 UI 层更新。\n */\nexport class AiChatController extends EventEmitter<AiChatControllerEvents> {\n private messages: ChatMessage[] = [];\n private abortController: AbortController | null = null;\n private loading = false;\n private apiConfig: ApiConfig;\n\n constructor(apiConfig: ApiConfig) {\n super();\n this.apiConfig = apiConfig;\n }\n\n setApiConfig(config: ApiConfig): void {\n this.apiConfig = config;\n }\n\n getApiConfig(): ApiConfig {\n return this.apiConfig;\n }\n\n getMessages(): readonly ChatMessage[] {\n return this.messages;\n }\n\n isLoading(): boolean {\n return this.loading;\n }\n\n /** 发送消息,可选携带编辑器上下文 */\n async send(\n userInput: string,\n options?: { editorContent?: string; language?: string },\n ): Promise<void> {\n const trimmed = userInput.trim();\n if (!trimmed || this.loading) return;\n\n if (!this.apiConfig.apiKey.trim()) {\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '⚠️ 尚未配置 API Key,请配置 Base URL、API Key 和模型名称后再开始对话。',\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n return;\n }\n\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '',\n isStreaming: true,\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n\n this.loading = true;\n this.emit('loadingChange', { loading: true });\n\n try {\n this.abortController = new AbortController();\n\n const systemPrompt = options?.language\n ? `You are an expert coding assistant. The user is working with ${options.language} code. Respond concisely in the same language as the user's message, defaulting to Chinese.`\n : \"You are an expert coding assistant. Respond concisely in the same language as the user's message, defaulting to Chinese.\";\n\n const historyForApi = this.messages\n .filter((m) => m.id !== assistantMsg.id)\n .map((m) => ({ role: m.role, content: m.content }));\n\n // 对话聊天场景级覆盖:chat.thinking > 顶层 thinking > 默认 enabled\n const chatOv = this.apiConfig.chat ?? {};\n const thinking =\n chatOv.thinking ?? this.apiConfig.thinking ?? ({ type: 'enabled' as const });\n const chatBody: Record<string, unknown> = {\n model: chatOv.model ?? this.apiConfig.model,\n messages: [\n { role: 'system', content: chatOv.systemPrompt ?? systemPrompt },\n ...historyForApi,\n ],\n max_tokens: chatOv.maxTokens ?? 4096,\n stream: true,\n thinking,\n };\n if (chatOv.temperature !== undefined) chatBody.temperature = chatOv.temperature;\n\n const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiConfig.apiKey}`,\n },\n body: JSON.stringify(chatBody),\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n let errText = '';\n try {\n errText = await response.text();\n } catch {\n /* ignore */\n }\n let hint = '';\n if (response.status === 401) hint = '(API Key 无效或已过期)';\n else if (response.status === 403) hint = '(无访问权限,请检查 API Key 和 Base URL)';\n else if (response.status === 429) hint = '(请求过于频繁,请稍后再试)';\n else if (response.status >= 500) hint = '(服务端错误)';\n throw new Error(`HTTP ${response.status}${hint}${errText ? `\\n${errText}` : ''}`);\n }\n\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let fullContent = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6).trim();\n if (data === '[DONE]') break;\n try {\n const parsed = JSON.parse(data) as {\n choices?: Array<{ delta?: { content?: string } }>;\n };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n fullContent += delta;\n assistantMsg.content = fullContent;\n this.emit('messageUpdated', { ...assistantMsg });\n }\n } catch {\n /* ignore */\n }\n }\n }\n\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n } catch (err: unknown) {\n const isAbort = err instanceof Error && err.name === 'AbortError';\n const errMsg = err instanceof Error ? err.message : String(err);\n const isNetworkErr = err instanceof TypeError && errMsg.toLowerCase().includes('fetch');\n const errorContent = isAbort\n ? '⏹ 请求已取消'\n : isNetworkErr\n ? `⚠️ 网络错误,请检查 Base URL 和网络。\\n\\n${errMsg}`\n : `⚠️ 请求失败:${errMsg}`;\n assistantMsg.content = errorContent;\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n if (!isAbort) this.emit('error', { message: errMsg });\n } finally {\n this.loading = false;\n this.emit('loadingChange', { loading: false });\n }\n }\n\n stop(): void {\n this.abortController?.abort();\n }\n\n clear(): void {\n this.messages = [];\n this.emit('cleared', undefined);\n }\n\n dispose(): void {\n this.abortController?.abort();\n this.removeAllListeners();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport type { EditorController } from '../controllers/EditorController';\nimport type { AiChatController } from '../controllers/AiChatController';\n\nexport interface EditorBusEvents {\n /** 编辑器已注册 */\n 'editor:ready': EditorController;\n /** 编辑器即将卸载 */\n 'editor:dispose': void;\n /** 编辑器内容变化 */\n 'editor:change': { value: string };\n /** 编辑器光标变化 */\n 'editor:cursor': { line: number; column: number };\n /** 编辑器语言变化 */\n 'editor:languageChange': { language: string };\n\n /** 聊天面板已注册 */\n 'chat:ready': AiChatController;\n /** 聊天面板卸载 */\n 'chat:dispose': void;\n /** 聊天面板请求向编辑器插入代码 */\n 'chat:insertCode': { code: string };\n /** 聊天面板请求替换编辑器全部内容 */\n 'chat:replaceCode': { code: string };\n}\n\n/**\n * 编辑器与聊天面板的通信总线。\n * 在两个组件都引入时由协调器(Coordinator)创建并共享,实现自动联动。\n * 当只引入其中一个组件时,bus 可为 null,组件正常独立工作。\n */\nexport class EditorBus extends EventEmitter<EditorBusEvents> {\n private editor: EditorController | null = null;\n private chat: AiChatController | null = null;\n\n registerEditor(controller: EditorController): () => void {\n this.editor = controller;\n\n // 桥接:编辑器事件 → bus 事件\n const offChange = controller.on('change', (data) => this.emit('editor:change', data));\n const offCursor = controller.on('cursor', (data) => this.emit('editor:cursor', data));\n const offLang = controller.on('languageChange', (data) => this.emit('editor:languageChange', data));\n\n // 桥接:bus 上的 chat 命令 → 编辑器操作\n const offInsert = this.on('chat:insertCode', ({ code }) => controller.insertText(code));\n const offReplace = this.on('chat:replaceCode', ({ code }) => controller.setValue(code));\n\n this.emit('editor:ready', controller);\n\n return () => {\n offChange();\n offCursor();\n offLang();\n offInsert();\n offReplace();\n if (this.editor === controller) {\n this.editor = null;\n this.emit('editor:dispose', undefined);\n }\n };\n }\n\n registerChat(controller: AiChatController): () => void {\n this.chat = controller;\n this.emit('chat:ready', controller);\n return () => {\n if (this.chat === controller) {\n this.chat = null;\n this.emit('chat:dispose', undefined);\n }\n };\n }\n\n getEditor(): EditorController | null {\n return this.editor;\n }\n\n getChat(): AiChatController | null {\n return this.chat;\n }\n\n /** 让聊天面板向编辑器请求当前内容 */\n getEditorContent(): string {\n return this.editor?.getValue() ?? '';\n }\n\n /** 让聊天面板向编辑器请求当前语言 */\n getEditorLanguage(): string | undefined {\n const editor = this.editor?.getEditor();\n return editor?.getModel()?.getLanguageId();\n }\n\n /** 让聊天面板请求向编辑器插入代码 */\n insertToEditor(code: string): void {\n this.emit('chat:insertCode', { code });\n }\n\n /** 让聊天面板请求替换编辑器全部内容 */\n replaceEditor(code: string): void {\n this.emit('chat:replaceCode', { code });\n }\n}\n"],"mappings":"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","names":["schema","userMsg","assistantMsg"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,28 @@
1
1
  import * as MonacoType from 'monaco-editor';
2
2
 
3
+ /**
4
+ * 场景级参数覆盖(优先级高于顶层同名字段)。
5
+ * 用于让「行内补全」和「对话聊天」使用不同的模型 / 思考策略 / token 预算等。
6
+ */
7
+ interface ScenarioOverrides {
8
+ /** 覆盖顶层 model(如补全用 flash、聊天用 pro) */
9
+ model?: string;
10
+ /**
11
+ * 思考能力开关(智谱 GLM 等思考模型专用)。
12
+ * - `{ type: 'disabled' }` 关闭思考,模型直接输出 content
13
+ * - `{ type: 'enabled' }` 开启思考
14
+ * - 不传则沿用顶层 thinking
15
+ */
16
+ thinking?: {
17
+ type: 'disabled' | 'enabled';
18
+ };
19
+ /** 覆盖硬编码 max_tokens(默认补全 512、聊天 4096) */
20
+ maxTokens?: number;
21
+ /** 采样温度(0~2) */
22
+ temperature?: number;
23
+ /** 覆盖默认 system prompt */
24
+ systemPrompt?: string;
25
+ }
3
26
  /** AI API 配置(OpenAI 兼容协议) */
4
27
  interface ApiConfig {
5
28
  baseUrl: string;
@@ -7,6 +30,20 @@ interface ApiConfig {
7
30
  model: string;
8
31
  /** true = 流式输出(默认),false = 一次性返回 */
9
32
  streamMode?: boolean;
33
+ /**
34
+ * 顶层思考能力开关(智谱 GLM 等思考模型专用)。
35
+ * 对补全和聊天同时生效,但可被 completion/chat 中的同名字段覆盖。
36
+ * - `{ type: 'disabled' }` 关闭思考
37
+ * - `{ type: 'enabled' }` 开启思考
38
+ * - 不传:行内补全自动关闭思考,对话聊天自动开启思考
39
+ */
40
+ thinking?: {
41
+ type: 'disabled' | 'enabled';
42
+ };
43
+ /** 行内补全(幽灵提示)专用覆盖 */
44
+ completion?: ScenarioOverrides;
45
+ /** 对话聊天专用覆盖 */
46
+ chat?: ScenarioOverrides;
10
47
  }
11
48
  /** SQL 表结构 Schema:{ 表名: [列名, ...] } */
12
49
  type SqlSchema = Record<string, string[]>;
@@ -292,4 +329,4 @@ declare function registerAiCompletionCommand(editor: MonacoType.editor.IStandalo
292
329
  current: PendingCompletion | null;
293
330
  }, onLoadingChange?: (loading: boolean) => void, onError?: (message: string) => void): MonacoType.IDisposable;
294
331
 
295
- export { AI_INLINE_LANGUAGES, AiChatController, type AiChatControllerEvents, type ApiConfig, type ChatMessage, type CompletionContext, type CompletionProvider, EditorBus, type EditorBusEvents, EditorController, type EditorControllerEvents, type EditorControllerOptions, type EditorSnapshot, EventEmitter, LANGUAGES, LOCALES, type Listener, type Locale, type PendingCompletion, SQL_DATA_TYPES, SQL_FUNCTIONS, SQL_KEYWORDS, type SqlSchema, THEMES, fetchAiCompletionNonStream, fetchAiCompletionStream, registerAiCompletionCommand, registerAiInlineCompletion, registerSqlCompletion };
332
+ export { AI_INLINE_LANGUAGES, AiChatController, type AiChatControllerEvents, type ApiConfig, type ChatMessage, type CompletionContext, type CompletionProvider, EditorBus, type EditorBusEvents, EditorController, type EditorControllerEvents, type EditorControllerOptions, type EditorSnapshot, EventEmitter, LANGUAGES, LOCALES, type Listener, type Locale, type PendingCompletion, SQL_DATA_TYPES, SQL_FUNCTIONS, SQL_KEYWORDS, type ScenarioOverrides, type SqlSchema, THEMES, fetchAiCompletionNonStream, fetchAiCompletionStream, registerAiCompletionCommand, registerAiInlineCompletion, registerSqlCompletion };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,28 @@
1
1
  import * as MonacoType from 'monaco-editor';
2
2
 
3
+ /**
4
+ * 场景级参数覆盖(优先级高于顶层同名字段)。
5
+ * 用于让「行内补全」和「对话聊天」使用不同的模型 / 思考策略 / token 预算等。
6
+ */
7
+ interface ScenarioOverrides {
8
+ /** 覆盖顶层 model(如补全用 flash、聊天用 pro) */
9
+ model?: string;
10
+ /**
11
+ * 思考能力开关(智谱 GLM 等思考模型专用)。
12
+ * - `{ type: 'disabled' }` 关闭思考,模型直接输出 content
13
+ * - `{ type: 'enabled' }` 开启思考
14
+ * - 不传则沿用顶层 thinking
15
+ */
16
+ thinking?: {
17
+ type: 'disabled' | 'enabled';
18
+ };
19
+ /** 覆盖硬编码 max_tokens(默认补全 512、聊天 4096) */
20
+ maxTokens?: number;
21
+ /** 采样温度(0~2) */
22
+ temperature?: number;
23
+ /** 覆盖默认 system prompt */
24
+ systemPrompt?: string;
25
+ }
3
26
  /** AI API 配置(OpenAI 兼容协议) */
4
27
  interface ApiConfig {
5
28
  baseUrl: string;
@@ -7,6 +30,20 @@ interface ApiConfig {
7
30
  model: string;
8
31
  /** true = 流式输出(默认),false = 一次性返回 */
9
32
  streamMode?: boolean;
33
+ /**
34
+ * 顶层思考能力开关(智谱 GLM 等思考模型专用)。
35
+ * 对补全和聊天同时生效,但可被 completion/chat 中的同名字段覆盖。
36
+ * - `{ type: 'disabled' }` 关闭思考
37
+ * - `{ type: 'enabled' }` 开启思考
38
+ * - 不传:行内补全自动关闭思考,对话聊天自动开启思考
39
+ */
40
+ thinking?: {
41
+ type: 'disabled' | 'enabled';
42
+ };
43
+ /** 行内补全(幽灵提示)专用覆盖 */
44
+ completion?: ScenarioOverrides;
45
+ /** 对话聊天专用覆盖 */
46
+ chat?: ScenarioOverrides;
10
47
  }
11
48
  /** SQL 表结构 Schema:{ 表名: [列名, ...] } */
12
49
  type SqlSchema = Record<string, string[]>;
@@ -292,4 +329,4 @@ declare function registerAiCompletionCommand(editor: MonacoType.editor.IStandalo
292
329
  current: PendingCompletion | null;
293
330
  }, onLoadingChange?: (loading: boolean) => void, onError?: (message: string) => void): MonacoType.IDisposable;
294
331
 
295
- export { AI_INLINE_LANGUAGES, AiChatController, type AiChatControllerEvents, type ApiConfig, type ChatMessage, type CompletionContext, type CompletionProvider, EditorBus, type EditorBusEvents, EditorController, type EditorControllerEvents, type EditorControllerOptions, type EditorSnapshot, EventEmitter, LANGUAGES, LOCALES, type Listener, type Locale, type PendingCompletion, SQL_DATA_TYPES, SQL_FUNCTIONS, SQL_KEYWORDS, type SqlSchema, THEMES, fetchAiCompletionNonStream, fetchAiCompletionStream, registerAiCompletionCommand, registerAiInlineCompletion, registerSqlCompletion };
332
+ export { AI_INLINE_LANGUAGES, AiChatController, type AiChatControllerEvents, type ApiConfig, type ChatMessage, type CompletionContext, type CompletionProvider, EditorBus, type EditorBusEvents, EditorController, type EditorControllerEvents, type EditorControllerOptions, type EditorSnapshot, EventEmitter, LANGUAGES, LOCALES, type Listener, type Locale, type PendingCompletion, SQL_DATA_TYPES, SQL_FUNCTIONS, SQL_KEYWORDS, type ScenarioOverrides, type SqlSchema, THEMES, fetchAiCompletionNonStream, fetchAiCompletionStream, registerAiCompletionCommand, registerAiInlineCompletion, registerSqlCompletion };
package/dist/index.js CHANGED
@@ -422,30 +422,33 @@ function createCursorSpinner(editor, line, col) {
422
422
  collection.clear();
423
423
  };
424
424
  }
425
- async function fetchAiCompletionNonStream(config, context, prefix, signal) {
426
- const response = await fetch(`${config.baseUrl}/chat/completions`, {
427
- method: "POST",
428
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
429
- body: JSON.stringify({
430
- model: config.model,
431
- messages: [
432
- {
433
- role: "system",
434
- content: "\u4F60\u662F\u4E00\u4E2A\u4EE3\u7801\u8865\u5168\u52A9\u624B\u3002\u57FA\u4E8E\u7528\u6237\u63D0\u4F9B\u7684\u4EE3\u7801\u4E0A\u4E0B\u6587\u548C\u524D\u7F00\uFF0C\u751F\u6210\u77ED\u5C0F\u7CBE\u608D\u7684\u4EE3\u7801\u8865\u5168\u3002\u53EA\u8FD4\u56DE\u8865\u5168\u7684\u4EE3\u7801\u7247\u6BB5\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002"
435
- },
436
- {
437
- role: "user",
438
- content: `\u4EE3\u7801\u4E0A\u4E0B\u6587\uFF1A
425
+ var DEFAULT_COMPLETION_SYSTEM = "\u4F60\u662F\u4E00\u4E2A\u4EE3\u7801\u8865\u5168\u52A9\u624B\u3002\u57FA\u4E8E\u7528\u6237\u63D0\u4F9B\u7684\u4EE3\u7801\u4E0A\u4E0B\u6587\u548C\u524D\u7F00\uFF0C\u751F\u6210\u77ED\u5C0F\u7CBE\u608D\u7684\u4EE3\u7801\u8865\u5168\u3002\u53EA\u8FD4\u56DE\u8865\u5168\u7684\u4EE3\u7801\u7247\u6BB5\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002";
426
+ function buildRequestBody(config, context, prefix, stream) {
427
+ const ov = config.completion ?? {};
428
+ const thinking = ov.thinking ?? config.thinking ?? { type: "disabled" };
429
+ const body = {
430
+ model: ov.model ?? config.model,
431
+ messages: [
432
+ { role: "system", content: ov.systemPrompt ?? DEFAULT_COMPLETION_SYSTEM },
433
+ { role: "user", content: `\u4EE3\u7801\u4E0A\u4E0B\u6587\uFF1A
439
434
  ${context}
440
435
 
441
436
  \u524D\u7F00\uFF1A${prefix}
442
437
 
443
- \u8BF7\u7EE7\u7EED\u8865\u5168\u8FD9\u6BB5\u4EE3\u7801\uFF0C\u53EA\u8FD4\u56DE\u8865\u5168\u90E8\u5206\u3002`
444
- }
445
- ],
446
- max_tokens: 1024,
447
- stream: false
448
- }),
438
+ \u8BF7\u7EE7\u7EED\u8865\u5168\u8FD9\u6BB5\u4EE3\u7801\uFF0C\u53EA\u8FD4\u56DE\u8865\u5168\u90E8\u5206\u3002` }
439
+ ],
440
+ max_tokens: ov.maxTokens ?? 512,
441
+ stream
442
+ };
443
+ body.thinking = thinking;
444
+ if (ov.temperature !== void 0) body.temperature = ov.temperature;
445
+ return body;
446
+ }
447
+ async function fetchAiCompletionNonStream(config, context, prefix, signal) {
448
+ const response = await fetch(`${config.baseUrl}/chat/completions`, {
449
+ method: "POST",
450
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
451
+ body: JSON.stringify(buildRequestBody(config, context, prefix, false)),
449
452
  signal
450
453
  });
451
454
  if (!response.ok) {
@@ -458,26 +461,7 @@ async function fetchAiCompletionStream(config, context, prefix, onChunk, signal)
458
461
  const response = await fetch(`${config.baseUrl}/chat/completions`, {
459
462
  method: "POST",
460
463
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
461
- body: JSON.stringify({
462
- model: config.model,
463
- messages: [
464
- {
465
- role: "system",
466
- content: "\u4F60\u662F\u4E00\u4E2A\u4EE3\u7801\u8865\u5168\u52A9\u624B\u3002\u57FA\u4E8E\u7528\u6237\u63D0\u4F9B\u7684\u4EE3\u7801\u4E0A\u4E0B\u6587\u548C\u524D\u7F00\uFF0C\u751F\u6210\u77ED\u5C0F\u7CBE\u608D\u7684\u4EE3\u7801\u8865\u5168\u3002\u53EA\u8FD4\u56DE\u8865\u5168\u7684\u4EE3\u7801\u7247\u6BB5\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002"
467
- },
468
- {
469
- role: "user",
470
- content: `\u4EE3\u7801\u4E0A\u4E0B\u6587\uFF1A
471
- ${context}
472
-
473
- \u524D\u7F00\uFF1A${prefix}
474
-
475
- \u8BF7\u7EE7\u7EED\u8865\u5168\u8FD9\u6BB5\u4EE3\u7801\uFF0C\u53EA\u8FD4\u56DE\u8865\u5168\u90E8\u5206\u3002`
476
- }
477
- ],
478
- max_tokens: 1024,
479
- stream: true
480
- }),
464
+ body: JSON.stringify(buildRequestBody(config, context, prefix, true)),
481
465
  signal
482
466
  });
483
467
  if (!response.ok) {
@@ -866,17 +850,26 @@ var AiChatController = class extends EventEmitter {
866
850
  this.abortController = new AbortController();
867
851
  const systemPrompt = options?.language ? `You are an expert coding assistant. The user is working with ${options.language} code. Respond concisely in the same language as the user's message, defaulting to Chinese.` : "You are an expert coding assistant. Respond concisely in the same language as the user's message, defaulting to Chinese.";
868
852
  const historyForApi = this.messages.filter((m) => m.id !== assistantMsg.id).map((m) => ({ role: m.role, content: m.content }));
853
+ const chatOv = this.apiConfig.chat ?? {};
854
+ const thinking = chatOv.thinking ?? this.apiConfig.thinking ?? { type: "enabled" };
855
+ const chatBody = {
856
+ model: chatOv.model ?? this.apiConfig.model,
857
+ messages: [
858
+ { role: "system", content: chatOv.systemPrompt ?? systemPrompt },
859
+ ...historyForApi
860
+ ],
861
+ max_tokens: chatOv.maxTokens ?? 4096,
862
+ stream: true,
863
+ thinking
864
+ };
865
+ if (chatOv.temperature !== void 0) chatBody.temperature = chatOv.temperature;
869
866
  const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {
870
867
  method: "POST",
871
868
  headers: {
872
869
  "Content-Type": "application/json",
873
870
  Authorization: `Bearer ${this.apiConfig.apiKey}`
874
871
  },
875
- body: JSON.stringify({
876
- model: this.apiConfig.model,
877
- messages: [{ role: "system", content: systemPrompt }, ...historyForApi],
878
- stream: true
879
- }),
872
+ body: JSON.stringify(chatBody),
880
873
  signal: this.abortController.signal
881
874
  });
882
875
  if (!response.ok) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/bus/EventEmitter.ts","../src/completion/sqlCompletion.ts","../src/ai/aiCompletion.ts","../src/controllers/EditorController.ts","../src/controllers/AiChatController.ts","../src/bus/EditorBus.ts"],"sourcesContent":["export const SQL_KEYWORDS = [\n 'SELECT', 'FROM', 'WHERE', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE',\n 'CREATE', 'TABLE', 'DROP', 'ALTER', 'ADD', 'COLUMN', 'INDEX', 'VIEW', 'DATABASE',\n 'SCHEMA', 'TRUNCATE', 'RENAME', 'AS', 'ON', 'JOIN', 'INNER', 'LEFT', 'RIGHT',\n 'FULL', 'OUTER', 'CROSS', 'NATURAL', 'USING', 'AND', 'OR', 'NOT', 'IN', 'EXISTS',\n 'BETWEEN', 'LIKE', 'IS', 'NULL', 'TRUE', 'FALSE', 'CASE', 'WHEN', 'THEN', 'ELSE',\n 'END', 'IF', 'UNION', 'ALL', 'DISTINCT', 'ORDER', 'BY', 'ASC', 'DESC', 'GROUP',\n 'HAVING', 'LIMIT', 'OFFSET', 'FETCH', 'NEXT', 'ROWS', 'ONLY', 'WITH', 'RECURSIVE',\n 'PRIMARY', 'KEY', 'FOREIGN', 'REFERENCES', 'UNIQUE', 'NOT NULL', 'DEFAULT',\n 'CHECK', 'CONSTRAINT', 'AUTO_INCREMENT', 'IDENTITY', 'SEQUENCE', 'GRANT',\n 'REVOKE', 'COMMIT', 'ROLLBACK', 'TRANSACTION', 'BEGIN', 'SAVEPOINT', 'EXPLAIN',\n];\n\nexport const SQL_FUNCTIONS = [\n 'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'COALESCE', 'NULLIF', 'IFNULL', 'NVL',\n 'CONCAT', 'LENGTH', 'SUBSTR', 'SUBSTRING', 'TRIM', 'LTRIM', 'RTRIM', 'UPPER',\n 'LOWER', 'REPLACE', 'INSTR', 'LPAD', 'RPAD', 'CHAR_LENGTH', 'POSITION',\n 'NOW', 'CURDATE', 'CURTIME', 'DATE', 'TIME', 'YEAR', 'MONTH', 'DAY',\n 'HOUR', 'MINUTE', 'SECOND', 'DATEDIFF', 'DATE_ADD', 'DATE_SUB', 'DATEADD',\n 'DATESUB', 'EXTRACT', 'TO_DATE', 'TO_CHAR', 'DATE_FORMAT', 'TIMESTAMPDIFF',\n 'ROUND', 'CEIL', 'FLOOR', 'ABS', 'MOD', 'POWER', 'SQRT', 'SIGN', 'RAND',\n 'CAST', 'CONVERT', 'ROW_NUMBER', 'RANK', 'DENSE_RANK', 'NTILE', 'LAG', 'LEAD',\n 'FIRST_VALUE', 'LAST_VALUE', 'OVER', 'PARTITION', 'LISTAGG', 'GROUP_CONCAT',\n 'STRING_AGG', 'JSON_OBJECT', 'JSON_ARRAY', 'JSON_EXTRACT', 'ISNULL',\n];\n\nexport const SQL_DATA_TYPES = [\n 'INT', 'INTEGER', 'BIGINT', 'SMALLINT', 'TINYINT', 'DECIMAL', 'NUMERIC',\n 'FLOAT', 'DOUBLE', 'REAL', 'CHAR', 'VARCHAR', 'TEXT', 'NCHAR', 'NVARCHAR',\n 'NTEXT', 'DATE', 'TIME', 'DATETIME', 'TIMESTAMP', 'BOOLEAN', 'BOOL',\n 'BLOB', 'CLOB', 'BINARY', 'VARBINARY', 'JSON', 'UUID', 'SERIAL',\n];\n\nexport const LANGUAGES = [\n 'javascript',\n 'typescript',\n 'python',\n 'json',\n 'css',\n 'html',\n 'markdown',\n 'rust',\n 'go',\n 'sql',\n] as const;\n\n/** Monaco 编辑器支持的 UI 本地化语言 */\nexport const LOCALES = {\n ZH_CN: 'zh-cn',\n EN: 'en',\n DE: 'de',\n ES: 'es',\n FR: 'fr',\n IT: 'it',\n JA: 'ja',\n KO: 'ko',\n RU: 'ru',\n} as const;\n\nexport type Locale = (typeof LOCALES)[keyof typeof LOCALES];\n\nexport const THEMES = [\n { value: 'vs-dark', label: 'Dark' },\n { value: 'light', label: 'Light' },\n { value: 'hc-black', label: 'High Contrast' },\n] as const;\n\nexport const AI_INLINE_LANGUAGES = [\n 'typescript', 'javascript', 'python', 'sql',\n 'java', 'cpp', 'csharp', 'go', 'rust',\n];\n","/**\n * 极简事件发射器,框架无关。\n * 用于 EditorController / AiChatController / EditorBus 之间的事件通信。\n */\nexport type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<EventMap> {\n private listeners: { [K in keyof EventMap]?: Set<Listener<EventMap[K]>> } = {};\n\n on<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): () => void {\n if (!this.listeners[event]) this.listeners[event] = new Set();\n this.listeners[event]!.add(listener);\n return () => this.off(event, listener);\n }\n\n off<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): void {\n this.listeners[event]?.delete(listener);\n }\n\n emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.listeners[event]?.forEach((listener) => {\n try {\n listener(payload);\n } catch (err) {\n console.error(`[EventEmitter] listener for \"${String(event)}\" threw:`, err);\n }\n });\n }\n\n removeAllListeners(): void {\n this.listeners = {};\n }\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { SQL_KEYWORDS, SQL_FUNCTIONS, SQL_DATA_TYPES } from '../constants';\nimport type { SqlSchema } from '../types';\n\n/** 从 SQL 文档中动态解析表名、CTE 别名和变量 */\nfunction parseDynamicItems(sql: string): { tables: string[]; variables: string[] } {\n const tables: string[] = [];\n const variables: string[] = [];\n let m: RegExpExecArray | null;\n\n const tableRe = /\\b(?:FROM|JOIN|UPDATE|INTO|TABLE)\\s+([`\"']?\\w+[`\"']?)/gi;\n while ((m = tableRe.exec(sql)) !== null) {\n const name = m[1].replace(/[`\"']/g, '');\n if (!tables.includes(name)) tables.push(name);\n }\n\n const cteRe = /\\bWITH\\s+(\\w+)\\s+AS\\s*\\(/gi;\n while ((m = cteRe.exec(sql)) !== null) {\n if (!tables.includes(m[1])) tables.push(m[1]);\n }\n\n const declareRe = /\\bDECLARE\\s+(@?\\w+)/gi;\n while ((m = declareRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const setVarRe = /\\bSET\\s+(@\\w+)\\s*=/gi;\n while ((m = setVarRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const atVarRe = /@(\\w+)/g;\n while ((m = atVarRe.exec(sql)) !== null) {\n const v = `@${m[1]}`;\n if (!variables.includes(v)) variables.push(v);\n }\n\n return { tables, variables };\n}\n\n/**\n * 注册 SQL 内置补全提供者。\n * schemaRef 使用 ref 模式以支持动态更新。\n * excludeLabelsRef(可选)使用 ref 模式,提供需要从内置关键字/函数中排除的 label\n * (大写匹配)。用于让使用方的自定义词表覆盖内置同名项,避免重复提示。\n */\nexport function registerSqlCompletion(\n monaco: typeof MonacoType,\n schemaRef: { readonly current: SqlSchema },\n excludeLabelsRef?: { readonly current: Set<string> },\n): MonacoType.IDisposable {\n return monaco.languages.registerCompletionItemProvider('sql', {\n triggerCharacters: ['.'],\n provideCompletionItems(model, position, context) {\n const word = model.getWordUntilPosition(position);\n const range: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: word.startColumn,\n endColumn: word.endColumn,\n };\n\n // 点号触发:提示该表的列名\n if (context.triggerCharacter === '.') {\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforeDot = lineText.substring(0, position.column - 2);\n const tableMatch = textBeforeDot.match(/(\\w+)$/);\n if (tableMatch) {\n const typed = tableMatch[1].toUpperCase();\n const schema = schemaRef.current;\n const tableKey = Object.keys(schema).find((k) => k.toUpperCase() === typed);\n if (tableKey) {\n const colRange: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n };\n return {\n suggestions: schema[tableKey].map((col) => ({\n label: col,\n kind: monaco.languages.CompletionItemKind.Field,\n insertText: col,\n range: colRange,\n detail: `${tableKey} · 列`,\n documentation: `表 ${tableKey} 的字段`,\n })),\n };\n }\n }\n return { suggestions: [] };\n }\n\n // 普通触发:关键字 + 函数 + 类型 + 表名 + 变量\n const fullText = model.getValue();\n const { tables: dynamicTables, variables } = parseDynamicItems(fullText);\n const schema = schemaRef.current;\n const schemaTables = Object.keys(schema);\n const allTables = [...new Set([...schemaTables, ...dynamicTables])];\n\n // 需要排除的内置 label(大写匹配),让使用方自定义词表覆盖同名项\n const exclude = excludeLabelsRef?.current;\n const isExcluded = (label: string) => exclude?.has(label.toUpperCase()) ?? false;\n\n const keywords = SQL_KEYWORDS.filter((kw) => !isExcluded(kw)).map((kw) => ({\n label: kw,\n kind: monaco.languages.CompletionItemKind.Keyword,\n insertText: kw,\n range,\n detail: 'SQL 关键字',\n }));\n\n const functions = SQL_FUNCTIONS.filter((fn) => !isExcluded(fn)).map((fn) => ({\n label: fn,\n kind: monaco.languages.CompletionItemKind.Function,\n insertText: `${fn}($1)`,\n insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n range,\n detail: 'SQL 函数',\n }));\n\n const dataTypes = SQL_DATA_TYPES.map((dt) => ({\n label: dt,\n kind: monaco.languages.CompletionItemKind.TypeParameter,\n insertText: dt,\n range,\n detail: 'SQL 数据类型',\n }));\n\n const tableItems = allTables.map((t) => ({\n label: t,\n kind: monaco.languages.CompletionItemKind.Class,\n insertText: t,\n range,\n detail: schemaTables.includes(t) ? '表名 (Schema)' : '表名 (文档)',\n }));\n\n const variableItems = variables.map((v) => ({\n label: v,\n kind: monaco.languages.CompletionItemKind.Variable,\n insertText: v,\n range,\n detail: 'SQL 变量',\n }));\n\n return {\n suggestions: [...keywords, ...functions, ...dataTypes, ...tableItems, ...variableItems],\n };\n },\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport type { ApiConfig, PendingCompletion } from '../types';\nimport { AI_INLINE_LANGUAGES } from '../constants';\n\n/** 去除模型返回中可能包含的代码围栏(```lang ... ```) */\nfunction stripCodeFence(text: string): string {\n return text.replace(/^```[a-z]*\\n?/, '').replace(/\\n?```$/, '');\n}\n\nconst SPINNER_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'] as const;\n\nfunction ensureSpinnerStyle() {\n const id = 'mae-ai-completion-spinner-style';\n if (typeof document === 'undefined' || document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n const frameCss = SPINNER_FRAMES.map((ch, i) => `.mae-ai-spinner-f${i}::after { content: \" ${ch}\"; }`).join('\\n');\n style.textContent = `\n@keyframes mae-ai-completion-glow {\n 0%, 100% { text-shadow: 0 0 3px rgba(96, 165, 250, 0.35); }\n 50% { text-shadow: 0 0 9px rgba(96, 165, 250, 0.95), 0 0 18px rgba(59, 130, 246, 0.35); }\n}\n${frameCss}\n[class^=\"mae-ai-spinner-f\"]::after {\n color: #60a5fa;\n font-family: \"Segoe UI Symbol\", \"Noto Sans Symbols\", \"Apple Symbols\", monospace;\n display: inline-block;\n margin-left: 2px;\n animation: mae-ai-completion-glow 1s ease-in-out infinite;\n}`;\n document.head.appendChild(style);\n}\n\nfunction createCursorSpinner(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n line: number,\n col: number,\n): () => void {\n ensureSpinnerStyle();\n let frameIdx = 0;\n const makeDecor = () => [{\n range: { startLineNumber: line, startColumn: col, endLineNumber: line, endColumn: col },\n options: { afterContentClassName: `mae-ai-spinner-f${frameIdx}` },\n }];\n const collection = editor.createDecorationsCollection(makeDecor());\n const timer = setInterval(() => {\n frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;\n collection.set(makeDecor());\n }, 80);\n return () => {\n clearInterval(timer);\n collection.clear();\n };\n}\n\n/** 非流式调用 OpenAI 兼容 API(使用原生 fetch,无 axios 依赖) */\nexport async function fetchAiCompletionNonStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n signal?: AbortSignal,\n): Promise<string> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify({\n model: config.model,\n messages: [\n {\n role: 'system',\n content: '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。',\n },\n {\n role: 'user',\n content: `代码上下文:\\n${context}\\n\\n前缀:${prefix}\\n\\n请继续补全这段代码,只返回补全部分。`,\n },\n ],\n max_tokens: 1024,\n stream: false,\n }),\n signal,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n const data = (await response.json()) as { choices?: Array<{ message?: { content?: string } }> };\n return stripCodeFence(data.choices?.[0]?.message?.content?.trim() ?? '');\n}\n\n/** 流式调用(fetch + ReadableStream) */\nexport async function fetchAiCompletionStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n onChunk: (accumulated: string) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify({\n model: config.model,\n messages: [\n {\n role: 'system',\n content: '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。',\n },\n {\n role: 'user',\n content: `代码上下文:\\n${context}\\n\\n前缀:${prefix}\\n\\n请继续补全这段代码,只返回补全部分。`,\n },\n ],\n max_tokens: 1024,\n stream: true,\n }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n if (!response.body) throw new Error('Response body is null');\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let accumulated = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data:')) continue;\n const data = trimmed.slice(5).trim();\n if (data === '[DONE]') return;\n try {\n const parsed = JSON.parse(data) as { choices?: Array<{ delta?: { content?: string } }> };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n accumulated += delta;\n onChunk(accumulated);\n }\n } catch {\n // ignore malformed lines\n }\n }\n }\n}\n\n/** 注册 AI 内联幽灵文本提供者 */\nexport function registerAiInlineCompletion(\n monaco: typeof MonacoType,\n pendingRef: { current: PendingCompletion | null },\n): void {\n AI_INLINE_LANGUAGES.forEach((lang) => {\n monaco.languages.registerInlineCompletionsProvider(lang, {\n provideInlineCompletions: (_model, position) => {\n const pending = pendingRef.current;\n if (!pending) return { items: [] };\n if (pending.lineNumber !== position.lineNumber || pending.column !== position.column) {\n pendingRef.current = null;\n return { items: [] };\n }\n return {\n items: [\n {\n insertText: pending.insertText,\n range: {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n },\n },\n ],\n };\n },\n disposeInlineCompletions: () => {},\n });\n });\n}\n\n/**\n * 注册 AI 补全命令(Ctrl+Alt+L 手动触发,流式更新幽灵文本)。\n * 框架无关:通过函数引用方式读取最新的 apiConfig。\n */\nexport function registerAiCompletionCommand(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n getApiConfig: () => ApiConfig | null,\n pendingRef: { current: PendingCompletion | null },\n onLoadingChange?: (loading: boolean) => void,\n onError?: (message: string) => void,\n): MonacoType.IDisposable {\n let currentAbortController: AbortController | null = null;\n\n const isAbortError = (err: unknown): boolean =>\n err instanceof Error && (err.name === 'AbortError' || err.message?.includes('aborted'));\n\n const triggerAiCompletion = async () => {\n const apiConfig = getApiConfig();\n if (!apiConfig || !apiConfig.apiKey.trim()) {\n onError?.('未配置 API Key,请先配置 AI 服务再使用补全功能。');\n return;\n }\n\n const position = editor.getPosition();\n if (!position) return;\n const model = editor.getModel();\n if (!model) return;\n\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforePosition = lineText.substring(0, position.column - 1);\n if (!textBeforePosition.trim()) return;\n\n const startLine = Math.max(0, position.lineNumber - 5);\n const contextLines: string[] = [];\n for (let i = startLine; i < position.lineNumber; i++) {\n contextLines.push(model.getLineContent(i + 1));\n }\n const contextCode = contextLines.join('\\n');\n\n currentAbortController?.abort();\n currentAbortController = new AbortController();\n pendingRef.current = null;\n\n const stopSpinner = createCursorSpinner(editor, position.lineNumber, position.column);\n onLoadingChange?.(true);\n\n const useStream = apiConfig.streamMode !== false;\n\n try {\n if (useStream) {\n let triggerTimer: ReturnType<typeof setTimeout> | null = null;\n const scheduleTrigger = () => {\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n triggerTimer = setTimeout(() => {\n triggerTimer = null;\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n }, 80);\n };\n\n await fetchAiCompletionStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n (accumulated) => {\n let insertText = stripCodeFence(accumulated);\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n scheduleTrigger();\n },\n currentAbortController.signal,\n );\n\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } else {\n const completion = await fetchAiCompletionNonStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n currentAbortController.signal,\n );\n if (!completion) return;\n let insertText = completion;\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } catch (err) {\n if (isAbortError(err)) return;\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(`AI 补全失败:${msg}`);\n console.error('[AI Completion] Error:', err);\n } finally {\n stopSpinner();\n onLoadingChange?.(false);\n }\n };\n\n return editor.onKeyDown((e) => {\n if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === 'KeyL') {\n e.preventDefault();\n void triggerAiCompletion();\n }\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, PendingCompletion, SqlSchema, CompletionProvider } from '../types';\nimport { registerSqlCompletion } from '../completion/sqlCompletion';\nimport { registerAiInlineCompletion } from '../ai/aiCompletion';\n\nexport interface EditorControllerEvents {\n change: { value: string };\n cursor: { line: number; column: number };\n ready: { editor: MonacoType.editor.IStandaloneCodeEditor };\n languageChange: { language: string };\n focus: void;\n blur: void;\n}\n\nexport interface EditorControllerOptions {\n container: HTMLElement;\n language?: string;\n theme?: string;\n value?: string;\n monaco: typeof MonacoType;\n /** Monaco loader monaco-editor 路径配置 */\n vsPath?: string;\n sqlSchema?: SqlSchema;\n apiConfig?: ApiConfig | null;\n completionProviders?: CompletionProvider[];\n /** Monaco editor options */\n editorOptions?: MonacoType.editor.IStandaloneEditorConstructionOptions;\n}\n\n/**\n * 框架无关的编辑器控制器。\n * 封装 Monaco 实例的生命周期、核心操作、补全注册。\n * 通过 EventEmitter 暴露编辑器事件,不依赖任何 UI 框架。\n */\nexport class EditorController extends EventEmitter<EditorControllerEvents> {\n private editor: MonacoType.editor.IStandaloneCodeEditor | null = null;\n private monaco: typeof MonacoType;\n private sqlProviderRegistered = false;\n private aiProviderRegistered = false;\n private pendingCompletionRef = { current: null as PendingCompletion | null };\n private customProviders: CompletionProvider[] = [];\n private disposables: MonacoType.IDisposable[] = [];\n\n completed = false;\n error: Error | null = null;\n\n constructor(private options: EditorControllerOptions) {\n super();\n this.monaco = options.monaco;\n this.customProviders = options.completionProviders ?? [];\n this.init();\n }\n\n private init(): void {\n const { language, theme, value, sqlSchema, apiConfig, editorOptions } = this.options;\n\n // 注册 SQL 补全(只注册一次)\n if (!this.sqlProviderRegistered) {\n const schemaRef = { current: sqlSchema ?? {} };\n registerSqlCompletion(this.monaco, schemaRef);\n this.sqlProviderRegistered = true;\n }\n\n // 注册 AI 幽灵文本提供者\n if (!this.aiProviderRegistered) {\n registerAiInlineCompletion(this.monaco, this.pendingCompletionRef);\n this.aiProviderRegistered = true;\n }\n\n // 注册自定义补全提供者\n this.registerCustomCompletionProviders();\n\n // 创建编辑器\n this.editor = this.monaco.editor.create(this.options.container, {\n value: value ?? '',\n language: language ?? 'typescript',\n theme: theme ?? 'vs-dark',\n fontSize: 14,\n minimap: { enabled: true },\n scrollBeyondLastLine: false,\n automaticLayout: true,\n lineNumbers: 'on',\n renderLineHighlight: 'all',\n smoothScrolling: true,\n cursorBlinking: 'smooth',\n bracketPairColorization: { enabled: true },\n tabSize: 2,\n wordWrap: 'on',\n folding: true,\n formatOnPaste: true,\n suggestOnTriggerCharacters: true,\n quickSuggestions: { other: true, comments: false, strings: false },\n acceptSuggestionOnCommitCharacter: true,\n acceptSuggestionOnEnter: 'on',\n inlineSuggest: { enabled: true },\n tabCompletion: 'on',\n ...editorOptions,\n });\n\n // 绑定事件\n this.bindEditorEvents();\n this.emit('ready', { editor: this.editor });\n }\n\n private bindEditorEvents(): void {\n const editor = this.editor!;\n\n const d1 = editor.onDidChangeModelContent(() => {\n this.emit('change', { value: editor.getValue() });\n });\n\n const d2 = editor.onDidChangeCursorPosition((e) => {\n this.emit('cursor', {\n line: e.position.lineNumber,\n column: e.position.column,\n });\n });\n\n const d3 = editor.onDidFocusEditorText(() => this.emit('focus', undefined));\n const d4 = editor.onDidBlurEditorText(() => this.emit('blur', undefined));\n\n this.disposables.push(d1, d2, d3, d4);\n }\n\n private registerCustomCompletionProviders(): void {\n if (this.customProviders.length === 0) return;\n\n for (const provider of this.customProviders) {\n const langs = provider.languages ?? ['*'];\n for (const lang of langs) {\n this.monaco.languages.registerCompletionItemProvider(lang, {\n triggerCharacters: provider.triggerCharacters,\n provideCompletionItems: async (model, position, context) => {\n const ctx = {\n monaco: this.monaco,\n model,\n position,\n lineText: model.getLineContent(position.lineNumber),\n currentWord: model.getWordUntilPosition(position).word,\n fullText: model.getValue(),\n triggerCharacter: context.triggerCharacter,\n };\n\n if (provider.shouldTrigger && !provider.shouldTrigger(ctx)) {\n return { suggestions: [] };\n }\n\n const suggestions = await provider.provide(ctx);\n return { suggestions };\n },\n });\n }\n }\n }\n\n // ─── 公开 API ──────────────────────────────────────────────────────────\n\n getEditor(): MonacoType.editor.IStandaloneCodeEditor | null {\n return this.editor;\n }\n\n getValue(): string {\n return this.editor?.getValue() ?? '';\n }\n\n setValue(value: string): void {\n this.editor?.setValue(value);\n }\n\n insertText(text: string, range?: MonacoType.IRange): void {\n const editor = this.editor;\n if (!editor) return;\n const targetRange = range ?? editor.getSelection();\n if (targetRange) {\n editor.executeEdits('controller-insert', [{ range: targetRange, text }]);\n editor.focus();\n }\n }\n\n format(): void {\n this.editor?.getAction('editor.action.formatDocument')?.run();\n }\n\n focus(): void {\n this.editor?.focus();\n }\n\n setLanguage(language: string): void {\n const model = this.editor?.getModel();\n if (model) {\n this.monaco.editor.setModelLanguage(model, language);\n this.emit('languageChange', { language });\n }\n }\n\n setTheme(theme: string): void {\n this.monaco.editor.setTheme(theme);\n }\n\n getCursorPosition(): { line: number; column: number } {\n const pos = this.editor?.getPosition();\n return pos\n ? { line: pos.lineNumber, column: pos.column }\n : { line: 1, column: 1 };\n }\n\n getSelection(): MonacoType.IRange | null {\n return this.editor?.getSelection() ?? null;\n }\n\n /**\n * 触发 AI 行内补全(Ctrl+Alt+L 快捷键)。\n * 需要提前设置 apiConfig(通过 setApiConfig 或构造函数传入)。\n */\n setApiConfig(config: ApiConfig | null): void {\n this.options.apiConfig = config;\n }\n\n getPendingCompletionRef(): { current: PendingCompletion | null } {\n return this.pendingCompletionRef;\n }\n\n dispose(): void {\n for (const d of this.disposables) d.dispose();\n this.disposables = [];\n this.editor?.dispose();\n this.editor = null;\n this.removeAllListeners();\n }\n}","import { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, ChatMessage } from '../types';\n\nexport interface AiChatControllerEvents {\n messageAdded: ChatMessage;\n messageUpdated: ChatMessage;\n cleared: void;\n loadingChange: { loading: boolean };\n error: { message: string };\n}\n\nfunction generateUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * AI 聊天控制器:管理消息列表、API 调用与流式响应。\n * 框架无关:通过事件通知 UI 层更新。\n */\nexport class AiChatController extends EventEmitter<AiChatControllerEvents> {\n private messages: ChatMessage[] = [];\n private abortController: AbortController | null = null;\n private loading = false;\n private apiConfig: ApiConfig;\n\n constructor(apiConfig: ApiConfig) {\n super();\n this.apiConfig = apiConfig;\n }\n\n setApiConfig(config: ApiConfig): void {\n this.apiConfig = config;\n }\n\n getApiConfig(): ApiConfig {\n return this.apiConfig;\n }\n\n getMessages(): readonly ChatMessage[] {\n return this.messages;\n }\n\n isLoading(): boolean {\n return this.loading;\n }\n\n /** 发送消息,可选携带编辑器上下文 */\n async send(\n userInput: string,\n options?: { editorContent?: string; language?: string },\n ): Promise<void> {\n const trimmed = userInput.trim();\n if (!trimmed || this.loading) return;\n\n if (!this.apiConfig.apiKey.trim()) {\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '⚠️ 尚未配置 API Key,请配置 Base URL、API Key 和模型名称后再开始对话。',\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n return;\n }\n\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '',\n isStreaming: true,\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n\n this.loading = true;\n this.emit('loadingChange', { loading: true });\n\n try {\n this.abortController = new AbortController();\n\n const systemPrompt = options?.language\n ? `You are an expert coding assistant. The user is working with ${options.language} code. Respond concisely in the same language as the user's message, defaulting to Chinese.`\n : \"You are an expert coding assistant. Respond concisely in the same language as the user's message, defaulting to Chinese.\";\n\n const historyForApi = this.messages\n .filter((m) => m.id !== assistantMsg.id)\n .map((m) => ({ role: m.role, content: m.content }));\n\n const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiConfig.apiKey}`,\n },\n body: JSON.stringify({\n model: this.apiConfig.model,\n messages: [{ role: 'system', content: systemPrompt }, ...historyForApi],\n stream: true,\n }),\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n let errText = '';\n try {\n errText = await response.text();\n } catch {\n /* ignore */\n }\n let hint = '';\n if (response.status === 401) hint = '(API Key 无效或已过期)';\n else if (response.status === 403) hint = '(无访问权限,请检查 API Key 和 Base URL)';\n else if (response.status === 429) hint = '(请求过于频繁,请稍后再试)';\n else if (response.status >= 500) hint = '(服务端错误)';\n throw new Error(`HTTP ${response.status}${hint}${errText ? `\\n${errText}` : ''}`);\n }\n\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let fullContent = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6).trim();\n if (data === '[DONE]') break;\n try {\n const parsed = JSON.parse(data) as {\n choices?: Array<{ delta?: { content?: string } }>;\n };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n fullContent += delta;\n assistantMsg.content = fullContent;\n this.emit('messageUpdated', { ...assistantMsg });\n }\n } catch {\n /* ignore */\n }\n }\n }\n\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n } catch (err: unknown) {\n const isAbort = err instanceof Error && err.name === 'AbortError';\n const errMsg = err instanceof Error ? err.message : String(err);\n const isNetworkErr = err instanceof TypeError && errMsg.toLowerCase().includes('fetch');\n const errorContent = isAbort\n ? '⏹ 请求已取消'\n : isNetworkErr\n ? `⚠️ 网络错误,请检查 Base URL 和网络。\\n\\n${errMsg}`\n : `⚠️ 请求失败:${errMsg}`;\n assistantMsg.content = errorContent;\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n if (!isAbort) this.emit('error', { message: errMsg });\n } finally {\n this.loading = false;\n this.emit('loadingChange', { loading: false });\n }\n }\n\n stop(): void {\n this.abortController?.abort();\n }\n\n clear(): void {\n this.messages = [];\n this.emit('cleared', undefined);\n }\n\n dispose(): void {\n this.abortController?.abort();\n this.removeAllListeners();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport type { EditorController } from '../controllers/EditorController';\nimport type { AiChatController } from '../controllers/AiChatController';\n\nexport interface EditorBusEvents {\n /** 编辑器已注册 */\n 'editor:ready': EditorController;\n /** 编辑器即将卸载 */\n 'editor:dispose': void;\n /** 编辑器内容变化 */\n 'editor:change': { value: string };\n /** 编辑器光标变化 */\n 'editor:cursor': { line: number; column: number };\n /** 编辑器语言变化 */\n 'editor:languageChange': { language: string };\n\n /** 聊天面板已注册 */\n 'chat:ready': AiChatController;\n /** 聊天面板卸载 */\n 'chat:dispose': void;\n /** 聊天面板请求向编辑器插入代码 */\n 'chat:insertCode': { code: string };\n /** 聊天面板请求替换编辑器全部内容 */\n 'chat:replaceCode': { code: string };\n}\n\n/**\n * 编辑器与聊天面板的通信总线。\n * 在两个组件都引入时由协调器(Coordinator)创建并共享,实现自动联动。\n * 当只引入其中一个组件时,bus 可为 null,组件正常独立工作。\n */\nexport class EditorBus extends EventEmitter<EditorBusEvents> {\n private editor: EditorController | null = null;\n private chat: AiChatController | null = null;\n\n registerEditor(controller: EditorController): () => void {\n this.editor = controller;\n\n // 桥接:编辑器事件 → bus 事件\n const offChange = controller.on('change', (data) => this.emit('editor:change', data));\n const offCursor = controller.on('cursor', (data) => this.emit('editor:cursor', data));\n const offLang = controller.on('languageChange', (data) => this.emit('editor:languageChange', data));\n\n // 桥接:bus 上的 chat 命令 → 编辑器操作\n const offInsert = this.on('chat:insertCode', ({ code }) => controller.insertText(code));\n const offReplace = this.on('chat:replaceCode', ({ code }) => controller.setValue(code));\n\n this.emit('editor:ready', controller);\n\n return () => {\n offChange();\n offCursor();\n offLang();\n offInsert();\n offReplace();\n if (this.editor === controller) {\n this.editor = null;\n this.emit('editor:dispose', undefined);\n }\n };\n }\n\n registerChat(controller: AiChatController): () => void {\n this.chat = controller;\n this.emit('chat:ready', controller);\n return () => {\n if (this.chat === controller) {\n this.chat = null;\n this.emit('chat:dispose', undefined);\n }\n };\n }\n\n getEditor(): EditorController | null {\n return this.editor;\n }\n\n getChat(): AiChatController | null {\n return this.chat;\n }\n\n /** 让聊天面板向编辑器请求当前内容 */\n getEditorContent(): string {\n return this.editor?.getValue() ?? '';\n }\n\n /** 让聊天面板向编辑器请求当前语言 */\n getEditorLanguage(): string | undefined {\n const editor = this.editor?.getEditor();\n return editor?.getModel()?.getLanguageId();\n }\n\n /** 让聊天面板请求向编辑器插入代码 */\n insertToEditor(code: string): void {\n this.emit('chat:insertCode', { code });\n }\n\n /** 让聊天面板请求替换编辑器全部内容 */\n replaceEditor(code: string): void {\n this.emit('chat:replaceCode', { code });\n }\n}\n"],"mappings":"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","names":["schema","userMsg","assistantMsg"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/bus/EventEmitter.ts","../src/completion/sqlCompletion.ts","../src/ai/aiCompletion.ts","../src/controllers/EditorController.ts","../src/controllers/AiChatController.ts","../src/bus/EditorBus.ts"],"sourcesContent":["export const SQL_KEYWORDS = [\n 'SELECT', 'FROM', 'WHERE', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE',\n 'CREATE', 'TABLE', 'DROP', 'ALTER', 'ADD', 'COLUMN', 'INDEX', 'VIEW', 'DATABASE',\n 'SCHEMA', 'TRUNCATE', 'RENAME', 'AS', 'ON', 'JOIN', 'INNER', 'LEFT', 'RIGHT',\n 'FULL', 'OUTER', 'CROSS', 'NATURAL', 'USING', 'AND', 'OR', 'NOT', 'IN', 'EXISTS',\n 'BETWEEN', 'LIKE', 'IS', 'NULL', 'TRUE', 'FALSE', 'CASE', 'WHEN', 'THEN', 'ELSE',\n 'END', 'IF', 'UNION', 'ALL', 'DISTINCT', 'ORDER', 'BY', 'ASC', 'DESC', 'GROUP',\n 'HAVING', 'LIMIT', 'OFFSET', 'FETCH', 'NEXT', 'ROWS', 'ONLY', 'WITH', 'RECURSIVE',\n 'PRIMARY', 'KEY', 'FOREIGN', 'REFERENCES', 'UNIQUE', 'NOT NULL', 'DEFAULT',\n 'CHECK', 'CONSTRAINT', 'AUTO_INCREMENT', 'IDENTITY', 'SEQUENCE', 'GRANT',\n 'REVOKE', 'COMMIT', 'ROLLBACK', 'TRANSACTION', 'BEGIN', 'SAVEPOINT', 'EXPLAIN',\n];\n\nexport const SQL_FUNCTIONS = [\n 'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'COALESCE', 'NULLIF', 'IFNULL', 'NVL',\n 'CONCAT', 'LENGTH', 'SUBSTR', 'SUBSTRING', 'TRIM', 'LTRIM', 'RTRIM', 'UPPER',\n 'LOWER', 'REPLACE', 'INSTR', 'LPAD', 'RPAD', 'CHAR_LENGTH', 'POSITION',\n 'NOW', 'CURDATE', 'CURTIME', 'DATE', 'TIME', 'YEAR', 'MONTH', 'DAY',\n 'HOUR', 'MINUTE', 'SECOND', 'DATEDIFF', 'DATE_ADD', 'DATE_SUB', 'DATEADD',\n 'DATESUB', 'EXTRACT', 'TO_DATE', 'TO_CHAR', 'DATE_FORMAT', 'TIMESTAMPDIFF',\n 'ROUND', 'CEIL', 'FLOOR', 'ABS', 'MOD', 'POWER', 'SQRT', 'SIGN', 'RAND',\n 'CAST', 'CONVERT', 'ROW_NUMBER', 'RANK', 'DENSE_RANK', 'NTILE', 'LAG', 'LEAD',\n 'FIRST_VALUE', 'LAST_VALUE', 'OVER', 'PARTITION', 'LISTAGG', 'GROUP_CONCAT',\n 'STRING_AGG', 'JSON_OBJECT', 'JSON_ARRAY', 'JSON_EXTRACT', 'ISNULL',\n];\n\nexport const SQL_DATA_TYPES = [\n 'INT', 'INTEGER', 'BIGINT', 'SMALLINT', 'TINYINT', 'DECIMAL', 'NUMERIC',\n 'FLOAT', 'DOUBLE', 'REAL', 'CHAR', 'VARCHAR', 'TEXT', 'NCHAR', 'NVARCHAR',\n 'NTEXT', 'DATE', 'TIME', 'DATETIME', 'TIMESTAMP', 'BOOLEAN', 'BOOL',\n 'BLOB', 'CLOB', 'BINARY', 'VARBINARY', 'JSON', 'UUID', 'SERIAL',\n];\n\nexport const LANGUAGES = [\n 'javascript',\n 'typescript',\n 'python',\n 'json',\n 'css',\n 'html',\n 'markdown',\n 'rust',\n 'go',\n 'sql',\n] as const;\n\n/** Monaco 编辑器支持的 UI 本地化语言 */\nexport const LOCALES = {\n ZH_CN: 'zh-cn',\n EN: 'en',\n DE: 'de',\n ES: 'es',\n FR: 'fr',\n IT: 'it',\n JA: 'ja',\n KO: 'ko',\n RU: 'ru',\n} as const;\n\nexport type Locale = (typeof LOCALES)[keyof typeof LOCALES];\n\nexport const THEMES = [\n { value: 'vs-dark', label: 'Dark' },\n { value: 'light', label: 'Light' },\n { value: 'hc-black', label: 'High Contrast' },\n] as const;\n\nexport const AI_INLINE_LANGUAGES = [\n 'typescript', 'javascript', 'python', 'sql',\n 'java', 'cpp', 'csharp', 'go', 'rust',\n];\n","/**\n * 极简事件发射器,框架无关。\n * 用于 EditorController / AiChatController / EditorBus 之间的事件通信。\n */\nexport type Listener<T> = (payload: T) => void;\n\nexport class EventEmitter<EventMap> {\n private listeners: { [K in keyof EventMap]?: Set<Listener<EventMap[K]>> } = {};\n\n on<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): () => void {\n if (!this.listeners[event]) this.listeners[event] = new Set();\n this.listeners[event]!.add(listener);\n return () => this.off(event, listener);\n }\n\n off<K extends keyof EventMap>(event: K, listener: Listener<EventMap[K]>): void {\n this.listeners[event]?.delete(listener);\n }\n\n emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.listeners[event]?.forEach((listener) => {\n try {\n listener(payload);\n } catch (err) {\n console.error(`[EventEmitter] listener for \"${String(event)}\" threw:`, err);\n }\n });\n }\n\n removeAllListeners(): void {\n this.listeners = {};\n }\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { SQL_KEYWORDS, SQL_FUNCTIONS, SQL_DATA_TYPES } from '../constants';\nimport type { SqlSchema } from '../types';\n\n/** 从 SQL 文档中动态解析表名、CTE 别名和变量 */\nfunction parseDynamicItems(sql: string): { tables: string[]; variables: string[] } {\n const tables: string[] = [];\n const variables: string[] = [];\n let m: RegExpExecArray | null;\n\n const tableRe = /\\b(?:FROM|JOIN|UPDATE|INTO|TABLE)\\s+([`\"']?\\w+[`\"']?)/gi;\n while ((m = tableRe.exec(sql)) !== null) {\n const name = m[1].replace(/[`\"']/g, '');\n if (!tables.includes(name)) tables.push(name);\n }\n\n const cteRe = /\\bWITH\\s+(\\w+)\\s+AS\\s*\\(/gi;\n while ((m = cteRe.exec(sql)) !== null) {\n if (!tables.includes(m[1])) tables.push(m[1]);\n }\n\n const declareRe = /\\bDECLARE\\s+(@?\\w+)/gi;\n while ((m = declareRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const setVarRe = /\\bSET\\s+(@\\w+)\\s*=/gi;\n while ((m = setVarRe.exec(sql)) !== null) {\n if (!variables.includes(m[1])) variables.push(m[1]);\n }\n\n const atVarRe = /@(\\w+)/g;\n while ((m = atVarRe.exec(sql)) !== null) {\n const v = `@${m[1]}`;\n if (!variables.includes(v)) variables.push(v);\n }\n\n return { tables, variables };\n}\n\n/**\n * 注册 SQL 内置补全提供者。\n * schemaRef 使用 ref 模式以支持动态更新。\n * excludeLabelsRef(可选)使用 ref 模式,提供需要从内置关键字/函数中排除的 label\n * (大写匹配)。用于让使用方的自定义词表覆盖内置同名项,避免重复提示。\n */\nexport function registerSqlCompletion(\n monaco: typeof MonacoType,\n schemaRef: { readonly current: SqlSchema },\n excludeLabelsRef?: { readonly current: Set<string> },\n): MonacoType.IDisposable {\n return monaco.languages.registerCompletionItemProvider('sql', {\n triggerCharacters: ['.'],\n provideCompletionItems(model, position, context) {\n const word = model.getWordUntilPosition(position);\n const range: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: word.startColumn,\n endColumn: word.endColumn,\n };\n\n // 点号触发:提示该表的列名\n if (context.triggerCharacter === '.') {\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforeDot = lineText.substring(0, position.column - 2);\n const tableMatch = textBeforeDot.match(/(\\w+)$/);\n if (tableMatch) {\n const typed = tableMatch[1].toUpperCase();\n const schema = schemaRef.current;\n const tableKey = Object.keys(schema).find((k) => k.toUpperCase() === typed);\n if (tableKey) {\n const colRange: MonacoType.IRange = {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n };\n return {\n suggestions: schema[tableKey].map((col) => ({\n label: col,\n kind: monaco.languages.CompletionItemKind.Field,\n insertText: col,\n range: colRange,\n detail: `${tableKey} · 列`,\n documentation: `表 ${tableKey} 的字段`,\n })),\n };\n }\n }\n return { suggestions: [] };\n }\n\n // 普通触发:关键字 + 函数 + 类型 + 表名 + 变量\n const fullText = model.getValue();\n const { tables: dynamicTables, variables } = parseDynamicItems(fullText);\n const schema = schemaRef.current;\n const schemaTables = Object.keys(schema);\n const allTables = [...new Set([...schemaTables, ...dynamicTables])];\n\n // 需要排除的内置 label(大写匹配),让使用方自定义词表覆盖同名项\n const exclude = excludeLabelsRef?.current;\n const isExcluded = (label: string) => exclude?.has(label.toUpperCase()) ?? false;\n\n const keywords = SQL_KEYWORDS.filter((kw) => !isExcluded(kw)).map((kw) => ({\n label: kw,\n kind: monaco.languages.CompletionItemKind.Keyword,\n insertText: kw,\n range,\n detail: 'SQL 关键字',\n }));\n\n const functions = SQL_FUNCTIONS.filter((fn) => !isExcluded(fn)).map((fn) => ({\n label: fn,\n kind: monaco.languages.CompletionItemKind.Function,\n insertText: `${fn}($1)`,\n insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,\n range,\n detail: 'SQL 函数',\n }));\n\n const dataTypes = SQL_DATA_TYPES.map((dt) => ({\n label: dt,\n kind: monaco.languages.CompletionItemKind.TypeParameter,\n insertText: dt,\n range,\n detail: 'SQL 数据类型',\n }));\n\n const tableItems = allTables.map((t) => ({\n label: t,\n kind: monaco.languages.CompletionItemKind.Class,\n insertText: t,\n range,\n detail: schemaTables.includes(t) ? '表名 (Schema)' : '表名 (文档)',\n }));\n\n const variableItems = variables.map((v) => ({\n label: v,\n kind: monaco.languages.CompletionItemKind.Variable,\n insertText: v,\n range,\n detail: 'SQL 变量',\n }));\n\n return {\n suggestions: [...keywords, ...functions, ...dataTypes, ...tableItems, ...variableItems],\n };\n },\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport type { ApiConfig, PendingCompletion } from '../types';\nimport { AI_INLINE_LANGUAGES } from '../constants';\n\n/** 去除模型返回中可能包含的代码围栏(```lang ... ```) */\nfunction stripCodeFence(text: string): string {\n return text.replace(/^```[a-z]*\\n?/, '').replace(/\\n?```$/, '');\n}\n\nconst SPINNER_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'] as const;\n\nfunction ensureSpinnerStyle() {\n const id = 'mae-ai-completion-spinner-style';\n if (typeof document === 'undefined' || document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n const frameCss = SPINNER_FRAMES.map((ch, i) => `.mae-ai-spinner-f${i}::after { content: \" ${ch}\"; }`).join('\\n');\n style.textContent = `\n@keyframes mae-ai-completion-glow {\n 0%, 100% { text-shadow: 0 0 3px rgba(96, 165, 250, 0.35); }\n 50% { text-shadow: 0 0 9px rgba(96, 165, 250, 0.95), 0 0 18px rgba(59, 130, 246, 0.35); }\n}\n${frameCss}\n[class^=\"mae-ai-spinner-f\"]::after {\n color: #60a5fa;\n font-family: \"Segoe UI Symbol\", \"Noto Sans Symbols\", \"Apple Symbols\", monospace;\n display: inline-block;\n margin-left: 2px;\n animation: mae-ai-completion-glow 1s ease-in-out infinite;\n}`;\n document.head.appendChild(style);\n}\n\nfunction createCursorSpinner(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n line: number,\n col: number,\n): () => void {\n ensureSpinnerStyle();\n let frameIdx = 0;\n const makeDecor = () => [{\n range: { startLineNumber: line, startColumn: col, endLineNumber: line, endColumn: col },\n options: { afterContentClassName: `mae-ai-spinner-f${frameIdx}` },\n }];\n const collection = editor.createDecorationsCollection(makeDecor());\n const timer = setInterval(() => {\n frameIdx = (frameIdx + 1) % SPINNER_FRAMES.length;\n collection.set(makeDecor());\n }, 80);\n return () => {\n clearInterval(timer);\n collection.clear();\n };\n}\n\n/** 默认 system prompt:行内补全 */\nconst DEFAULT_COMPLETION_SYSTEM = '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。';\n\n/** 构建行内补全请求体:读 config.completion 覆盖,默认思考关闭、max_tokens 512 */\nfunction buildRequestBody(\n config: ApiConfig,\n context: string,\n prefix: string,\n stream: boolean,\n): Record<string, unknown> {\n const ov = config.completion ?? {};\n // 思考开关优先级:completion.thinking > 顶层 thinking > 默认 disabled\n const thinking = ov.thinking ?? config.thinking ?? { type: 'disabled' as const };\n const body: Record<string, unknown> = {\n model: ov.model ?? config.model,\n messages: [\n { role: 'system', content: ov.systemPrompt ?? DEFAULT_COMPLETION_SYSTEM },\n { role: 'user', content: `代码上下文:\\n${context}\\n\\n前缀:${prefix}\\n\\n请继续补全这段代码,只返回补全部分。` },\n ],\n max_tokens: ov.maxTokens ?? 512,\n stream,\n };\n body.thinking = thinking;\n if (ov.temperature !== undefined) body.temperature = ov.temperature;\n return body;\n}\n\n/** 非流式调用 OpenAI 兼容 API(使用原生 fetch,无 axios 依赖) */\nexport async function fetchAiCompletionNonStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n signal?: AbortSignal,\n): Promise<string> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify(buildRequestBody(config, context, prefix, false)),\n signal,\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n const data = (await response.json()) as { choices?: Array<{ message?: { content?: string } }> };\n return stripCodeFence(data.choices?.[0]?.message?.content?.trim() ?? '');\n}\n\n/** 流式调用(fetch + ReadableStream) */\nexport async function fetchAiCompletionStream(\n config: ApiConfig,\n context: string,\n prefix: string,\n onChunk: (accumulated: string) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const response = await fetch(`${config.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },\n body: JSON.stringify(buildRequestBody(config, context, prefix, true)),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${await response.text().catch(() => '')}`);\n }\n if (!response.body) throw new Error('Response body is null');\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let accumulated = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data:')) continue;\n const data = trimmed.slice(5).trim();\n if (data === '[DONE]') return;\n try {\n const parsed = JSON.parse(data) as { choices?: Array<{ delta?: { content?: string } }> };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n accumulated += delta;\n onChunk(accumulated);\n }\n } catch {\n // ignore malformed lines\n }\n }\n }\n}\n\n/** 注册 AI 内联幽灵文本提供者 */\nexport function registerAiInlineCompletion(\n monaco: typeof MonacoType,\n pendingRef: { current: PendingCompletion | null },\n): void {\n AI_INLINE_LANGUAGES.forEach((lang) => {\n monaco.languages.registerInlineCompletionsProvider(lang, {\n provideInlineCompletions: (_model, position) => {\n const pending = pendingRef.current;\n if (!pending) return { items: [] };\n if (pending.lineNumber !== position.lineNumber || pending.column !== position.column) {\n pendingRef.current = null;\n return { items: [] };\n }\n return {\n items: [\n {\n insertText: pending.insertText,\n range: {\n startLineNumber: position.lineNumber,\n endLineNumber: position.lineNumber,\n startColumn: position.column,\n endColumn: position.column,\n },\n },\n ],\n };\n },\n disposeInlineCompletions: () => {},\n });\n });\n}\n\n/**\n * 注册 AI 补全命令(Ctrl+Alt+L 手动触发,流式更新幽灵文本)。\n * 框架无关:通过函数引用方式读取最新的 apiConfig。\n */\nexport function registerAiCompletionCommand(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n getApiConfig: () => ApiConfig | null,\n pendingRef: { current: PendingCompletion | null },\n onLoadingChange?: (loading: boolean) => void,\n onError?: (message: string) => void,\n): MonacoType.IDisposable {\n let currentAbortController: AbortController | null = null;\n\n const isAbortError = (err: unknown): boolean =>\n err instanceof Error && (err.name === 'AbortError' || err.message?.includes('aborted'));\n\n const triggerAiCompletion = async () => {\n const apiConfig = getApiConfig();\n if (!apiConfig || !apiConfig.apiKey.trim()) {\n onError?.('未配置 API Key,请先配置 AI 服务再使用补全功能。');\n return;\n }\n\n const position = editor.getPosition();\n if (!position) return;\n const model = editor.getModel();\n if (!model) return;\n\n const lineText = model.getLineContent(position.lineNumber);\n const textBeforePosition = lineText.substring(0, position.column - 1);\n if (!textBeforePosition.trim()) return;\n\n const startLine = Math.max(0, position.lineNumber - 5);\n const contextLines: string[] = [];\n for (let i = startLine; i < position.lineNumber; i++) {\n contextLines.push(model.getLineContent(i + 1));\n }\n const contextCode = contextLines.join('\\n');\n\n currentAbortController?.abort();\n currentAbortController = new AbortController();\n pendingRef.current = null;\n\n const stopSpinner = createCursorSpinner(editor, position.lineNumber, position.column);\n onLoadingChange?.(true);\n\n const useStream = apiConfig.streamMode !== false;\n\n try {\n if (useStream) {\n let triggerTimer: ReturnType<typeof setTimeout> | null = null;\n const scheduleTrigger = () => {\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n triggerTimer = setTimeout(() => {\n triggerTimer = null;\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n }, 80);\n };\n\n await fetchAiCompletionStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n (accumulated) => {\n let insertText = stripCodeFence(accumulated);\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n scheduleTrigger();\n },\n currentAbortController.signal,\n );\n\n if (triggerTimer !== null) clearTimeout(triggerTimer);\n if (pendingRef.current) {\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } else {\n const completion = await fetchAiCompletionNonStream(\n apiConfig,\n contextCode,\n textBeforePosition,\n currentAbortController.signal,\n );\n if (!completion) return;\n let insertText = completion;\n if (insertText.startsWith(textBeforePosition)) {\n insertText = insertText.slice(textBeforePosition.length);\n }\n if (!insertText.trim()) return;\n pendingRef.current = {\n lineNumber: position.lineNumber,\n column: position.column,\n insertText,\n };\n editor.trigger('ai', 'editor.action.inlineSuggest.trigger', {});\n }\n } catch (err) {\n if (isAbortError(err)) return;\n const msg = err instanceof Error ? err.message : String(err);\n onError?.(`AI 补全失败:${msg}`);\n console.error('[AI Completion] Error:', err);\n } finally {\n stopSpinner();\n onLoadingChange?.(false);\n }\n };\n\n return editor.onKeyDown((e) => {\n if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === 'KeyL') {\n e.preventDefault();\n void triggerAiCompletion();\n }\n });\n}\n","import type * as MonacoType from 'monaco-editor';\nimport { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, PendingCompletion, SqlSchema, CompletionProvider } from '../types';\nimport { registerSqlCompletion } from '../completion/sqlCompletion';\nimport { registerAiInlineCompletion } from '../ai/aiCompletion';\n\nexport interface EditorControllerEvents {\n change: { value: string };\n cursor: { line: number; column: number };\n ready: { editor: MonacoType.editor.IStandaloneCodeEditor };\n languageChange: { language: string };\n focus: void;\n blur: void;\n}\n\nexport interface EditorControllerOptions {\n container: HTMLElement;\n language?: string;\n theme?: string;\n value?: string;\n monaco: typeof MonacoType;\n /** Monaco loader monaco-editor 路径配置 */\n vsPath?: string;\n sqlSchema?: SqlSchema;\n apiConfig?: ApiConfig | null;\n completionProviders?: CompletionProvider[];\n /** Monaco editor options */\n editorOptions?: MonacoType.editor.IStandaloneEditorConstructionOptions;\n}\n\n/**\n * 框架无关的编辑器控制器。\n * 封装 Monaco 实例的生命周期、核心操作、补全注册。\n * 通过 EventEmitter 暴露编辑器事件,不依赖任何 UI 框架。\n */\nexport class EditorController extends EventEmitter<EditorControllerEvents> {\n private editor: MonacoType.editor.IStandaloneCodeEditor | null = null;\n private monaco: typeof MonacoType;\n private sqlProviderRegistered = false;\n private aiProviderRegistered = false;\n private pendingCompletionRef = { current: null as PendingCompletion | null };\n private customProviders: CompletionProvider[] = [];\n private disposables: MonacoType.IDisposable[] = [];\n\n completed = false;\n error: Error | null = null;\n\n constructor(private options: EditorControllerOptions) {\n super();\n this.monaco = options.monaco;\n this.customProviders = options.completionProviders ?? [];\n this.init();\n }\n\n private init(): void {\n const { language, theme, value, sqlSchema, apiConfig, editorOptions } = this.options;\n\n // 注册 SQL 补全(只注册一次)\n if (!this.sqlProviderRegistered) {\n const schemaRef = { current: sqlSchema ?? {} };\n registerSqlCompletion(this.monaco, schemaRef);\n this.sqlProviderRegistered = true;\n }\n\n // 注册 AI 幽灵文本提供者\n if (!this.aiProviderRegistered) {\n registerAiInlineCompletion(this.monaco, this.pendingCompletionRef);\n this.aiProviderRegistered = true;\n }\n\n // 注册自定义补全提供者\n this.registerCustomCompletionProviders();\n\n // 创建编辑器\n this.editor = this.monaco.editor.create(this.options.container, {\n value: value ?? '',\n language: language ?? 'typescript',\n theme: theme ?? 'vs-dark',\n fontSize: 14,\n minimap: { enabled: true },\n scrollBeyondLastLine: false,\n automaticLayout: true,\n lineNumbers: 'on',\n renderLineHighlight: 'all',\n smoothScrolling: true,\n cursorBlinking: 'smooth',\n bracketPairColorization: { enabled: true },\n tabSize: 2,\n wordWrap: 'on',\n folding: true,\n formatOnPaste: true,\n suggestOnTriggerCharacters: true,\n quickSuggestions: { other: true, comments: false, strings: false },\n acceptSuggestionOnCommitCharacter: true,\n acceptSuggestionOnEnter: 'on',\n inlineSuggest: { enabled: true },\n tabCompletion: 'on',\n ...editorOptions,\n });\n\n // 绑定事件\n this.bindEditorEvents();\n this.emit('ready', { editor: this.editor });\n }\n\n private bindEditorEvents(): void {\n const editor = this.editor!;\n\n const d1 = editor.onDidChangeModelContent(() => {\n this.emit('change', { value: editor.getValue() });\n });\n\n const d2 = editor.onDidChangeCursorPosition((e) => {\n this.emit('cursor', {\n line: e.position.lineNumber,\n column: e.position.column,\n });\n });\n\n const d3 = editor.onDidFocusEditorText(() => this.emit('focus', undefined));\n const d4 = editor.onDidBlurEditorText(() => this.emit('blur', undefined));\n\n this.disposables.push(d1, d2, d3, d4);\n }\n\n private registerCustomCompletionProviders(): void {\n if (this.customProviders.length === 0) return;\n\n for (const provider of this.customProviders) {\n const langs = provider.languages ?? ['*'];\n for (const lang of langs) {\n this.monaco.languages.registerCompletionItemProvider(lang, {\n triggerCharacters: provider.triggerCharacters,\n provideCompletionItems: async (model, position, context) => {\n const ctx = {\n monaco: this.monaco,\n model,\n position,\n lineText: model.getLineContent(position.lineNumber),\n currentWord: model.getWordUntilPosition(position).word,\n fullText: model.getValue(),\n triggerCharacter: context.triggerCharacter,\n };\n\n if (provider.shouldTrigger && !provider.shouldTrigger(ctx)) {\n return { suggestions: [] };\n }\n\n const suggestions = await provider.provide(ctx);\n return { suggestions };\n },\n });\n }\n }\n }\n\n // ─── 公开 API ──────────────────────────────────────────────────────────\n\n getEditor(): MonacoType.editor.IStandaloneCodeEditor | null {\n return this.editor;\n }\n\n getValue(): string {\n return this.editor?.getValue() ?? '';\n }\n\n setValue(value: string): void {\n this.editor?.setValue(value);\n }\n\n insertText(text: string, range?: MonacoType.IRange): void {\n const editor = this.editor;\n if (!editor) return;\n const targetRange = range ?? editor.getSelection();\n if (targetRange) {\n editor.executeEdits('controller-insert', [{ range: targetRange, text }]);\n editor.focus();\n }\n }\n\n format(): void {\n this.editor?.getAction('editor.action.formatDocument')?.run();\n }\n\n focus(): void {\n this.editor?.focus();\n }\n\n setLanguage(language: string): void {\n const model = this.editor?.getModel();\n if (model) {\n this.monaco.editor.setModelLanguage(model, language);\n this.emit('languageChange', { language });\n }\n }\n\n setTheme(theme: string): void {\n this.monaco.editor.setTheme(theme);\n }\n\n getCursorPosition(): { line: number; column: number } {\n const pos = this.editor?.getPosition();\n return pos\n ? { line: pos.lineNumber, column: pos.column }\n : { line: 1, column: 1 };\n }\n\n getSelection(): MonacoType.IRange | null {\n return this.editor?.getSelection() ?? null;\n }\n\n /**\n * 触发 AI 行内补全(Ctrl+Alt+L 快捷键)。\n * 需要提前设置 apiConfig(通过 setApiConfig 或构造函数传入)。\n */\n setApiConfig(config: ApiConfig | null): void {\n this.options.apiConfig = config;\n }\n\n getPendingCompletionRef(): { current: PendingCompletion | null } {\n return this.pendingCompletionRef;\n }\n\n dispose(): void {\n for (const d of this.disposables) d.dispose();\n this.disposables = [];\n this.editor?.dispose();\n this.editor = null;\n this.removeAllListeners();\n }\n}","import { EventEmitter } from '../bus/EventEmitter';\nimport type { ApiConfig, ChatMessage } from '../types';\n\nexport interface AiChatControllerEvents {\n messageAdded: ChatMessage;\n messageUpdated: ChatMessage;\n cleared: void;\n loadingChange: { loading: boolean };\n error: { message: string };\n}\n\nfunction generateUUID(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * AI 聊天控制器:管理消息列表、API 调用与流式响应。\n * 框架无关:通过事件通知 UI 层更新。\n */\nexport class AiChatController extends EventEmitter<AiChatControllerEvents> {\n private messages: ChatMessage[] = [];\n private abortController: AbortController | null = null;\n private loading = false;\n private apiConfig: ApiConfig;\n\n constructor(apiConfig: ApiConfig) {\n super();\n this.apiConfig = apiConfig;\n }\n\n setApiConfig(config: ApiConfig): void {\n this.apiConfig = config;\n }\n\n getApiConfig(): ApiConfig {\n return this.apiConfig;\n }\n\n getMessages(): readonly ChatMessage[] {\n return this.messages;\n }\n\n isLoading(): boolean {\n return this.loading;\n }\n\n /** 发送消息,可选携带编辑器上下文 */\n async send(\n userInput: string,\n options?: { editorContent?: string; language?: string },\n ): Promise<void> {\n const trimmed = userInput.trim();\n if (!trimmed || this.loading) return;\n\n if (!this.apiConfig.apiKey.trim()) {\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '⚠️ 尚未配置 API Key,请配置 Base URL、API Key 和模型名称后再开始对话。',\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n return;\n }\n\n const userMsg: ChatMessage = { id: generateUUID(), role: 'user', content: trimmed };\n this.messages.push(userMsg);\n this.emit('messageAdded', userMsg);\n\n const assistantMsg: ChatMessage = {\n id: generateUUID(),\n role: 'assistant',\n content: '',\n isStreaming: true,\n };\n this.messages.push(assistantMsg);\n this.emit('messageAdded', assistantMsg);\n\n this.loading = true;\n this.emit('loadingChange', { loading: true });\n\n try {\n this.abortController = new AbortController();\n\n const systemPrompt = options?.language\n ? `You are an expert coding assistant. The user is working with ${options.language} code. Respond concisely in the same language as the user's message, defaulting to Chinese.`\n : \"You are an expert coding assistant. Respond concisely in the same language as the user's message, defaulting to Chinese.\";\n\n const historyForApi = this.messages\n .filter((m) => m.id !== assistantMsg.id)\n .map((m) => ({ role: m.role, content: m.content }));\n\n // 对话聊天场景级覆盖:chat.thinking > 顶层 thinking > 默认 enabled\n const chatOv = this.apiConfig.chat ?? {};\n const thinking =\n chatOv.thinking ?? this.apiConfig.thinking ?? ({ type: 'enabled' as const });\n const chatBody: Record<string, unknown> = {\n model: chatOv.model ?? this.apiConfig.model,\n messages: [\n { role: 'system', content: chatOv.systemPrompt ?? systemPrompt },\n ...historyForApi,\n ],\n max_tokens: chatOv.maxTokens ?? 4096,\n stream: true,\n thinking,\n };\n if (chatOv.temperature !== undefined) chatBody.temperature = chatOv.temperature;\n\n const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiConfig.apiKey}`,\n },\n body: JSON.stringify(chatBody),\n signal: this.abortController.signal,\n });\n\n if (!response.ok) {\n let errText = '';\n try {\n errText = await response.text();\n } catch {\n /* ignore */\n }\n let hint = '';\n if (response.status === 401) hint = '(API Key 无效或已过期)';\n else if (response.status === 403) hint = '(无访问权限,请检查 API Key 和 Base URL)';\n else if (response.status === 429) hint = '(请求过于频繁,请稍后再试)';\n else if (response.status >= 500) hint = '(服务端错误)';\n throw new Error(`HTTP ${response.status}${hint}${errText ? `\\n${errText}` : ''}`);\n }\n\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let fullContent = '';\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const data = line.slice(6).trim();\n if (data === '[DONE]') break;\n try {\n const parsed = JSON.parse(data) as {\n choices?: Array<{ delta?: { content?: string } }>;\n };\n const delta = parsed.choices?.[0]?.delta?.content ?? '';\n if (delta) {\n fullContent += delta;\n assistantMsg.content = fullContent;\n this.emit('messageUpdated', { ...assistantMsg });\n }\n } catch {\n /* ignore */\n }\n }\n }\n\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n } catch (err: unknown) {\n const isAbort = err instanceof Error && err.name === 'AbortError';\n const errMsg = err instanceof Error ? err.message : String(err);\n const isNetworkErr = err instanceof TypeError && errMsg.toLowerCase().includes('fetch');\n const errorContent = isAbort\n ? '⏹ 请求已取消'\n : isNetworkErr\n ? `⚠️ 网络错误,请检查 Base URL 和网络。\\n\\n${errMsg}`\n : `⚠️ 请求失败:${errMsg}`;\n assistantMsg.content = errorContent;\n assistantMsg.isStreaming = false;\n this.emit('messageUpdated', { ...assistantMsg });\n if (!isAbort) this.emit('error', { message: errMsg });\n } finally {\n this.loading = false;\n this.emit('loadingChange', { loading: false });\n }\n }\n\n stop(): void {\n this.abortController?.abort();\n }\n\n clear(): void {\n this.messages = [];\n this.emit('cleared', undefined);\n }\n\n dispose(): void {\n this.abortController?.abort();\n this.removeAllListeners();\n }\n}\n","import { EventEmitter } from './EventEmitter';\nimport type { EditorController } from '../controllers/EditorController';\nimport type { AiChatController } from '../controllers/AiChatController';\n\nexport interface EditorBusEvents {\n /** 编辑器已注册 */\n 'editor:ready': EditorController;\n /** 编辑器即将卸载 */\n 'editor:dispose': void;\n /** 编辑器内容变化 */\n 'editor:change': { value: string };\n /** 编辑器光标变化 */\n 'editor:cursor': { line: number; column: number };\n /** 编辑器语言变化 */\n 'editor:languageChange': { language: string };\n\n /** 聊天面板已注册 */\n 'chat:ready': AiChatController;\n /** 聊天面板卸载 */\n 'chat:dispose': void;\n /** 聊天面板请求向编辑器插入代码 */\n 'chat:insertCode': { code: string };\n /** 聊天面板请求替换编辑器全部内容 */\n 'chat:replaceCode': { code: string };\n}\n\n/**\n * 编辑器与聊天面板的通信总线。\n * 在两个组件都引入时由协调器(Coordinator)创建并共享,实现自动联动。\n * 当只引入其中一个组件时,bus 可为 null,组件正常独立工作。\n */\nexport class EditorBus extends EventEmitter<EditorBusEvents> {\n private editor: EditorController | null = null;\n private chat: AiChatController | null = null;\n\n registerEditor(controller: EditorController): () => void {\n this.editor = controller;\n\n // 桥接:编辑器事件 → bus 事件\n const offChange = controller.on('change', (data) => this.emit('editor:change', data));\n const offCursor = controller.on('cursor', (data) => this.emit('editor:cursor', data));\n const offLang = controller.on('languageChange', (data) => this.emit('editor:languageChange', data));\n\n // 桥接:bus 上的 chat 命令 → 编辑器操作\n const offInsert = this.on('chat:insertCode', ({ code }) => controller.insertText(code));\n const offReplace = this.on('chat:replaceCode', ({ code }) => controller.setValue(code));\n\n this.emit('editor:ready', controller);\n\n return () => {\n offChange();\n offCursor();\n offLang();\n offInsert();\n offReplace();\n if (this.editor === controller) {\n this.editor = null;\n this.emit('editor:dispose', undefined);\n }\n };\n }\n\n registerChat(controller: AiChatController): () => void {\n this.chat = controller;\n this.emit('chat:ready', controller);\n return () => {\n if (this.chat === controller) {\n this.chat = null;\n this.emit('chat:dispose', undefined);\n }\n };\n }\n\n getEditor(): EditorController | null {\n return this.editor;\n }\n\n getChat(): AiChatController | null {\n return this.chat;\n }\n\n /** 让聊天面板向编辑器请求当前内容 */\n getEditorContent(): string {\n return this.editor?.getValue() ?? '';\n }\n\n /** 让聊天面板向编辑器请求当前语言 */\n getEditorLanguage(): string | undefined {\n const editor = this.editor?.getEditor();\n return editor?.getModel()?.getLanguageId();\n }\n\n /** 让聊天面板请求向编辑器插入代码 */\n insertToEditor(code: string): void {\n this.emit('chat:insertCode', { code });\n }\n\n /** 让聊天面板请求替换编辑器全部内容 */\n replaceEditor(code: string): void {\n this.emit('chat:replaceCode', { code });\n }\n}\n"],"mappings":"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","names":["schema","userMsg","assistantMsg"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monaco-ai-editor/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework-agnostic core for Monaco AI editor (controllers, event bus, completion providers).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -53,6 +53,33 @@ function createCursorSpinner(
53
53
  };
54
54
  }
55
55
 
56
+ /** 默认 system prompt:行内补全 */
57
+ const DEFAULT_COMPLETION_SYSTEM = '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。';
58
+
59
+ /** 构建行内补全请求体:读 config.completion 覆盖,默认思考关闭、max_tokens 512 */
60
+ function buildRequestBody(
61
+ config: ApiConfig,
62
+ context: string,
63
+ prefix: string,
64
+ stream: boolean,
65
+ ): Record<string, unknown> {
66
+ const ov = config.completion ?? {};
67
+ // 思考开关优先级:completion.thinking > 顶层 thinking > 默认 disabled
68
+ const thinking = ov.thinking ?? config.thinking ?? { type: 'disabled' as const };
69
+ const body: Record<string, unknown> = {
70
+ model: ov.model ?? config.model,
71
+ messages: [
72
+ { role: 'system', content: ov.systemPrompt ?? DEFAULT_COMPLETION_SYSTEM },
73
+ { role: 'user', content: `代码上下文:\n${context}\n\n前缀:${prefix}\n\n请继续补全这段代码,只返回补全部分。` },
74
+ ],
75
+ max_tokens: ov.maxTokens ?? 512,
76
+ stream,
77
+ };
78
+ body.thinking = thinking;
79
+ if (ov.temperature !== undefined) body.temperature = ov.temperature;
80
+ return body;
81
+ }
82
+
56
83
  /** 非流式调用 OpenAI 兼容 API(使用原生 fetch,无 axios 依赖) */
57
84
  export async function fetchAiCompletionNonStream(
58
85
  config: ApiConfig,
@@ -63,21 +90,7 @@ export async function fetchAiCompletionNonStream(
63
90
  const response = await fetch(`${config.baseUrl}/chat/completions`, {
64
91
  method: 'POST',
65
92
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },
66
- body: JSON.stringify({
67
- model: config.model,
68
- messages: [
69
- {
70
- role: 'system',
71
- content: '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。',
72
- },
73
- {
74
- role: 'user',
75
- content: `代码上下文:\n${context}\n\n前缀:${prefix}\n\n请继续补全这段代码,只返回补全部分。`,
76
- },
77
- ],
78
- max_tokens: 1024,
79
- stream: false,
80
- }),
93
+ body: JSON.stringify(buildRequestBody(config, context, prefix, false)),
81
94
  signal,
82
95
  });
83
96
  if (!response.ok) {
@@ -98,21 +111,7 @@ export async function fetchAiCompletionStream(
98
111
  const response = await fetch(`${config.baseUrl}/chat/completions`, {
99
112
  method: 'POST',
100
113
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },
101
- body: JSON.stringify({
102
- model: config.model,
103
- messages: [
104
- {
105
- role: 'system',
106
- content: '你是一个代码补全助手。基于用户提供的代码上下文和前缀,生成短小精悍的代码补全。只返回补全的代码片段,不要解释。',
107
- },
108
- {
109
- role: 'user',
110
- content: `代码上下文:\n${context}\n\n前缀:${prefix}\n\n请继续补全这段代码,只返回补全部分。`,
111
- },
112
- ],
113
- max_tokens: 1024,
114
- stream: true,
115
- }),
114
+ body: JSON.stringify(buildRequestBody(config, context, prefix, true)),
116
115
  signal,
117
116
  });
118
117
 
@@ -100,17 +100,29 @@ export class AiChatController extends EventEmitter<AiChatControllerEvents> {
100
100
  .filter((m) => m.id !== assistantMsg.id)
101
101
  .map((m) => ({ role: m.role, content: m.content }));
102
102
 
103
+ // 对话聊天场景级覆盖:chat.thinking > 顶层 thinking > 默认 enabled
104
+ const chatOv = this.apiConfig.chat ?? {};
105
+ const thinking =
106
+ chatOv.thinking ?? this.apiConfig.thinking ?? ({ type: 'enabled' as const });
107
+ const chatBody: Record<string, unknown> = {
108
+ model: chatOv.model ?? this.apiConfig.model,
109
+ messages: [
110
+ { role: 'system', content: chatOv.systemPrompt ?? systemPrompt },
111
+ ...historyForApi,
112
+ ],
113
+ max_tokens: chatOv.maxTokens ?? 4096,
114
+ stream: true,
115
+ thinking,
116
+ };
117
+ if (chatOv.temperature !== undefined) chatBody.temperature = chatOv.temperature;
118
+
103
119
  const response = await fetch(`${this.apiConfig.baseUrl}/chat/completions`, {
104
120
  method: 'POST',
105
121
  headers: {
106
122
  'Content-Type': 'application/json',
107
123
  Authorization: `Bearer ${this.apiConfig.apiKey}`,
108
124
  },
109
- body: JSON.stringify({
110
- model: this.apiConfig.model,
111
- messages: [{ role: 'system', content: systemPrompt }, ...historyForApi],
112
- stream: true,
113
- }),
125
+ body: JSON.stringify(chatBody),
114
126
  signal: this.abortController.signal,
115
127
  });
116
128
 
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // ─── 类型 ──────────────────────────────────────────────────────────────
2
2
  export type {
3
3
  ApiConfig,
4
+ ScenarioOverrides,
4
5
  SqlSchema,
5
6
  PendingCompletion,
6
7
  ChatMessage,
package/src/types.ts CHANGED
@@ -1,5 +1,27 @@
1
1
  import type * as MonacoType from 'monaco-editor';
2
2
 
3
+ /**
4
+ * 场景级参数覆盖(优先级高于顶层同名字段)。
5
+ * 用于让「行内补全」和「对话聊天」使用不同的模型 / 思考策略 / token 预算等。
6
+ */
7
+ export interface ScenarioOverrides {
8
+ /** 覆盖顶层 model(如补全用 flash、聊天用 pro) */
9
+ model?: string;
10
+ /**
11
+ * 思考能力开关(智谱 GLM 等思考模型专用)。
12
+ * - `{ type: 'disabled' }` 关闭思考,模型直接输出 content
13
+ * - `{ type: 'enabled' }` 开启思考
14
+ * - 不传则沿用顶层 thinking
15
+ */
16
+ thinking?: { type: 'disabled' | 'enabled' };
17
+ /** 覆盖硬编码 max_tokens(默认补全 512、聊天 4096) */
18
+ maxTokens?: number;
19
+ /** 采样温度(0~2) */
20
+ temperature?: number;
21
+ /** 覆盖默认 system prompt */
22
+ systemPrompt?: string;
23
+ }
24
+
3
25
  /** AI API 配置(OpenAI 兼容协议) */
4
26
  export interface ApiConfig {
5
27
  baseUrl: string;
@@ -7,6 +29,18 @@ export interface ApiConfig {
7
29
  model: string;
8
30
  /** true = 流式输出(默认),false = 一次性返回 */
9
31
  streamMode?: boolean;
32
+ /**
33
+ * 顶层思考能力开关(智谱 GLM 等思考模型专用)。
34
+ * 对补全和聊天同时生效,但可被 completion/chat 中的同名字段覆盖。
35
+ * - `{ type: 'disabled' }` 关闭思考
36
+ * - `{ type: 'enabled' }` 开启思考
37
+ * - 不传:行内补全自动关闭思考,对话聊天自动开启思考
38
+ */
39
+ thinking?: { type: 'disabled' | 'enabled' };
40
+ /** 行内补全(幽灵提示)专用覆盖 */
41
+ completion?: ScenarioOverrides;
42
+ /** 对话聊天专用覆盖 */
43
+ chat?: ScenarioOverrides;
10
44
  }
11
45
 
12
46
  /** SQL 表结构 Schema:{ 表名: [列名, ...] } */