diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..89f0acdc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,31 @@ +# 强制使用 LF 换行符 +* text=auto eol=lf + +# 明确指定文本文件 +*.ts text eol=lf +*.tsx text eol=lf +*.js text eol=lf +*.jsx text eol=lf +*.vue text eol=lf +*.json text eol=lf +*.md text eol=lf +*.yml text eol=lf +*.yaml text eol=lf +*.css text eol=lf +*.scss text eol=lf +*.html text eol=lf +*.xml text eol=lf +*.txt text eol=lf +*.sh text eol=lf + +# 二进制文件 +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.woff binary +*.woff2 binary +*.ttf binary +*.eot binary +*.otf binary diff --git a/packages/extension/src/App.vue b/packages/extension/src/App.vue index 7f834351..c331342c 100644 --- a/packages/extension/src/App.vue +++ b/packages/extension/src/App.vue @@ -952,6 +952,7 @@ import { toRef, nextTick, onMounted, + type Ref, } from "vue"; import { useI18n } from "vue-i18n"; import { @@ -1045,6 +1046,7 @@ import type { import type { ModelSelectOption, TemplateSelectOption, + TestAreaPanelInstance, } from "@prompt-optimizer/ui"; // 1. 基础 composables @@ -1090,9 +1092,13 @@ const saveFavoriteData = ref<{ originalContent?: string; } | null>(null); const optimizeModelSelect = ref(null); -const testPanelRef = ref(null); -const systemWorkspaceRef = ref(null); -const userWorkspaceRef = ref(null); +type ContextWorkspaceExpose = { + testAreaPanelRef?: Ref; +}; + +const testPanelRef = ref(null); +const systemWorkspaceRef = ref(null); +const userWorkspaceRef = ref(null); const promptPanelRef = ref<{ refreshIterateTemplateSelect?: () => void; } | null>(null); @@ -2057,6 +2063,23 @@ const promptInputPlaceholder = computed(() => { }); // 真实测试处理函数 +const getActiveTestPanelInstance = (): TestAreaPanelInstance | null => { + if (functionMode.value === "pro") { + if (contextMode.value === "system") { + return ( + systemWorkspaceRef.value?.testAreaPanelRef?.value ?? null + ); + } + return userWorkspaceRef.value?.testAreaPanelRef?.value ?? null; + } + + if (functionMode.value === "basic") { + return testPanelRef.value; + } + + return null; +}; + const handleTestAreaTest = async (testVariables?: Record) => { // 调用 promptTester 的 executeTest 方法 await promptTester.executeTest( @@ -2065,7 +2088,7 @@ const handleTestAreaTest = async (testVariables?: Record) => { testContent.value, isCompareMode.value, testVariables, - testPanelRef.value + getActiveTestPanelInstance() ); }; diff --git a/packages/ui/.eslintrc.json b/packages/ui/.eslintrc.json index 2fe7708c..7d9fb71b 100644 --- a/packages/ui/.eslintrc.json +++ b/packages/ui/.eslintrc.json @@ -20,13 +20,19 @@ "node": true }, "rules": { - "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + }], "@typescript-eslint/no-explicit-any": "warn", "prefer-const": "error", "no-var": "error", "no-console": "off", "no-duplicate-imports": "error", "no-undef": "off", + "no-empty": ["error", { "allowEmptyCatch": true }], + "no-unused-vars": "off", "vue/multi-word-component-names": "off", "vue/no-v-html": "off", "vue/require-default-prop": "off", @@ -39,11 +45,23 @@ "parser": "vue-eslint-parser", "parserOptions": { "parser": "@typescript-eslint/parser" + }, + "rules": { + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^(props|emit|context|slots|attrs)$", + "destructuredArrayIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + }], + "no-unused-vars": "off" } }, { "files": ["*.ts", "*.tsx"], - "parser": "@typescript-eslint/parser" + "parser": "@typescript-eslint/parser", + "rules": { + "@typescript-eslint/no-unused-vars": "off" + } } ], "ignorePatterns": [ @@ -53,4 +71,4 @@ "*.cjs", "*.mjs" ] -} \ No newline at end of file +} diff --git a/packages/ui/env.d.ts b/packages/ui/env.d.ts index 553a8626..128cde31 100644 --- a/packages/ui/env.d.ts +++ b/packages/ui/env.d.ts @@ -1,7 +1,8 @@ /// declare module '*.vue' { - import type { DefineComponent } from 'vue' + import { type DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> export default component } diff --git a/packages/ui/src/components.d.ts b/packages/ui/src/components.d.ts index f635cc73..3f6e8109 100644 --- a/packages/ui/src/components.d.ts +++ b/packages/ui/src/components.d.ts @@ -1,12 +1,12 @@ -import type { DefineComponent } from 'vue' +import { type DefineComponent } from 'vue' declare module 'vue' { export interface GlobalComponents { - [key: string]: DefineComponent<{}, {}, any> + [key: string]: DefineComponent, Record, Record> } } declare module '*.vue' { - const component: DefineComponent<{}, {}, any> + const component: DefineComponent, Record, Record> export default component -} \ No newline at end of file +} diff --git a/packages/ui/src/components/ActionButton.vue b/packages/ui/src/components/ActionButton.vue index 43b87642..c2e2d749 100644 --- a/packages/ui/src/components/ActionButton.vue +++ b/packages/ui/src/components/ActionButton.vue @@ -21,6 +21,7 @@ diff --git a/packages/ui/src/components/PromptPreviewPanel.vue b/packages/ui/src/components/PromptPreviewPanel.vue index 8b535f47..09a0c8a5 100644 --- a/packages/ui/src/components/PromptPreviewPanel.vue +++ b/packages/ui/src/components/PromptPreviewPanel.vue @@ -83,6 +83,7 @@ \ No newline at end of file + name: "MessageApiInitializer", + setup() { + onMounted(() => { + try { + const messageApi = useMessage(); + setGlobalMessageApi(messageApi); + console.log("[Toast] Message API initialized successfully"); + } catch (error) { + console.warn( + "[Toast] Message API initialization failed (this is normal during SSR or when provider is not ready):", + error, + ); + } + }); + return () => h("div", { style: { display: "none" } }); + }, +}); + diff --git a/packages/ui/src/components/ToolCallDisplay.vue b/packages/ui/src/components/ToolCallDisplay.vue index d86c82d8..f6d14fd6 100644 --- a/packages/ui/src/components/ToolCallDisplay.vue +++ b/packages/ui/src/components/ToolCallDisplay.vue @@ -87,6 +87,7 @@ diff --git a/packages/ui/src/components/context-mode/ContextUserWorkspace.vue b/packages/ui/src/components/context-mode/ContextUserWorkspace.vue index b5422f10..825aef42 100644 --- a/packages/ui/src/components/context-mode/ContextUserWorkspace.vue +++ b/packages/ui/src/components/context-mode/ContextUserWorkspace.vue @@ -246,7 +246,8 @@ * /> * ``` */ -import { ref, computed } from "vue"; +import { ref, computed } from 'vue' + import { useI18n } from "vue-i18n"; import { NCard, NFlex, NButton, NText, NTag } from "naive-ui"; import { useBreakpoints } from "@vueuse/core"; @@ -254,7 +255,13 @@ import InputPanelUI from "../InputPanel.vue"; import PromptPanelUI from "../PromptPanel.vue"; import TestAreaPanel from "../TestAreaPanel.vue"; import type { OptimizationMode } from "../../types"; -import type { IServices } from "@prompt-optimizer/core"; +import type { + IServices, + PromptRecord, + Template, +} from "@prompt-optimizer/core"; +import type { TestAreaPanelInstance } from "../types/test-area"; +import type { IteratePayload, SaveFavoritePayload } from "../../types/workspace"; // ======================== // 响应式断点配置 @@ -289,11 +296,11 @@ interface Props { // --- 版本管理 --- /** 历史版本列表 */ - versions: any[]; + versions: PromptRecord[]; /** 当前版本 ID */ currentVersionId: string | null; /** 选中的迭代模板 */ - selectedIterateTemplate: any; + selectedIterateTemplate: Template | null; // --- 测试数据 --- /** 测试输入内容 */ @@ -341,7 +348,7 @@ const emit = defineEmits<{ // --- 数据更新事件 --- "update:prompt": [value: string]; "update:optimizedPrompt": [value: string]; - "update:selectedIterateTemplate": [value: any]; + "update:selectedIterateTemplate": [value: Template | null]; "update:testContent": [value: string]; "update:isCompareMode": [value: boolean]; @@ -349,15 +356,15 @@ const emit = defineEmits<{ /** 执行优化 */ optimize: []; /** 执行迭代优化 */ - iterate: [payload: any]; + iterate: [payload: IteratePayload]; /** 执行测试 (传递测试变量) */ test: [testVariables: Record]; /** 切换对比模式 */ "compare-toggle": []; /** 切换历史版本 */ - "switch-version": [versionId: any]; + "switch-version": [version: PromptRecord]; /** 保存到收藏 */ - "save-favorite": [data: any]; + "save-favorite": [data: SaveFavoritePayload]; // --- 打开面板/管理器 --- /** 打开全局变量管理器 */ @@ -427,7 +434,7 @@ const predefinedVariableValues = computed(() => ({ ...props.predefinedVariables // 组件引用 // ======================== /** TestAreaPanel 组件引用,用于获取测试变量 */ -const testAreaPanelRef = ref | null>(null); +const testAreaPanelRef = ref(null); // ======================== // 事件处理 @@ -579,4 +586,9 @@ const handleTestWithVariables = async () => { emit("test", {}); } }; + +// 暴露 TestAreaPanel 引用给父组件(用于工具调用等高级功能) +defineExpose({ + testAreaPanelRef +}); diff --git a/packages/ui/src/components/context-mode/ConversationManager.vue b/packages/ui/src/components/context-mode/ConversationManager.vue index 77f8b73c..3cdfd49f 100644 --- a/packages/ui/src/components/context-mode/ConversationManager.vue +++ b/packages/ui/src/components/context-mode/ConversationManager.vue @@ -427,7 +427,8 @@