Compare commits

...

2 Commits

Author SHA1 Message Date
MyPrototypeWhat
bd6d6bd56e refactor: update ClaudeCodeService initialization to remove config parameter
- Modified the initialization of the Claude code provider in ClaudeCodeService to no longer accept a configuration parameter, simplifying the setup process.
- This change enhances clarity and reduces potential configuration errors during provider instantiation.
2025-09-04 17:37:10 +08:00
MyPrototypeWhat
7a23386de4 feat: enhance AI core with Claude code integration and new provider support
- Added ClaudeCodeService for managing Claude code interactions via HTTP.
- Updated IPC channels to include new provider functionalities, enabling communication with the Claude code service.
- Enhanced electron configuration to support new AI core paths and dependencies.
- Updated package.json to include new dependencies for AI SDK and express.
- Refactored tsconfig to include paths for the new AI core modules, improving module resolution.

This update improves the integration of AI capabilities and enhances the overall functionality of the application.
2025-09-04 17:21:50 +08:00
13 changed files with 511 additions and 17 deletions

View File

@@ -23,7 +23,10 @@ export default defineConfig({
'@shared': resolve('packages/shared'),
'@logger': resolve('src/main/services/LoggerService'),
'@mcp-trace/trace-core': resolve('packages/mcp-trace/trace-core'),
'@mcp-trace/trace-node': resolve('packages/mcp-trace/trace-node')
'@mcp-trace/trace-node': resolve('packages/mcp-trace/trace-node'),
'@cherrystudio/ai-core/provider': resolve('packages/aiCore/src/core/providers'),
'@cherrystudio/ai-core/built-in/plugins': resolve('packages/aiCore/src/core/plugins/built-in'),
'@cherrystudio/ai-core': resolve('packages/aiCore/src')
}
},
build: {

View File

@@ -74,6 +74,8 @@
"@libsql/win32-x64-msvc": "^0.4.7",
"@napi-rs/system-ocr": "patch:@napi-rs/system-ocr@npm%3A1.0.2#~/.yarn/patches/@napi-rs-system-ocr-npm-1.0.2-59e7a78e8b.patch",
"@strongtz/win32-arm64-msvc": "^0.4.7",
"ai-sdk-provider-claude-code": "^1.1.3",
"express": "^5.1.0",
"graceful-fs": "^4.2.11",
"jsdom": "26.1.0",
"node-stream-zip": "^1.15.0",
@@ -169,6 +171,7 @@
"@truto/turndown-plugin-gfm": "^1.0.2",
"@tryfabric/martian": "^1.2.4",
"@types/cli-progress": "^3",
"@types/express": "^5.0.3",
"@types/fs-extra": "^11",
"@types/he": "^1",
"@types/lodash": "^4.17.5",
@@ -335,7 +338,13 @@
"pkce-challenge@npm:^4.1.0": "patch:pkce-challenge@npm%3A4.1.0#~/.yarn/patches/pkce-challenge-npm-4.1.0-fbc51695a3.patch",
"undici": "6.21.2",
"vite": "npm:rolldown-vite@latest",
"tesseract.js@npm:*": "patch:tesseract.js@npm%3A6.0.1#~/.yarn/patches/tesseract.js-npm-6.0.1-2562a7e46d.patch"
"tesseract.js@npm:*": "patch:tesseract.js@npm%3A6.0.1#~/.yarn/patches/tesseract.js-npm-6.0.1-2562a7e46d.patch",
"@img/sharp-darwin-arm64": "0.34.3",
"@img/sharp-darwin-x64": "0.34.3",
"@img/sharp-linux-arm": "0.34.3",
"@img/sharp-linux-arm64": "0.34.3",
"@img/sharp-linux-x64": "0.34.3",
"@img/sharp-win32-x64": "0.34.3"
},
"packageManager": "yarn@4.9.1",
"lint-staged": {

View File

@@ -250,6 +250,7 @@ export enum IpcChannel {
// Provider
Provider_AddKey = 'provider:add-key',
Provider_GetClaudeCodePort = 'provider:get-claude-code-port',
//Selection Assistant
Selection_TextSelected = 'selection:text-selected',

View File

@@ -13,6 +13,7 @@ import installExtension, { REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } from 'electro
import { isDev, isLinux, isWin } from './constant'
import { registerIpc } from './ipc'
import { claudeCodeService } from './services/ClaudeCodeService'
import { configManager } from './services/ConfigManager'
import mcpService from './services/MCPService'
import { nodeTraceService } from './services/NodeTraceService'
@@ -119,6 +120,14 @@ if (!app.requestSingleInstanceLock()) {
nodeTraceService.init()
// Start Claude-code HTTP service
try {
await claudeCodeService.start()
logger.info('Claude-code HTTP service started successfully')
} catch (error) {
logger.error('Failed to start Claude-code HTTP service:', error as Error)
}
app.on('activate', function () {
const mainWindow = windowService.getMainWindow()
if (!mainWindow || mainWindow.isDestroyed()) {
@@ -193,6 +202,15 @@ if (!app.requestSingleInstanceLock()) {
} catch (error) {
logger.warn('Error cleaning up MCP service:', error as Error)
}
// Stop Claude-code HTTP service
try {
await claudeCodeService.stop()
logger.info('Claude-code HTTP service stopped')
} catch (error) {
logger.warn('Error stopping Claude-code HTTP service:', error as Error)
}
// finish the logger
logger.finish()
})

View File

@@ -11,6 +11,7 @@ import { SpanEntity, TokenUsage } from '@mcp-trace/trace-core'
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, UpgradeChannel } from '@shared/config/constant'
import { IpcChannel } from '@shared/IpcChannel'
import { FileMetadata, Provider, Shortcut, ThemeMode } from '@types'
import { claudeCodeService } from './services/ClaudeCodeService'
import { BrowserWindow, dialog, ipcMain, ProxyConfig, session, shell, systemPreferences, webContents } from 'electron'
import { Notification } from 'src/renderer/src/types/notification'
@@ -755,4 +756,9 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
// CherryIN
ipcMain.handle(IpcChannel.Cherryin_GetSignature, (_, params) => generateSignature(params))
// Provider
ipcMain.handle(IpcChannel.Provider_GetClaudeCodePort, () => {
return claudeCodeService.getPort()
})
}

View File

@@ -0,0 +1,158 @@
import { createExecutor } from '@cherrystudio/ai-core'
import { loggerService } from '@logger'
import { createClaudeCode } from 'ai-sdk-provider-claude-code'
import express, { Request, Response } from 'express'
import { Server } from 'http'
const logger = loggerService.withContext('ClaudeCodeService')
export class ClaudeCodeService {
private app: express.Application
private server: Server | null = null
private port: number = 0
private claudeCodeProvider: any = null
constructor() {
this.app = express()
this.setupMiddleware()
this.setupRoutes()
}
private setupMiddleware() {
this.app.use(express.json())
this.app.use(express.text())
}
private setupRoutes() {
// Health check endpoint
this.app.get('/health', (_req: Request, res: Response) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() })
})
// Initialize claude-code provider
this.app.post('/init', async (req: Request, res: Response) => {
try {
const config = req.body
logger.info('Initializing claude-code provider with config', config)
this.claudeCodeProvider = createClaudeCode()
res.json({
success: true,
message: 'Claude-code provider initialized successfully'
})
} catch (error) {
logger.error('Failed to initialize claude-code provider', error as Error)
res.status(500).json({
success: false,
error: (error as Error).message
})
}
})
// Stream text completion endpoint
this.app.post('/completions', async (req: Request, res: Response): Promise<void> => {
try {
if (!this.claudeCodeProvider) {
res.status(400).json({
success: false,
error: 'Claude-code provider not initialized. Call /init first.'
})
return
}
const { modelId, params, options } = req.body
logger.info('Processing completions request', { modelId, hasParams: !!params })
// 创建执行器
const executor = createExecutor('claude-code', options || {}, [])
const model = this.claudeCodeProvider.languageModel('opus')
// 执行流式文本生成
const result = await executor.streamText({
...params,
model,
abortSignal: new AbortController().signal
})
console.log('result', result)
// 使用 AI SDK 提供的便捷函数处理流式响应
result.pipeUIMessageStreamToResponse(res)
logger.info('Completions request completed successfully')
} catch (error) {
logger.error('Error in completions endpoint', error as Error)
if (!res.headersSent) {
res.status(500).json({
success: false,
error: (error as Error).message
})
}
}
})
}
public async start(): Promise<number> {
return new Promise((resolve, reject) => {
// 尝试使用固定端口,如果失败则使用系统分配端口
const preferredPort = 23456
this.server = this.app.listen(preferredPort, 'localhost', () => {
if (this.server?.address()) {
this.port = (this.server.address() as any)?.port || 0
logger.info(`Claude-code HTTP service started on port ${this.port}`)
resolve(this.port)
} else {
reject(new Error('Failed to start server'))
}
})
this.server.on('error', (error: any) => {
if (error.code === 'EADDRINUSE') {
logger.warn(`Port ${preferredPort} is in use, trying with dynamic port`)
// 如果固定端口被占用,使用动态端口
this.server = this.app.listen(0, 'localhost', () => {
if (this.server?.address()) {
this.port = (this.server.address() as any)?.port || 0
logger.info(`Claude-code HTTP service started on dynamic port ${this.port}`)
resolve(this.port)
} else {
reject(new Error('Failed to start server'))
}
})
this.server.on('error', (dynamicError) => {
logger.error('Server error on dynamic port', dynamicError)
reject(dynamicError)
})
} else {
logger.error('Server error', error)
reject(error)
}
})
})
}
public async stop(): Promise<void> {
return new Promise((resolve) => {
if (this.server) {
this.server.close(() => {
logger.info('Claude-code HTTP service stopped')
resolve()
})
} else {
resolve()
}
})
}
public getPort(): number {
return this.port
}
public isRunning(): boolean {
return this.server !== null && this.server.listening
}
}
// 单例实例
export const claudeCodeService = new ClaudeCodeService()

View File

@@ -437,6 +437,9 @@ const api = {
cherryin: {
generateSignature: (params: { method: string; path: string; query: string; body: Record<string, any> }) =>
ipcRenderer.invoke(IpcChannel.Cherryin_GetSignature, params)
},
provider: {
getClaudeCodePort: () => ipcRenderer.invoke(IpcChannel.Provider_GetClaudeCodePort)
}
}

View File

@@ -53,6 +53,54 @@ export class AiSdkToChunkAdapter {
return await aiSdkResult.text
}
/**
* 直接处理单个 chunk 数据
* @param chunk AI SDK 的 chunk 数据
*/
async processChunk(response: ReadableStream<TextStreamPart<any>>): Promise<void> {
const reader = response.getReader()
const final = {
text: '',
reasoningContent: '',
webSearchResults: [],
reasoningId: ''
}
try {
let buffer = ''
const decoder = new TextDecoder()
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value, { stream: true })
buffer += chunk
// 按行处理 SSE 数据
const lines = buffer.split('\n')
buffer = lines.pop() || '' // 保留最后一行(可能不完整)
for (const line of lines) {
if (line.startsWith('data: ')) {
const dataStr = line.slice(6) // 移除 "data: " 前缀
if (dataStr === '[DONE]') {
break
}
try {
const data = JSON.parse(dataStr)
this.convertAndEmitChunk(data, final)
} catch (parseError) {
// 忽略无法解析的数据
// logger.debug('Failed to parse streamed data:', parseError as Error, line)
}
}
}
}
} finally {
reader.releaseLock()
}
}
/**
* 读取 fullStream 并转换为 Cherry Studio chunks
* @param fullStream AI SDK 的 fullStream (ReadableStream)
@@ -90,6 +138,7 @@ export class AiSdkToChunkAdapter {
final: { text: string; reasoningContent: string; webSearchResults: any[]; reasoningId: string }
) {
logger.info(`AI SDK chunk type: ${chunk.type}`, chunk)
console.log('final', final)
switch (chunk.type) {
// === 文本相关事件 ===
case 'text-start':
@@ -99,7 +148,7 @@ export class AiSdkToChunkAdapter {
break
case 'text-delta':
if (this.accumulate) {
final.text += chunk.text || ''
final.text += chunk.delta || ''
} else {
final.text = chunk.text || ''
}
@@ -232,13 +281,13 @@ export class AiSdkToChunkAdapter {
text: final.text || '',
reasoning_content: final.reasoningContent || '',
usage: {
completion_tokens: chunk.totalUsage.outputTokens || 0,
prompt_tokens: chunk.totalUsage.inputTokens || 0,
total_tokens: chunk.totalUsage.totalTokens || 0
completion_tokens: chunk?.totalUsage?.outputTokens || 0,
prompt_tokens: chunk?.totalUsage?.inputTokens || 0,
total_tokens: chunk?.totalUsage?.totalTokens || 0
},
metrics: chunk.totalUsage
metrics: chunk?.totalUsage
? {
completion_tokens: chunk.totalUsage.outputTokens || 0,
completion_tokens: chunk?.totalUsage?.outputTokens || 0,
time_completion_millsec: 0
}
: undefined
@@ -250,13 +299,13 @@ export class AiSdkToChunkAdapter {
text: final.text || '',
reasoning_content: final.reasoningContent || '',
usage: {
completion_tokens: chunk.totalUsage.outputTokens || 0,
prompt_tokens: chunk.totalUsage.inputTokens || 0,
total_tokens: chunk.totalUsage.totalTokens || 0
completion_tokens: chunk?.totalUsage?.outputTokens || 0,
prompt_tokens: chunk?.totalUsage?.inputTokens || 0,
total_tokens: chunk?.totalUsage?.totalTokens || 0
},
metrics: chunk.totalUsage
metrics: chunk?.totalUsage
? {
completion_tokens: chunk.totalUsage.outputTokens || 0,
completion_tokens: chunk?.totalUsage?.outputTokens || 0,
time_completion_millsec: 0
}
: undefined

View File

@@ -90,6 +90,11 @@ export default class ModernAiProvider {
// 准备特殊配置
await prepareSpecialProviderConfig(this.actualProvider, this.config)
// 特殊处理 claude-code provider通过本地 HTTP 服务器
// if (this.config.providerId === 'claude-code') {
return await this._completionsViaHttpService(modelId, params, config)
// }
// 提前创建本地 provider 实例
if (!this.localProvider) {
this.localProvider = await createAiSdkProvider(this.config)
@@ -246,6 +251,79 @@ export default class ModernAiProvider {
}
}
/**
* 通过本地 HTTP 服务器处理 claude-code completions
*/
private async _completionsViaHttpService(
modelId: string,
params: StreamTextParams,
config: ModernAiProviderConfig
): Promise<CompletionsResult> {
logger.info('Starting claude-code completions via HTTP service', {
modelId,
providerId: this.config!.providerId,
topicId: config.topicId,
hasOnChunk: !!config.onChunk
})
try {
// 初始化 claude-code provider
const initResponse = await fetch('http://localhost:' + (await this.getClaudeCodePort()) + '/init', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.config!.options)
})
if (!initResponse.ok) {
throw new Error(`Failed to initialize claude-code provider: ${initResponse.statusText}`)
}
// 发送 completions 请求
const completionsResponse = await fetch('http://localhost:' + (await this.getClaudeCodePort()) + '/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
modelId,
params,
options: this.config!.options
})
})
if (!completionsResponse.ok) {
throw new Error(`Failed to get completions: ${completionsResponse.statusText}`)
}
let finalText = ''
if (config.onChunk && completionsResponse.body) {
// 创建 adapter 来处理 chunk 数据
const accumulate = this.model!.supported_text_delta !== false
const adapter = new AiSdkToChunkAdapter(config.onChunk, config.mcpTools, accumulate)
await adapter.processChunk(completionsResponse.body)
} else {
finalText = await completionsResponse.text()
}
return {
getText: () => finalText
}
} catch (error) {
logger.error('Error in claude-code HTTP service completions', error as Error)
throw error
}
}
/**
* 获取 Claude-code HTTP 服务端口
*/
private async getClaudeCodePort(): Promise<number> {
return await window.api.provider.getClaudeCodePort()
}
/**
* 使用现代化AI SDK的completions实现
*/

View File

@@ -76,6 +76,17 @@ export function getAiSdkProviderId(provider: Provider): ProviderId | 'openai-com
export async function createAiSdkProvider(config) {
let localProvider: Awaited<AiSdkProvider> | null = null
try {
// 特殊处理 claude-code provider通过 IPC 在主线程中创建
// if (config.providerId === 'claude-code') {
localProvider = await window.api.provider.createClaudeCode()
logger.debug('Claude-code provider created via IPC', {
providerId: config.providerId,
hasOptions: !!config.options
})
console.log('localProvider', localProvider)
return localProvider
// }
if (config.providerId === 'openai' && config.options?.mode === 'chat') {
config.providerId = `${config.providerId}-chat`
} else if (config.providerId === 'azure' && config.options?.mode === 'responses') {

View File

@@ -92,7 +92,6 @@ function formatProviderApiHost(provider: Provider): Provider {
*/
export function getActualProvider(model: Model): Provider {
const baseProvider = getProviderByModel(model)
// 按顺序处理各种转换
let actualProvider = cloneDeep(baseProvider)
actualProvider = handleSpecialProviders(model, actualProvider)

View File

@@ -7,6 +7,7 @@
"src/main/env.d.ts",
"src/renderer/src/types/*",
"packages/shared/**/*",
"packages/aiCore/**/*",
"scripts",
"packages/mcp-trace/**/*",
"src/renderer/src/services/traceApi.ts" ],
@@ -19,12 +20,17 @@
"vitest/globals"
],
"baseUrl": ".",
"moduleResolution": "bundler",
"paths": {
"@logger": ["src/main/services/LoggerService"],
"@main/*": ["src/main/*"],
"@types": ["src/renderer/src/types/index.ts"],
"@shared/*": ["packages/shared/*"],
"@mcp-trace/*": ["packages/mcp-trace/*"]
"@mcp-trace/*": ["packages/mcp-trace/*"],
"@cherrystudio/ai-core/provider": ["packages/aiCore/src/core/providers/index.ts"],
"@cherrystudio/ai-core/built-in/plugins": ["packages/aiCore/src/core/plugins/built-in/index.ts"],
"@cherrystudio/ai-core/*": ["packages/aiCore/src/*"],
"@cherrystudio/ai-core": ["packages/aiCore/src/index.ts"],
},
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

157
yarn.lock
View File

@@ -451,6 +451,35 @@ __metadata:
languageName: node
linkType: hard
"@anthropic-ai/claude-code@npm:1.0.94":
version: 1.0.94
resolution: "@anthropic-ai/claude-code@npm:1.0.94"
dependencies:
"@img/sharp-darwin-arm64": "npm:^0.33.5"
"@img/sharp-darwin-x64": "npm:^0.33.5"
"@img/sharp-linux-arm": "npm:^0.33.5"
"@img/sharp-linux-arm64": "npm:^0.33.5"
"@img/sharp-linux-x64": "npm:^0.33.5"
"@img/sharp-win32-x64": "npm:^0.33.5"
dependenciesMeta:
"@img/sharp-darwin-arm64":
optional: true
"@img/sharp-darwin-x64":
optional: true
"@img/sharp-linux-arm":
optional: true
"@img/sharp-linux-arm64":
optional: true
"@img/sharp-linux-x64":
optional: true
"@img/sharp-win32-x64":
optional: true
bin:
claude: cli.js
checksum: 10c0/d97966f07f43f8c247a10d0a55766c018a10bd3bddb0fc5c68f75b5c9a54324175e8f1f5c4a3a3469ff9673e2150defdbb9f9b8da6b52dbbe62f8f9fec4d5afb
languageName: node
linkType: hard
"@anthropic-ai/sdk@npm:>=0.50.3 <1":
version: 0.56.0
resolution: "@anthropic-ai/sdk@npm:0.56.0"
@@ -3252,7 +3281,7 @@ __metadata:
languageName: node
linkType: hard
"@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.4.4, @emnapi/runtime@npm:^1.4.5":
"@emnapi/runtime@npm:^1.4.3, @emnapi/runtime@npm:^1.4.5":
version: 1.4.5
resolution: "@emnapi/runtime@npm:1.4.5"
dependencies:
@@ -3261,6 +3290,15 @@ __metadata:
languageName: node
linkType: hard
"@emnapi/runtime@npm:^1.4.4":
version: 1.5.0
resolution: "@emnapi/runtime@npm:1.5.0"
dependencies:
tslib: "npm:^2.4.0"
checksum: 10c0/a85c9fc4e3af49cbe41e5437e5be2551392a931910cd0a5b5d3572532786927810c9cc1db11b232ec8f9657b33d4e6f7c4f985f1a052917d7cd703b5b2a20faa
languageName: node
linkType: hard
"@emnapi/wasi-threads@npm:1.0.4":
version: 1.0.4
resolution: "@emnapi/wasi-threads@npm:1.0.4"
@@ -8143,6 +8181,16 @@ __metadata:
languageName: node
linkType: hard
"@types/body-parser@npm:*":
version: 1.19.6
resolution: "@types/body-parser@npm:1.19.6"
dependencies:
"@types/connect": "npm:*"
"@types/node": "npm:*"
checksum: 10c0/542da05c924dce58ee23f50a8b981fee36921850c82222e384931fda3e106f750f7880c47be665217d72dbe445129049db6eb1f44e7a06b09d62af8f3cca8ea7
languageName: node
linkType: hard
"@types/cacheable-request@npm:^6.0.1":
version: 6.0.3
resolution: "@types/cacheable-request@npm:6.0.3"
@@ -8173,6 +8221,15 @@ __metadata:
languageName: node
linkType: hard
"@types/connect@npm:*":
version: 3.4.38
resolution: "@types/connect@npm:3.4.38"
dependencies:
"@types/node": "npm:*"
checksum: 10c0/2e1cdba2c410f25649e77856505cd60223250fa12dff7a503e492208dbfdd25f62859918f28aba95315251fd1f5e1ffbfca1e25e73037189ab85dd3f8d0a148c
languageName: node
linkType: hard
"@types/d3-array@npm:*":
version: 3.2.1
resolution: "@types/d3-array@npm:3.2.1"
@@ -8477,6 +8534,29 @@ __metadata:
languageName: node
linkType: hard
"@types/express-serve-static-core@npm:^5.0.0":
version: 5.0.7
resolution: "@types/express-serve-static-core@npm:5.0.7"
dependencies:
"@types/node": "npm:*"
"@types/qs": "npm:*"
"@types/range-parser": "npm:*"
"@types/send": "npm:*"
checksum: 10c0/28666f6a0743b8678be920a6eed075bc8afc96fc7d8ef59c3c049bd6b51533da3b24daf3b437d061e053fba1475e4f3175cb4972f5e8db41608e817997526430
languageName: node
linkType: hard
"@types/express@npm:^5.0.3":
version: 5.0.3
resolution: "@types/express@npm:5.0.3"
dependencies:
"@types/body-parser": "npm:*"
"@types/express-serve-static-core": "npm:^5.0.0"
"@types/serve-static": "npm:*"
checksum: 10c0/f0fbc8daa7f40070b103cf4d020ff1dd08503477d866d1134b87c0390bba71d5d7949cb8b4e719a81ccba89294d8e1573414e6dcbb5bb1d097a7b820928ebdef
languageName: node
linkType: hard
"@types/fs-extra@npm:9.0.13, @types/fs-extra@npm:^9.0.11":
version: 9.0.13
resolution: "@types/fs-extra@npm:9.0.13"
@@ -8526,6 +8606,13 @@ __metadata:
languageName: node
linkType: hard
"@types/http-errors@npm:*":
version: 2.0.5
resolution: "@types/http-errors@npm:2.0.5"
checksum: 10c0/00f8140fbc504f47356512bd88e1910c2f07e04233d99c88c854b3600ce0523c8cd0ba7d1897667243282eb44c59abb9245959e2428b9de004f93937f52f7c15
languageName: node
linkType: hard
"@types/json-schema@npm:^7.0.15":
version: 7.0.15
resolution: "@types/json-schema@npm:7.0.15"
@@ -8621,6 +8708,13 @@ __metadata:
languageName: node
linkType: hard
"@types/mime@npm:^1":
version: 1.3.5
resolution: "@types/mime@npm:1.3.5"
checksum: 10c0/c2ee31cd9b993804df33a694d5aa3fa536511a49f2e06eeab0b484fef59b4483777dbb9e42a4198a0809ffbf698081fdbca1e5c2218b82b91603dfab10a10fbc
languageName: node
linkType: hard
"@types/ms@npm:*":
version: 2.1.0
resolution: "@types/ms@npm:2.1.0"
@@ -8682,6 +8776,20 @@ __metadata:
languageName: node
linkType: hard
"@types/qs@npm:*":
version: 6.14.0
resolution: "@types/qs@npm:6.14.0"
checksum: 10c0/5b3036df6e507483869cdb3858201b2e0b64b4793dc4974f188caa5b5732f2333ab9db45c08157975054d3b070788b35088b4bc60257ae263885016ee2131310
languageName: node
linkType: hard
"@types/range-parser@npm:*":
version: 1.2.7
resolution: "@types/range-parser@npm:1.2.7"
checksum: 10c0/361bb3e964ec5133fa40644a0b942279ed5df1949f21321d77de79f48b728d39253e5ce0408c9c17e4e0fd95ca7899da36841686393b9f7a1e209916e9381a3c
languageName: node
linkType: hard
"@types/react-dom@npm:^19.0.4":
version: 19.1.2
resolution: "@types/react-dom@npm:19.1.2"
@@ -8734,6 +8842,27 @@ __metadata:
languageName: node
linkType: hard
"@types/send@npm:*":
version: 0.17.5
resolution: "@types/send@npm:0.17.5"
dependencies:
"@types/mime": "npm:^1"
"@types/node": "npm:*"
checksum: 10c0/a86c9b89bb0976ff58c1cdd56360ea98528f4dbb18a5c2287bb8af04815513a576a42b4e0e1e7c4d14f7d6ea54733f6ef935ebff8c65e86d9c222881a71e1f15
languageName: node
linkType: hard
"@types/serve-static@npm:*":
version: 1.15.8
resolution: "@types/serve-static@npm:1.15.8"
dependencies:
"@types/http-errors": "npm:*"
"@types/node": "npm:*"
"@types/send": "npm:*"
checksum: 10c0/8ad86a25b87da5276cb1008c43c74667ff7583904d46d5fcaf0355887869d859d453d7dc4f890788ae04705c23720e9b6b6f3215e2d1d2a4278bbd090a9268dd
languageName: node
linkType: hard
"@types/stylis@npm:4.2.5":
version: 4.2.5
resolution: "@types/stylis@npm:4.2.5"
@@ -9771,6 +9900,7 @@ __metadata:
"@truto/turndown-plugin-gfm": "npm:^1.0.2"
"@tryfabric/martian": "npm:^1.2.4"
"@types/cli-progress": "npm:^3"
"@types/express": "npm:^5.0.3"
"@types/fs-extra": "npm:^11"
"@types/he": "npm:^1"
"@types/lodash": "npm:^4.17.5"
@@ -9797,6 +9927,7 @@ __metadata:
"@viz-js/viz": "npm:^3.14.0"
"@xyflow/react": "npm:^12.4.4"
ai: "npm:^5.0.29"
ai-sdk-provider-claude-code: "npm:^1.1.3"
antd: "patch:antd@npm%3A5.27.0#~/.yarn/patches/antd-npm-5.27.0-aa91c36546.patch"
archiver: "npm:^7.0.1"
async-mutex: "npm:^0.5.0"
@@ -9830,6 +9961,7 @@ __metadata:
eslint-plugin-react-hooks: "npm:^5.2.0"
eslint-plugin-simple-import-sort: "npm:^12.1.1"
eslint-plugin-unused-imports: "npm:^4.1.4"
express: "npm:^5.1.0"
fast-diff: "npm:^1.3.0"
fast-xml-parser: "npm:^5.2.0"
fetch-socks: "npm:1.3.2"
@@ -10022,6 +10154,20 @@ __metadata:
languageName: node
linkType: hard
"ai-sdk-provider-claude-code@npm:^1.1.3":
version: 1.1.3
resolution: "ai-sdk-provider-claude-code@npm:1.1.3"
dependencies:
"@ai-sdk/provider": "npm:2.0.0"
"@ai-sdk/provider-utils": "npm:3.0.3"
"@anthropic-ai/claude-code": "npm:1.0.94"
jsonc-parser: "npm:^3.3.1"
peerDependencies:
zod: ^3.0.0 || ^4.0.0
checksum: 10c0/e503414d19f89ebc638dea791b49a1a4c322088c2f7446b0122b2c557e6e8001f00e9cdd7fbe126870082aaff2f9c25199e07a42d3f594fa7303dfd9547986ca
languageName: node
linkType: hard
"ai@npm:^5.0.29":
version: 5.0.29
resolution: "ai@npm:5.0.29"
@@ -13910,7 +14056,7 @@ __metadata:
languageName: node
linkType: hard
"express@npm:^5.0.1":
"express@npm:^5.0.1, express@npm:^5.1.0":
version: 5.1.0
resolution: "express@npm:5.1.0"
dependencies:
@@ -16170,6 +16316,13 @@ __metadata:
languageName: node
linkType: hard
"jsonc-parser@npm:^3.3.1":
version: 3.3.1
resolution: "jsonc-parser@npm:3.3.1"
checksum: 10c0/269c3ae0a0e4f907a914bf334306c384aabb9929bd8c99f909275ebd5c2d3bc70b9bcd119ad794f339dec9f24b6a4ee9cd5a8ab2e6435e730ad4075388fc2ab6
languageName: node
linkType: hard
"jsonfile@npm:^4.0.0":
version: 4.0.0
resolution: "jsonfile@npm:4.0.0"