mirror of
https://github.com/linshenkx/prompt-optimizer.git
synced 2026-05-06 21:50:27 +08:00
build(deps): align toolchain peers and replace npm-run-all
- align TypeScript with the current eslint peer range across packages - replace npm-run-all with a local run-many script and test coverage - tighten remaining mcp-server typing so the package lint stays clean - update the lockfile after removing redundant root-level tooling deps
This commit is contained in:
28
package.json
28
package.json
@@ -9,24 +9,24 @@
|
||||
"yarn": "请使用pnpm代替yarn"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm-run-all build:core build:ui build:parallel",
|
||||
"build": "node scripts/run-many.js build:core build:ui build:parallel",
|
||||
"build:core": "pnpm -F @prompt-optimizer/core build",
|
||||
"build:ui": "pnpm -F @prompt-optimizer/ui build",
|
||||
"build:parallel": "npm-run-all --parallel build:web build:ext",
|
||||
"build:parallel": "node scripts/run-many.js --parallel build:web build:ext",
|
||||
"build:web": "pnpm -F @prompt-optimizer/web build",
|
||||
"build:ext": "pnpm -F @prompt-optimizer/extension build",
|
||||
"build:desktop-only": "pnpm -F @prompt-optimizer/desktop build",
|
||||
"build:desktop-only:ci": "pnpm -F @prompt-optimizer/desktop build:ci",
|
||||
"build:desktop": "npm-run-all build:core build:ui build:web build:desktop-only",
|
||||
"build:desktop:ci": "npm-run-all build:core build:ui build:web build:desktop-only:ci",
|
||||
"dev": "npm-run-all clean:dist build:core build:ui dev:parallel",
|
||||
"dev:fresh": "npm-run-all kill:dev clean pnpm-install dev",
|
||||
"build:desktop": "node scripts/run-many.js build:core build:ui build:web build:desktop-only",
|
||||
"build:desktop:ci": "node scripts/run-many.js build:core build:ui build:web build:desktop-only:ci",
|
||||
"dev": "node scripts/run-many.js clean:dist build:core build:ui dev:parallel",
|
||||
"dev:fresh": "node scripts/run-many.js kill:dev clean pnpm-install dev",
|
||||
"dev:parallel": "concurrently -k -p \"[{name}]\" -n \"UI,WEB\" \"pnpm -F @prompt-optimizer/ui build --watch\" \"pnpm -F @prompt-optimizer/web dev\"",
|
||||
"dev:ext": "pnpm -F @prompt-optimizer/extension dev",
|
||||
"dev:desktop": "npm-run-all clean:dist build:core build:ui dev:desktop:parallel",
|
||||
"dev:desktop:fresh": "npm-run-all kill:dev clean pnpm-install dev:desktop",
|
||||
"dev:desktop": "node scripts/run-many.js clean:dist build:core build:ui dev:desktop:parallel",
|
||||
"dev:desktop:fresh": "node scripts/run-many.js kill:dev clean pnpm-install dev:desktop",
|
||||
"dev:desktop:parallel": "concurrently -k -p \"[{name}]\" -n \"WEB,DESKTOP\" \"pnpm -F @prompt-optimizer/web dev\" \"pnpm -F @prompt-optimizer/desktop dev\"",
|
||||
"test": "npm-run-all -s test:unit test:e2e:smart",
|
||||
"test": "node scripts/run-many.js -s test:unit test:e2e:smart",
|
||||
"test:unit": "pnpm -r test --run --passWithNoTests",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:smart": "node scripts/smart-e2e.js",
|
||||
@@ -36,12 +36,12 @@
|
||||
"test:gate:core": "pnpm -F @prompt-optimizer/core test:gate",
|
||||
"test:gate:ui": "pnpm -F @prompt-optimizer/core build && pnpm -F @prompt-optimizer/ui test",
|
||||
"test:gate:e2e": "playwright test tests/e2e/regression.spec.ts tests/e2e/workflows/p0-route-smoke.spec.ts",
|
||||
"test:gate": "npm-run-all -s test:gate:core test:gate:ui",
|
||||
"test:gate:full": "npm-run-all -s test:gate test:gate:e2e",
|
||||
"test:gate": "node scripts/run-many.js -s test:gate:core test:gate:ui",
|
||||
"test:gate:full": "node scripts/run-many.js -s test:gate test:gate:e2e",
|
||||
"test:fast": "pnpm -r test --run --passWithNoTests",
|
||||
"test:e2e:ui": "playwright test --ui",
|
||||
"test:e2e:debug": "playwright test --debug",
|
||||
"clean": "npm-run-all clean:dist clean:vite",
|
||||
"clean": "node scripts/run-many.js clean:dist clean:vite",
|
||||
"clean:dist": "rimraf packages/core/dist packages/ui/dist packages/web/dist packages/extension/dist packages/desktop/dist packages/desktop/web-dist",
|
||||
"clean:vite": "rimraf packages/core/node_modules/.vite packages/ui/node_modules/.vite packages/web/node_modules/.vite packages/extension/node_modules/.vite",
|
||||
"pnpm-install": "pnpm install",
|
||||
@@ -62,9 +62,7 @@
|
||||
"@playwright/test": "^1.58.2",
|
||||
"concurrently": "^9.2.1",
|
||||
"cross-env": "^10.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rimraf": "^6.1.3",
|
||||
"typescript": "^6.0.2"
|
||||
"rimraf": "^6.1.3"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"dotenv": "^17.3.1",
|
||||
"msw": "^2.12.14",
|
||||
"tsup": "^8.5.1",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"ignoreDeprecations": "6.0",
|
||||
"ignoreDeprecations": "5.0",
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
|
||||
@@ -33,14 +33,16 @@
|
||||
"express": "^5.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/debug": "^4.1.13",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^22.19.15",
|
||||
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
||||
"@typescript-eslint/parser": "^8.57.2",
|
||||
"eslint": "^10.1.0",
|
||||
"globals": "^17.4.0",
|
||||
"tsup": "^8.5.1",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.1.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -108,7 +108,7 @@ export class CoreServicesManager {
|
||||
// 检查是否有任何可用的模型配置
|
||||
this.showEnvironmentHint();
|
||||
|
||||
throw new Error(`Core services initialization failed: ${(error as Error).message}`);
|
||||
throw new Error(`Core services initialization failed: ${(error as Error).message}`, { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ export class CoreServicesManager {
|
||||
logger.info(`Default model configured with preferred provider: ${config.preferredModelProvider || 'auto-selected'}`);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to setup default model: ${(error as Error).message}`);
|
||||
throw new Error(`Failed to setup default model: ${(error as Error).message}`, { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 完全复用 core 包的模型管理功能
|
||||
*/
|
||||
|
||||
import { ModelManager } from '@prompt-optimizer/core';
|
||||
import { ModelManager, type TextModelConfig } from '@prompt-optimizer/core';
|
||||
|
||||
/**
|
||||
* 为 MCP 服务器设置默认模型
|
||||
@@ -23,7 +23,7 @@ export async function setupDefaultModel(
|
||||
throw new Error('No enabled models found in core defaultModels');
|
||||
}
|
||||
|
||||
let selectedModel: [string, any] | undefined;
|
||||
let selectedModel: [string, TextModelConfig] | undefined;
|
||||
|
||||
// 1. 如果指定了 preferredProvider,尝试匹配
|
||||
if (preferredProvider) {
|
||||
@@ -64,4 +64,3 @@ export async function setupDefaultModel(
|
||||
await modelManager.addModel(mcpModelKey, finalConfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
||||
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
||||
import { ListToolsRequestSchema, CallToolRequestSchema, isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
||||
import { CoreServicesManager } from './adapters/core-services.js';
|
||||
import { loadConfig } from './config/environment.js';
|
||||
import { loadConfig, type MCPServerConfig } from './config/environment.js';
|
||||
import * as logger from './utils/logging.js';
|
||||
import { ParameterValidator } from './adapters/parameter-adapter.js';
|
||||
import { getTemplateOptions, getDefaultTemplateId } from './config/templates.js';
|
||||
@@ -43,7 +43,7 @@ import { randomUUID } from 'node:crypto';
|
||||
import express from 'express';
|
||||
|
||||
// 创建服务器实例的工厂函数
|
||||
async function createServerInstance(config: any) {
|
||||
async function createServerInstance(config: MCPServerConfig) {
|
||||
// 创建 MCP Server 实例 - 使用正确的 API
|
||||
const server = new Server({
|
||||
name: 'prompt-optimizer-mcp-server',
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"ignoreDeprecations": "6.0",
|
||||
"ignoreDeprecations": "5.0",
|
||||
"noEmit": false,
|
||||
"lib": [
|
||||
"ES2022",
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"vue-router": "^5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
@@ -63,12 +64,14 @@
|
||||
"@vue/tsconfig": "^0.9.1",
|
||||
"eslint": "^10.1.0",
|
||||
"eslint-plugin-vue": "^10.8.0",
|
||||
"globals": "^17.4.0",
|
||||
"jsdom": "^29.0.1",
|
||||
"postcss": "^8.5.8",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^8.0.3",
|
||||
"vitest": "^4.1.2",
|
||||
"vue-eslint-parser": "^10.4.0",
|
||||
"vue-tsc": "^3.2.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,22 +540,16 @@ const handleExtractionConfirm = (data: {
|
||||
|
||||
const placeholder = `{{${data.variableName}}}`;
|
||||
const text = editorView.state.doc.toString();
|
||||
let newValue = text;
|
||||
|
||||
if (data.replaceAll && occurrenceCount.value > 1) {
|
||||
// 全部替换
|
||||
newValue = replaceAllOccurrencesOutsideVariables(
|
||||
text,
|
||||
currentSelection.value.rawText,
|
||||
placeholder,
|
||||
);
|
||||
} else {
|
||||
// 仅替换当前选中的文本
|
||||
newValue =
|
||||
text.substring(0, currentSelection.value.start) +
|
||||
placeholder +
|
||||
text.substring(currentSelection.value.end);
|
||||
}
|
||||
const newValue =
|
||||
data.replaceAll && occurrenceCount.value > 1
|
||||
? replaceAllOccurrencesOutsideVariables(
|
||||
text,
|
||||
currentSelection.value.rawText,
|
||||
placeholder,
|
||||
)
|
||||
: text.substring(0, currentSelection.value.start) +
|
||||
placeholder +
|
||||
text.substring(currentSelection.value.end);
|
||||
|
||||
// 更新编辑器内容
|
||||
editorView.dispatch({
|
||||
|
||||
@@ -58,7 +58,7 @@ export function useVariableDetection(
|
||||
|
||||
// 分类变量并获取值
|
||||
let source: DetectedVariable["source"];
|
||||
let value = "";
|
||||
let value: string;
|
||||
|
||||
// 优先级: 预定义 > 全局 > 临时 > 缺失
|
||||
if (predefinedVariables.value[name] !== undefined) {
|
||||
|
||||
@@ -431,7 +431,10 @@ export function useImageModelManager() {
|
||||
const adapter = registry.getAdapter(selectedProviderId.value)
|
||||
selectedModel = adapter.buildDefaultModel(configForm.value.modelId)
|
||||
} catch (error) {
|
||||
throw new Error(`无法构建模型 ${configForm.value.modelId}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
throw new Error(
|
||||
`无法构建模型 ${configForm.value.modelId}: ${error instanceof Error ? error.message : String(error)}`,
|
||||
{ cause: error }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,7 +618,10 @@ export function useImageModelManager() {
|
||||
const adapter = registry.getAdapter(selectedProviderId.value)
|
||||
cachedModel = adapter.buildDefaultModel(selectedModelId.value)
|
||||
} catch (error) {
|
||||
throw new Error(`无法构建模型 ${selectedModelId.value}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
throw new Error(
|
||||
`无法构建模型 ${selectedModelId.value}: ${error instanceof Error ? error.message : String(error)}`,
|
||||
{ cause: error }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -562,7 +562,7 @@ export function useTextModelManager() {
|
||||
// but surface the failure to avoid a misleading "success" toast.
|
||||
const errorMessage = getI18nErrorMessage(error, t('modelManager.loadFailed'))
|
||||
|
||||
let staticCount = 0
|
||||
let staticCount: number
|
||||
try {
|
||||
const staticModels = textAdapterRegistry.getStaticModels(providerTemplateId)
|
||||
staticCount = staticModels.length
|
||||
|
||||
@@ -44,7 +44,7 @@ export function useClipboard(): ClipboardHooks {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Failed to copy to clipboard'
|
||||
error.value = errorMessage
|
||||
console.error('[useClipboard] Failed to copy text:', err)
|
||||
throw new Error(errorMessage)
|
||||
throw new Error(errorMessage, { cause: err })
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
@@ -68,7 +68,7 @@ export function useClipboard(): ClipboardHooks {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Failed to read from clipboard'
|
||||
error.value = errorMessage
|
||||
console.error('[useClipboard] Failed to read text:', err)
|
||||
throw new Error(errorMessage)
|
||||
throw new Error(errorMessage, { cause: err })
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
@@ -81,4 +81,4 @@ export function useClipboard(): ClipboardHooks {
|
||||
isLoading,
|
||||
error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,10 @@ export class DataImportExportManager implements DataImportExport {
|
||||
URL.revokeObjectURL(url)
|
||||
} catch (error) {
|
||||
console.error('Export to file failed:', error)
|
||||
throw new Error(`Export failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
||||
throw new Error(
|
||||
`Export failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
{ cause: error }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ function parseJsonObject(rawText: string): Record<string, unknown> {
|
||||
if (error instanceof Error && error.message === 'Model response is not a valid JSON object') {
|
||||
throw error
|
||||
}
|
||||
throw new Error('Model response is not valid JSON')
|
||||
throw new Error('Model response is not valid JSON', { cause: error })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1319
pnpm-lock.yaml
generated
1319
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
99
scripts/run-many.js
Normal file
99
scripts/run-many.js
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const { spawn } = require('node:child_process');
|
||||
|
||||
function getRunnerSpec(platform = process.platform) {
|
||||
if (platform === 'win32') {
|
||||
return {
|
||||
command: 'pnpm',
|
||||
shell: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
command: 'pnpm',
|
||||
shell: false,
|
||||
};
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
let parallel = false;
|
||||
const scripts = [];
|
||||
|
||||
for (const arg of argv) {
|
||||
if (arg === '--parallel' || arg === '-p') {
|
||||
parallel = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === '--silent' || arg === '-s') {
|
||||
continue;
|
||||
}
|
||||
scripts.push(arg);
|
||||
}
|
||||
|
||||
if (scripts.length === 0) {
|
||||
throw new Error('No scripts provided');
|
||||
}
|
||||
|
||||
return { parallel, scripts };
|
||||
}
|
||||
|
||||
function runPackageScript(script, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { command, shell } = getRunnerSpec();
|
||||
const child = spawn(command, ['run', script], {
|
||||
stdio: 'inherit',
|
||||
shell,
|
||||
env: process.env,
|
||||
...options,
|
||||
});
|
||||
|
||||
child.on('error', reject);
|
||||
child.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
if (signal) {
|
||||
reject(new Error(`Script "${script}" terminated by signal ${signal}`));
|
||||
return;
|
||||
}
|
||||
reject(new Error(`Script "${script}" exited with code ${code}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function runSequential(scripts, runner = runPackageScript) {
|
||||
for (const script of scripts) {
|
||||
await runner(script);
|
||||
}
|
||||
}
|
||||
|
||||
async function runParallel(scripts, runner = runPackageScript) {
|
||||
await Promise.all(scripts.map((script) => runner(script)));
|
||||
}
|
||||
|
||||
async function main(argv = process.argv.slice(2)) {
|
||||
const { parallel, scripts } = parseArgs(argv);
|
||||
if (parallel) {
|
||||
await runParallel(scripts);
|
||||
return;
|
||||
}
|
||||
await runSequential(scripts);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error.message || error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getRunnerSpec,
|
||||
main,
|
||||
parseArgs,
|
||||
runPackageScript,
|
||||
runParallel,
|
||||
runSequential,
|
||||
};
|
||||
60
scripts/run-many.test.mjs
Normal file
60
scripts/run-many.test.mjs
Normal file
@@ -0,0 +1,60 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { getRunnerSpec, parseArgs, runSequential, runParallel } from './run-many.js';
|
||||
|
||||
test('parseArgs supports sequential mode by default', () => {
|
||||
assert.deepEqual(parseArgs(['build:core', 'build:ui']), {
|
||||
parallel: false,
|
||||
scripts: ['build:core', 'build:ui'],
|
||||
});
|
||||
});
|
||||
|
||||
test('parseArgs supports parallel aliases', () => {
|
||||
assert.deepEqual(parseArgs(['--parallel', 'build:web', 'build:ext']), {
|
||||
parallel: true,
|
||||
scripts: ['build:web', 'build:ext'],
|
||||
});
|
||||
assert.deepEqual(parseArgs(['-p', 'build:web', 'build:ext']), {
|
||||
parallel: true,
|
||||
scripts: ['build:web', 'build:ext'],
|
||||
});
|
||||
});
|
||||
|
||||
test('getRunnerSpec uses shell mode for Windows pnpm invocation', () => {
|
||||
assert.deepEqual(getRunnerSpec('win32'), {
|
||||
command: 'pnpm',
|
||||
shell: true,
|
||||
});
|
||||
assert.deepEqual(getRunnerSpec('linux'), {
|
||||
command: 'pnpm',
|
||||
shell: false,
|
||||
});
|
||||
});
|
||||
|
||||
test('runSequential executes scripts in order and stops on failure', async () => {
|
||||
const executed = [];
|
||||
const runner = async (script) => {
|
||||
executed.push(script);
|
||||
if (script === 'build:ui') {
|
||||
throw new Error('boom');
|
||||
}
|
||||
};
|
||||
|
||||
await assert.rejects(
|
||||
runSequential(['build:core', 'build:ui', 'build:web'], runner),
|
||||
/boom/
|
||||
);
|
||||
assert.deepEqual(executed, ['build:core', 'build:ui']);
|
||||
});
|
||||
|
||||
test('runParallel waits for all scripts to finish when all succeed', async () => {
|
||||
const executed = [];
|
||||
const runner = async (script) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, script === 'build:web' ? 10 : 1));
|
||||
executed.push(script);
|
||||
};
|
||||
|
||||
await runParallel(['build:web', 'build:ext'], runner);
|
||||
assert.deepEqual(new Set(executed), new Set(['build:web', 'build:ext']));
|
||||
});
|
||||
Reference in New Issue
Block a user