From 07bc4f36df594a71f44a7ec71a457aca18262ad4 Mon Sep 17 00:00:00 2001 From: honlnk Date: Sun, 24 May 2026 21:31:49 +0800 Subject: [PATCH 01/16] =?UTF-8?q?feat(app):=20=E5=A2=9E=E5=8A=A0=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=AF=BB=E5=8F=96=E7=8A=B6=E6=80=81=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/core/agent/query.ts | 3 + .../core/src/core/agent/tool-execution.ts | 7 +- .../core/src/core/agent/tool-orchestration.ts | 3 + packages/core/src/core/tools/file-tools.ts | 74 ++++++++++++++++++- packages/core/src/core/tools/index.ts | 2 + packages/core/src/core/tools/types.ts | 10 +++ 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/packages/core/src/core/agent/query.ts b/packages/core/src/core/agent/query.ts index 194b140..a2fab50 100644 --- a/packages/core/src/core/agent/query.ts +++ b/packages/core/src/core/agent/query.ts @@ -7,6 +7,7 @@ import type { AgentMessage, } from './messages' import type { AgentRunnableToolMap } from './tools' +import type { ReadFileState } from '../tools/types' const DEFAULT_MAX_TURNS = 8 @@ -31,6 +32,7 @@ export async function query(input: { }): Promise { let messages = [...input.messages] const maxTurns = input.maxTurns ?? DEFAULT_MAX_TURNS + const readFileStates = new Map() for (let turn = 0; turn < maxTurns; turn += 1) { const step = turn + 1 @@ -84,6 +86,7 @@ export async function query(input: { calls: assistantResponse.toolCalls, project: input.project, tools: input.tools, + readFileStates, onEvent: input.onEvent, }) diff --git a/packages/core/src/core/agent/tool-execution.ts b/packages/core/src/core/agent/tool-execution.ts index 2ae0c28..b6a75a4 100644 --- a/packages/core/src/core/agent/tool-execution.ts +++ b/packages/core/src/core/agent/tool-execution.ts @@ -1,6 +1,7 @@ import type { ProjectSnapshot } from '../../types/project' import type { AgentToolCall, AgentToolResultMessage } from './messages' import type { AgentRunnableToolMap } from './tools' +import type { ReadFileState } from '../tools/types' export type ToolExecutionEvent = | { type: 'tool-call'; call: AgentToolCall; inputSummary: string } @@ -10,6 +11,7 @@ export async function executeAgentTool(input: { call: AgentToolCall project: ProjectSnapshot tools: AgentRunnableToolMap + readFileStates?: Map onEvent?: (event: ToolExecutionEvent) => void }): Promise { const tool = input.tools[input.call.name] @@ -69,7 +71,10 @@ export async function executeAgentTool(input: { }) try { - const output = await tool.core.run(validatedInput, { project: input.project }) + const output = await tool.core.run(validatedInput, { + project: input.project, + readFileStates: input.readFileStates, + }) const resultSummary = tool.core.summarizeOutput(output) input.onEvent?.({ diff --git a/packages/core/src/core/agent/tool-orchestration.ts b/packages/core/src/core/agent/tool-orchestration.ts index 2cd33a7..4db99f1 100644 --- a/packages/core/src/core/agent/tool-orchestration.ts +++ b/packages/core/src/core/agent/tool-orchestration.ts @@ -3,11 +3,13 @@ import type { ToolExecutionEvent } from './tool-execution' import type { ProjectSnapshot } from '../../types/project' import type { AgentToolCall, AgentToolResultMessage } from './messages' import type { AgentRunnableToolMap } from './tools' +import type { ReadFileState } from '../tools/types' export async function runAgentTools(input: { calls: AgentToolCall[] project: ProjectSnapshot tools: AgentRunnableToolMap + readFileStates?: Map onEvent?: (event: ToolExecutionEvent) => void }): Promise { const results: AgentToolResultMessage[] = [] @@ -17,6 +19,7 @@ export async function runAgentTools(input: { call, project: input.project, tools: input.tools, + readFileStates: input.readFileStates, onEvent: input.onEvent, })) } diff --git a/packages/core/src/core/tools/file-tools.ts b/packages/core/src/core/tools/file-tools.ts index 83a17e8..2237468 100644 --- a/packages/core/src/core/tools/file-tools.ts +++ b/packages/core/src/core/tools/file-tools.ts @@ -16,6 +16,7 @@ import type { EditFileOutput, ReadFileInput, ReadFileOutput, + ReadFileState, RenameFileInput, RenameFileOutput, ToolDefinition, @@ -57,6 +58,9 @@ export const readFileTool: ToolDefinition<'ReadFile', ReadFileInput, ReadFileOut } const content = await file.text() + const readFileState = createReadFileState(input.path, content, file) + runtime.readFileStates?.set(input.path, readFileState) + const lines = splitLines(content) const startLine = input.offset ?? 1 const limit = input.limit ?? DEFAULT_READ_LIMIT @@ -80,6 +84,7 @@ export const readFileTool: ToolDefinition<'ReadFile', ReadFileInput, ReadFileOut path: input.path, content: selectedLines.join('\n'), numberedContent, + readFileState, startLine, endLine, totalLines: empty ? 0 : lines.length, @@ -118,6 +123,9 @@ export const editFileTool: ToolDefinition<'EditFile', EditFileInput, EditFileOut const path = normalizeProjectPath(readString(value.path, 'EditFile.path')) const oldText = readString(value.oldText, 'EditFile.oldText') const newText = readString(value.newText, 'EditFile.newText') + const readFileState = value.readFileState === undefined + ? undefined + : readReadFileState(value.readFileState, 'EditFile.readFileState') assertTextFilePath(path) @@ -130,10 +138,20 @@ export const editFileTool: ToolDefinition<'EditFile', EditFileInput, EditFileOut oldText, newText, replaceAll: typeof value.replaceAll === 'boolean' ? value.replaceAll : false, + readFileState, } }, async run(input, runtime) { - const currentContent = await readProjectTextFile(runtime.project.handle, input.path) + const file = await getProjectTextFile(runtime.project.handle, input.path) + const currentContent = await file.text() + const currentState = createReadFileState(input.path, currentContent, file) + const expectedState = input.readFileState ?? runtime.readFileStates?.get(input.path) + + if (!expectedState) { + throw new Error(`修改 ${input.path} 前必须先用 ReadFile 读取目标文件;工具层没有找到可校验的读取状态`) + } + + assertFreshReadFileState(input.path, expectedState, currentState) if (!input.oldText) { throw new Error('EditFile.oldText 不能为空;新增文件请使用 CreateFile,修改已有文件请先 ReadFile 并提供要替换的原文片段') @@ -157,6 +175,7 @@ export const editFileTool: ToolDefinition<'EditFile', EditFileInput, EditFileOut : currentContent.replace(actualOldText, actualNewText) await writeProjectTextFile(runtime.project.handle, input.path, nextContent) + runtime.readFileStates?.delete(input.path) return { path: input.path, @@ -340,6 +359,59 @@ function readString(value: unknown, label: string) { return value } +function readReadFileState(value: unknown, label: string): ReadFileState { + const state = asRecord(value) + const path = normalizeProjectPath(readString(state.path, `${label}.path`)) + const contentHash = readString(state.contentHash, `${label}.contentHash`) + const lastModified = readString(state.lastModified, `${label}.lastModified`) + const fileSizeBytes = state.fileSizeBytes + + if (!Number.isInteger(fileSizeBytes) || Number(fileSizeBytes) < 0) { + throw new Error(`${label}.fileSizeBytes 必须是非负整数`) + } + + return { + path, + contentHash, + lastModified, + fileSizeBytes: Number(fileSizeBytes), + } +} + +function createReadFileState(path: string, content: string, file: File): ReadFileState { + return { + path, + contentHash: hashContent(content), + lastModified: new Date(file.lastModified).toISOString(), + fileSizeBytes: file.size, + } +} + +function assertFreshReadFileState( + path: string, + expectedState: ReadFileState, + currentState: ReadFileState, +) { + if (expectedState.path !== path) { + throw new Error(`EditFile.readFileState.path 与目标文件不一致:读取的是 ${expectedState.path},准备修改的是 ${path}`) + } + + if (expectedState.contentHash !== currentState.contentHash) { + throw new Error(`文件 ${path} 已在 ReadFile 之后发生变化;请重新 ReadFile 获取最新内容后再 EditFile,避免覆盖他人或其他工具的修改`) + } +} + +function hashContent(content: string) { + let hash = 2166136261 + + for (let index = 0; index < content.length; index += 1) { + hash ^= content.charCodeAt(index) + hash = Math.imul(hash, 16777619) + } + + return `h${(hash >>> 0).toString(16)}` +} + function readOptionalPositiveInteger(value: unknown, label: string) { if (value === undefined) { return undefined diff --git a/packages/core/src/core/tools/index.ts b/packages/core/src/core/tools/index.ts index d7ea660..5d34944 100644 --- a/packages/core/src/core/tools/index.ts +++ b/packages/core/src/core/tools/index.ts @@ -20,6 +20,7 @@ import type { ListDirectoryOutput, ReadFileInput, ReadFileOutput, + ReadFileState, RenameFileInput, RenameFileOutput, ToolCall, @@ -43,6 +44,7 @@ export type { ListDirectoryOutput, ReadFileInput, ReadFileOutput, + ReadFileState, RenameFileInput, RenameFileOutput, ToolCall, diff --git a/packages/core/src/core/tools/types.ts b/packages/core/src/core/tools/types.ts index 0717f38..5d70c0d 100644 --- a/packages/core/src/core/tools/types.ts +++ b/packages/core/src/core/tools/types.ts @@ -11,6 +11,7 @@ export type CoreToolName = export type ToolRuntime = { project: ProjectSnapshot + readFileStates?: Map } export type ToolCall = { @@ -54,6 +55,7 @@ export type ReadFileOutput = { path: string content: string numberedContent: string + readFileState: ReadFileState startLine: number endLine: number totalLines: number @@ -64,11 +66,19 @@ export type ReadFileOutput = { notice?: string } +export type ReadFileState = { + path: string + contentHash: string + lastModified: string + fileSizeBytes: number +} + export type EditFileInput = { path: string oldText: string newText: string replaceAll?: boolean + readFileState?: ReadFileState } export type EditFileOutput = { From 79a8c44dd6ab075daee1bc5c866d53cbd2a8191b Mon Sep 17 00:00:00 2001 From: honlnk Date: Sun, 24 May 2026 22:04:42 +0800 Subject: [PATCH 02/16] =?UTF-8?q?refactor(other):=20=E6=8B=86=E5=88=86?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=B7=A5=E5=85=B7=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/core/tools/file-tools.ts | 560 +----------------- .../core/src/core/tools/file-tools/common.ts | 39 ++ .../src/core/tools/file-tools/create-file.ts | 44 ++ .../src/core/tools/file-tools/delete-file.ts | 63 ++ .../src/core/tools/file-tools/edit-file.ts | 94 +++ .../core/src/core/tools/file-tools/index.ts | 5 + .../core/tools/file-tools/read-file-state.ts | 56 ++ .../src/core/tools/file-tools/read-file.ts | 154 +++++ .../src/core/tools/file-tools/rename-file.ts | 52 ++ .../src/core/tools/file-tools/text-replace.ts | 76 +++ 10 files changed, 590 insertions(+), 553 deletions(-) create mode 100644 packages/core/src/core/tools/file-tools/common.ts create mode 100644 packages/core/src/core/tools/file-tools/create-file.ts create mode 100644 packages/core/src/core/tools/file-tools/delete-file.ts create mode 100644 packages/core/src/core/tools/file-tools/edit-file.ts create mode 100644 packages/core/src/core/tools/file-tools/index.ts create mode 100644 packages/core/src/core/tools/file-tools/read-file-state.ts create mode 100644 packages/core/src/core/tools/file-tools/read-file.ts create mode 100644 packages/core/src/core/tools/file-tools/rename-file.ts create mode 100644 packages/core/src/core/tools/file-tools/text-replace.ts diff --git a/packages/core/src/core/tools/file-tools.ts b/packages/core/src/core/tools/file-tools.ts index 2237468..08a300d 100644 --- a/packages/core/src/core/tools/file-tools.ts +++ b/packages/core/src/core/tools/file-tools.ts @@ -1,553 +1,7 @@ -import { - getProjectTextFile, - moveProjectTextFile, - readProjectTextFile, - removeProjectFile, - writeProjectTextFile, -} from '../fs/project-fs' - -import { assertTextFilePath, isNotFoundError, normalizeProjectPath } from './path' -import type { - CreateFileInput, - CreateFileOutput, - DeleteFileInput, - DeleteFileOutput, - EditFileInput, - EditFileOutput, - ReadFileInput, - ReadFileOutput, - ReadFileState, - RenameFileInput, - RenameFileOutput, - ToolDefinition, -} from './types' - -const DEFAULT_READ_LIMIT = 2000 -const MAX_READ_LIMIT = 2000 -const MAX_FULL_READ_BYTES = 512 * 1024 -const LEFT_SINGLE_CURLY_QUOTE = '‘' -const RIGHT_SINGLE_CURLY_QUOTE = '’' -const LEFT_DOUBLE_CURLY_QUOTE = '“' -const RIGHT_DOUBLE_CURLY_QUOTE = '”' - -export const readFileTool: ToolDefinition<'ReadFile', ReadFileInput, ReadFileOutput> = { - name: 'ReadFile', - description: '读取当前小说项目中的文本文件,返回带行号的内容。', - validateInput(input) { - const value = asRecord(input) - const path = normalizeProjectPath(readString(value.path, 'ReadFile.path')) - assertTextFilePath(path) - - const offset = readOptionalPositiveInteger(value.offset, 'ReadFile.offset') - const limit = readOptionalPositiveInteger(value.limit, 'ReadFile.limit') - - return { - path, - offset, - limit, - } - }, - async run(input, runtime) { - const file = await getProjectTextFile(runtime.project.handle, input.path) - const shouldReadWholeFile = input.offset === undefined && input.limit === undefined - - if (shouldReadWholeFile && file.size > MAX_FULL_READ_BYTES) { - throw new Error( - `文件 ${input.path} 大小为 ${formatBytes(file.size)},超过 ReadFile 单次完整读取上限 ${formatBytes(MAX_FULL_READ_BYTES)};请使用 offset 和 limit 分段读取,或先用 FindFiles 定位更具体的文件。`, - ) - } - - const content = await file.text() - const readFileState = createReadFileState(input.path, content, file) - runtime.readFileStates?.set(input.path, readFileState) - - const lines = splitLines(content) - const startLine = input.offset ?? 1 - const limit = input.limit ?? DEFAULT_READ_LIMIT - const startIndex = Math.max(startLine - 1, 0) - const selectedLines = lines.slice(startIndex, startIndex + limit) - const empty = content.length === 0 - const offsetBeyondEnd = !empty && startIndex >= lines.length - const endLine = selectedLines.length > 0 ? startIndex + selectedLines.length : startLine - const numberedContent = selectedLines - .map((line, index) => `${String(startIndex + index + 1).padStart(4, ' ')} | ${line}`) - .join('\n') - const notice = getReadNotice({ - empty, - offsetBeyondEnd, - startLine, - totalLines: empty ? 0 : lines.length, - truncated: startIndex + selectedLines.length < lines.length, - }) - - return { - path: input.path, - content: selectedLines.join('\n'), - numberedContent, - readFileState, - startLine, - endLine, - totalLines: empty ? 0 : lines.length, - truncated: startIndex + selectedLines.length < lines.length, - empty, - offsetBeyondEnd, - fileSizeBytes: file.size, - notice, - } - }, - summarizeInput(input) { - return input.offset || input.limit - ? `读取 ${input.path} 的部分内容` - : `读取 ${input.path}` - }, - summarizeOutput(output) { - if (output.empty) { - return `已读取 ${output.path},文件为空` - } - - if (output.offsetBeyondEnd) { - return `已读取 ${output.path},但文件只有 ${output.totalLines} 行,短于请求的起始行 ${output.startLine}` - } - - return output.truncated - ? `已读取 ${output.path} 第 ${output.startLine}-${output.endLine} 行,共 ${output.totalLines} 行,结果已截断` - : `已读取 ${output.path},共 ${output.totalLines} 行` - }, -} - -export const editFileTool: ToolDefinition<'EditFile', EditFileInput, EditFileOutput> = { - name: 'EditFile', - description: '用精确文本替换的方式修改当前小说项目中的已有文本文件;修改前应先读取目标文件。', - validateInput(input) { - const value = asRecord(input) - const path = normalizeProjectPath(readString(value.path, 'EditFile.path')) - const oldText = readString(value.oldText, 'EditFile.oldText') - const newText = readString(value.newText, 'EditFile.newText') - const readFileState = value.readFileState === undefined - ? undefined - : readReadFileState(value.readFileState, 'EditFile.readFileState') - - assertTextFilePath(path) - - if (oldText === newText) { - throw new Error('EditFile.oldText 和 EditFile.newText 完全相同,没有可修改内容') - } - - return { - path, - oldText, - newText, - replaceAll: typeof value.replaceAll === 'boolean' ? value.replaceAll : false, - readFileState, - } - }, - async run(input, runtime) { - const file = await getProjectTextFile(runtime.project.handle, input.path) - const currentContent = await file.text() - const currentState = createReadFileState(input.path, currentContent, file) - const expectedState = input.readFileState ?? runtime.readFileStates?.get(input.path) - - if (!expectedState) { - throw new Error(`修改 ${input.path} 前必须先用 ReadFile 读取目标文件;工具层没有找到可校验的读取状态`) - } - - assertFreshReadFileState(input.path, expectedState, currentState) - - if (!input.oldText) { - throw new Error('EditFile.oldText 不能为空;新增文件请使用 CreateFile,修改已有文件请先 ReadFile 并提供要替换的原文片段') - } - - const actualOldText = findActualText(currentContent, input.oldText) - - if (!actualOldText) { - throw new Error(`在 ${input.path} 中没有找到要替换的原文;请先用 ReadFile 读取最新内容,确认 oldText 与文件内容完全一致,且不要包含行号前缀`) - } - - const occurrences = countOccurrences(currentContent, actualOldText) - - if (occurrences > 1 && !input.replaceAll) { - throw new Error(`在 ${input.path} 中找到 ${occurrences} 处匹配;如需全部替换请启用 replaceAll。如只改其中一处,请直接把目标行与相邻上一行或下一行一起放进 oldText,组成唯一片段后再试`) - } - - const actualNewText = preserveQuoteStyle(input.oldText, actualOldText, input.newText) - const nextContent = input.replaceAll - ? currentContent.split(actualOldText).join(actualNewText) - : currentContent.replace(actualOldText, actualNewText) - - await writeProjectTextFile(runtime.project.handle, input.path, nextContent) - runtime.readFileStates?.delete(input.path) - - return { - path: input.path, - occurrences: input.replaceAll ? occurrences : 1, - contentLength: nextContent.length, - linesAdded: countLines(actualNewText) - countLines(actualOldText), - linesRemoved: Math.max(countLines(actualOldText) - countLines(actualNewText), 0), - } - }, - summarizeInput(input) { - return input.replaceAll - ? `替换 ${input.path} 中所有匹配文本` - : `替换 ${input.path} 中一处匹配文本` - }, - summarizeOutput(output) { - return `已修改 ${output.path},替换 ${output.occurrences} 处,当前 ${output.contentLength} 个字符` - }, -} - -export const createFileTool: ToolDefinition<'CreateFile', CreateFileInput, CreateFileOutput> = { - name: 'CreateFile', - description: '在当前小说项目中新建文本文件;中间目录会自动创建,目标已存在时会失败。已有文件请用 EditFile 修改。', - validateInput(input) { - const value = asRecord(input) - const path = normalizeProjectPath(readString(value.path, 'CreateFile.path')) - const content = readString(value.content, 'CreateFile.content') - - assertTextFilePath(path) - - return { - path, - content, - } - }, - async run(input, runtime) { - try { - await readProjectTextFile(runtime.project.handle, input.path) - throw new Error(`文件已存在:${input.path};CreateFile 只用于新建文件。修改已有文件请先用 ReadFile 读取原文,再使用 EditFile 精确替换`) - } catch (error) { - if (!isNotFoundError(error)) { - throw error - } - } - - await writeProjectTextFile(runtime.project.handle, input.path, input.content) - - return { - path: input.path, - contentLength: input.content.length, - linesAdded: countLines(input.content), - created: true, - } - }, - summarizeInput(input) { - return `新建 ${input.path}` - }, - summarizeOutput(output) { - return `已新建 ${output.path},共 ${output.linesAdded} 行,${output.contentLength} 个字符` - }, -} - -export const renameFileTool: ToolDefinition<'RenameFile', RenameFileInput, RenameFileOutput> = { - name: 'RenameFile', - description: '重命名或移动当前小说项目中的单个文本文件;目标路径已存在时会失败。', - validateInput(input) { - const value = asRecord(input) - const fromPath = normalizeProjectPath(readString(value.fromPath, 'RenameFile.fromPath')) - const toPath = normalizeProjectPath(readString(value.toPath, 'RenameFile.toPath')) - - assertMutableDocumentPath(fromPath, 'RenameFile.fromPath') - assertMutableDocumentPath(toPath, 'RenameFile.toPath') - - if (fromPath === toPath) { - throw new Error('RenameFile.fromPath 和 RenameFile.toPath 不能相同') - } - - return { - fromPath, - toPath, - } - }, - async run(input, runtime) { - const content = await readProjectTextFile(runtime.project.handle, input.fromPath) - - try { - await readProjectTextFile(runtime.project.handle, input.toPath) - throw new Error(`目标文件已存在:${input.toPath};RenameFile 不会覆盖已有文件,请换一个新路径`) - } catch (error) { - if (!isNotFoundError(error)) { - throw error - } - } - - await moveProjectTextFile(runtime.project.handle, input.fromPath, input.toPath) - - return { - fromPath: input.fromPath, - toPath: input.toPath, - contentLength: content.length, - } - }, - summarizeInput(input) { - return `将 ${input.fromPath} 重命名或移动到 ${input.toPath}` - }, - summarizeOutput(output) { - return `已将 ${output.fromPath} 移动到 ${output.toPath},共 ${output.contentLength} 个字符` - }, -} - -export const deleteFileTool: ToolDefinition<'DeleteFile', DeleteFileInput, DeleteFileOutput> = { - name: 'DeleteFile', - description: '将当前小说项目中的单个文本文件移入回收站;不会直接永久删除。', - validateInput(input) { - const value = asRecord(input) - const path = normalizeProjectPath(readString(value.path, 'DeleteFile.path')) - - assertMutableDocumentPath(path, 'DeleteFile.path') - - return { - path, - } - }, - async run(input, runtime) { - const content = await readProjectTextFile(runtime.project.handle, input.path) - const trashPath = createTrashPath(input.path) - - await writeProjectTextFile(runtime.project.handle, trashPath, content) - await removeProjectFile(runtime.project.handle, input.path) - - return { - path: input.path, - trashPath, - contentLength: content.length, - linesRemoved: countLines(content), - } - }, - summarizeInput(input) { - return `删除 ${input.path}` - }, - summarizeOutput(output) { - return `已将 ${output.path} 移入回收站 ${output.trashPath},原文件共 ${output.linesRemoved} 行,${output.contentLength} 个字符` - }, -} - -function asRecord(input: unknown) { - if (!input || typeof input !== 'object') { - throw new Error('工具输入必须是对象') - } - - return input as Record -} - -function assertMutableDocumentPath(path: string, label: string) { - assertTextFilePath(path) - - if (path === 'novel.config.json' || path.startsWith('.novel/')) { - throw new Error(`${label} 不能指向项目配置或 .novel 内部文件`) - } -} - -function createTrashPath(path: string) { - const now = new Date() - const stamp = [ - now.getFullYear(), - `${now.getMonth() + 1}`.padStart(2, '0'), - `${now.getDate()}`.padStart(2, '0'), - `${now.getHours()}`.padStart(2, '0'), - `${now.getMinutes()}`.padStart(2, '0'), - `${now.getSeconds()}`.padStart(2, '0'), - Math.random().toString(36).slice(2, 8), - ].join('-') - - return `.novel/trash/${stamp}/${path}` -} - -function readString(value: unknown, label: string) { - if (typeof value !== 'string') { - throw new Error(`${label} 必须是字符串`) - } - - return value -} - -function readReadFileState(value: unknown, label: string): ReadFileState { - const state = asRecord(value) - const path = normalizeProjectPath(readString(state.path, `${label}.path`)) - const contentHash = readString(state.contentHash, `${label}.contentHash`) - const lastModified = readString(state.lastModified, `${label}.lastModified`) - const fileSizeBytes = state.fileSizeBytes - - if (!Number.isInteger(fileSizeBytes) || Number(fileSizeBytes) < 0) { - throw new Error(`${label}.fileSizeBytes 必须是非负整数`) - } - - return { - path, - contentHash, - lastModified, - fileSizeBytes: Number(fileSizeBytes), - } -} - -function createReadFileState(path: string, content: string, file: File): ReadFileState { - return { - path, - contentHash: hashContent(content), - lastModified: new Date(file.lastModified).toISOString(), - fileSizeBytes: file.size, - } -} - -function assertFreshReadFileState( - path: string, - expectedState: ReadFileState, - currentState: ReadFileState, -) { - if (expectedState.path !== path) { - throw new Error(`EditFile.readFileState.path 与目标文件不一致:读取的是 ${expectedState.path},准备修改的是 ${path}`) - } - - if (expectedState.contentHash !== currentState.contentHash) { - throw new Error(`文件 ${path} 已在 ReadFile 之后发生变化;请重新 ReadFile 获取最新内容后再 EditFile,避免覆盖他人或其他工具的修改`) - } -} - -function hashContent(content: string) { - let hash = 2166136261 - - for (let index = 0; index < content.length; index += 1) { - hash ^= content.charCodeAt(index) - hash = Math.imul(hash, 16777619) - } - - return `h${(hash >>> 0).toString(16)}` -} - -function readOptionalPositiveInteger(value: unknown, label: string) { - if (value === undefined) { - return undefined - } - - if (!Number.isInteger(value) || Number(value) < 1) { - throw new Error(`${label} 必须是正整数`) - } - - const numberValue = Number(value) - - if (numberValue > MAX_READ_LIMIT) { - throw new Error(`${label} 不能超过 ${MAX_READ_LIMIT} 行;请分多次使用 offset/limit 读取`) - } - - return numberValue -} - -function splitLines(content: string) { - if (!content) { - return [] - } - - return content.replace(/\r\n/g, '\n').split('\n') -} - -function getReadNotice(input: { - empty: boolean - offsetBeyondEnd: boolean - startLine: number - totalLines: number - truncated: boolean -}) { - if (input.empty) { - return 'Warning: 文件存在,但内容为空。' - } - - if (input.offsetBeyondEnd) { - return `Warning: 文件存在,但短于请求的起始行 ${input.startLine};当前文件共 ${input.totalLines} 行。` - } - - if (input.truncated) { - return '结果已截断;如需继续阅读,请使用 offset 和 limit 读取后续行。' - } - - return undefined -} - -function formatBytes(bytes: number) { - if (bytes < 1024) { - return `${bytes} B` - } - - if (bytes < 1024 * 1024) { - return `${(bytes / 1024).toFixed(1)} KB` - } - - return `${(bytes / 1024 / 1024).toFixed(1)} MB` -} - -function countOccurrences(source: string, needle: string) { - if (!needle) { - return 0 - } - - return source.split(needle).length - 1 -} - -function findActualText(source: string, searchText: string) { - if (source.includes(searchText)) { - return searchText - } - - const normalizedSource = normalizeQuotes(source) - const normalizedSearchText = normalizeQuotes(searchText) - const startIndex = normalizedSource.indexOf(normalizedSearchText) - - if (startIndex === -1) { - return null - } - - return source.slice(startIndex, startIndex + searchText.length) -} - -function normalizeQuotes(text: string) { - return text - .split(LEFT_SINGLE_CURLY_QUOTE).join("'") - .split(RIGHT_SINGLE_CURLY_QUOTE).join("'") - .split(LEFT_DOUBLE_CURLY_QUOTE).join('"') - .split(RIGHT_DOUBLE_CURLY_QUOTE).join('"') -} - -function preserveQuoteStyle(oldText: string, actualOldText: string, newText: string) { - if (oldText === actualOldText) { - return newText - } - - let nextText = newText - - if (actualOldText.includes(LEFT_DOUBLE_CURLY_QUOTE) || actualOldText.includes(RIGHT_DOUBLE_CURLY_QUOTE)) { - nextText = applyCurlyDoubleQuotes(nextText) - } - - if (actualOldText.includes(LEFT_SINGLE_CURLY_QUOTE) || actualOldText.includes(RIGHT_SINGLE_CURLY_QUOTE)) { - nextText = applyCurlySingleQuotes(nextText) - } - - return nextText -} - -function applyCurlyDoubleQuotes(text: string) { - return replaceStraightQuotes(text, '"', LEFT_DOUBLE_CURLY_QUOTE, RIGHT_DOUBLE_CURLY_QUOTE) -} - -function applyCurlySingleQuotes(text: string) { - return replaceStraightQuotes(text, "'", LEFT_SINGLE_CURLY_QUOTE, RIGHT_SINGLE_CURLY_QUOTE) -} - -function replaceStraightQuotes(text: string, straightQuote: string, leftQuote: string, rightQuote: string) { - let open = true - - return Array.from(text).map((char) => { - if (char !== straightQuote) { - return char - } - - const quote = open ? leftQuote : rightQuote - open = !open - return quote - }).join('') -} - -function countLines(content: string) { - if (!content) { - return 0 - } - - return content.replace(/\r\n/g, '\n').split('\n').length -} +export { + createFileTool, + deleteFileTool, + editFileTool, + readFileTool, + renameFileTool, +} from './file-tools/index' diff --git a/packages/core/src/core/tools/file-tools/common.ts b/packages/core/src/core/tools/file-tools/common.ts new file mode 100644 index 0000000..09ff2f9 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/common.ts @@ -0,0 +1,39 @@ +import { assertTextFilePath, normalizeProjectPath } from '../path' + +export function asRecord(input: unknown) { + if (!input || typeof input !== 'object') { + throw new Error('工具输入必须是对象') + } + + return input as Record +} + +export function readString(value: unknown, label: string) { + if (typeof value !== 'string') { + throw new Error(`${label} 必须是字符串`) + } + + return value +} + +export function assertMutableDocumentPath(path: string, label: string) { + assertTextFilePath(path) + + if (path === 'novel.config.json' || path.startsWith('.novel/')) { + throw new Error(`${label} 不能指向项目配置或 .novel 内部文件`) + } +} + +export function normalizeTextFilePath(value: unknown, label: string) { + const path = normalizeProjectPath(readString(value, label)) + assertTextFilePath(path) + return path +} + +export function countLines(content: string) { + if (!content) { + return 0 + } + + return content.replace(/\r\n/g, '\n').split('\n').length +} diff --git a/packages/core/src/core/tools/file-tools/create-file.ts b/packages/core/src/core/tools/file-tools/create-file.ts new file mode 100644 index 0000000..cd2f758 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/create-file.ts @@ -0,0 +1,44 @@ +import { readProjectTextFile, writeProjectTextFile } from '../../fs/project-fs' +import { isNotFoundError } from '../path' +import type { CreateFileInput, CreateFileOutput, ToolDefinition } from '../types' +import { asRecord, countLines, normalizeTextFilePath, readString } from './common' + +export const createFileTool: ToolDefinition<'CreateFile', CreateFileInput, CreateFileOutput> = { + name: 'CreateFile', + description: '在当前小说项目中新建文本文件;中间目录会自动创建,目标已存在时会失败。已有文件请用 EditFile 修改。', + validateInput(input) { + const value = asRecord(input) + const path = normalizeTextFilePath(value.path, 'CreateFile.path') + const content = readString(value.content, 'CreateFile.content') + + return { + path, + content, + } + }, + async run(input, runtime) { + try { + await readProjectTextFile(runtime.project.handle, input.path) + throw new Error(`文件已存在:${input.path};CreateFile 只用于新建文件。修改已有文件请先用 ReadFile 读取原文,再使用 EditFile 精确替换`) + } catch (error) { + if (!isNotFoundError(error)) { + throw error + } + } + + await writeProjectTextFile(runtime.project.handle, input.path, input.content) + + return { + path: input.path, + contentLength: input.content.length, + linesAdded: countLines(input.content), + created: true, + } + }, + summarizeInput(input) { + return `新建 ${input.path}` + }, + summarizeOutput(output) { + return `已新建 ${output.path},共 ${output.linesAdded} 行,${output.contentLength} 个字符` + }, +} diff --git a/packages/core/src/core/tools/file-tools/delete-file.ts b/packages/core/src/core/tools/file-tools/delete-file.ts new file mode 100644 index 0000000..27252e2 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/delete-file.ts @@ -0,0 +1,63 @@ +import { + readProjectTextFile, + removeProjectFile, + writeProjectTextFile, +} from '../../fs/project-fs' +import { normalizeProjectPath } from '../path' +import type { DeleteFileInput, DeleteFileOutput, ToolDefinition } from '../types' +import { + asRecord, + assertMutableDocumentPath, + countLines, + readString, +} from './common' + +export const deleteFileTool: ToolDefinition<'DeleteFile', DeleteFileInput, DeleteFileOutput> = { + name: 'DeleteFile', + description: '将当前小说项目中的单个文本文件移入回收站;不会直接永久删除。', + validateInput(input) { + const value = asRecord(input) + const path = normalizeProjectPath(readString(value.path, 'DeleteFile.path')) + + assertMutableDocumentPath(path, 'DeleteFile.path') + + return { + path, + } + }, + async run(input, runtime) { + const content = await readProjectTextFile(runtime.project.handle, input.path) + const trashPath = createTrashPath(input.path) + + await writeProjectTextFile(runtime.project.handle, trashPath, content) + await removeProjectFile(runtime.project.handle, input.path) + + return { + path: input.path, + trashPath, + contentLength: content.length, + linesRemoved: countLines(content), + } + }, + summarizeInput(input) { + return `删除 ${input.path}` + }, + summarizeOutput(output) { + return `已将 ${output.path} 移入回收站 ${output.trashPath},原文件共 ${output.linesRemoved} 行,${output.contentLength} 个字符` + }, +} + +function createTrashPath(path: string) { + const now = new Date() + const stamp = [ + now.getFullYear(), + `${now.getMonth() + 1}`.padStart(2, '0'), + `${now.getDate()}`.padStart(2, '0'), + `${now.getHours()}`.padStart(2, '0'), + `${now.getMinutes()}`.padStart(2, '0'), + `${now.getSeconds()}`.padStart(2, '0'), + Math.random().toString(36).slice(2, 8), + ].join('-') + + return `.novel/trash/${stamp}/${path}` +} diff --git a/packages/core/src/core/tools/file-tools/edit-file.ts b/packages/core/src/core/tools/file-tools/edit-file.ts new file mode 100644 index 0000000..69eedf9 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/edit-file.ts @@ -0,0 +1,94 @@ +import { getProjectTextFile, writeProjectTextFile } from '../../fs/project-fs' +import type { EditFileInput, EditFileOutput, ToolDefinition } from '../types' +import { assertTextFilePath, normalizeProjectPath } from '../path' +import { asRecord, countLines, readString } from './common' +import { + assertFreshReadFileState, + createReadFileState, + readReadFileState, +} from './read-file-state' +import { + countOccurrences, + findActualText, + preserveQuoteStyle, +} from './text-replace' + +export const editFileTool: ToolDefinition<'EditFile', EditFileInput, EditFileOutput> = { + name: 'EditFile', + description: '用精确文本替换的方式修改当前小说项目中的已有文本文件;修改前应先读取目标文件。', + validateInput(input) { + const value = asRecord(input) + const path = normalizeProjectPath(readString(value.path, 'EditFile.path')) + const oldText = readString(value.oldText, 'EditFile.oldText') + const newText = readString(value.newText, 'EditFile.newText') + const readFileState = value.readFileState === undefined + ? undefined + : readReadFileState(value.readFileState, 'EditFile.readFileState') + + assertTextFilePath(path) + + if (oldText === newText) { + throw new Error('EditFile.oldText 和 EditFile.newText 完全相同,没有可修改内容') + } + + return { + path, + oldText, + newText, + replaceAll: typeof value.replaceAll === 'boolean' ? value.replaceAll : false, + readFileState, + } + }, + async run(input, runtime) { + const file = await getProjectTextFile(runtime.project.handle, input.path) + const currentContent = await file.text() + const currentState = createReadFileState(input.path, currentContent, file) + const expectedState = input.readFileState ?? runtime.readFileStates?.get(input.path) + + if (!expectedState) { + throw new Error(`修改 ${input.path} 前必须先用 ReadFile 读取目标文件;工具层没有找到可校验的读取状态`) + } + + assertFreshReadFileState(input.path, expectedState, currentState) + + if (!input.oldText) { + throw new Error('EditFile.oldText 不能为空;新增文件请使用 CreateFile,修改已有文件请先 ReadFile 并提供要替换的原文片段') + } + + const actualOldText = findActualText(currentContent, input.oldText) + + if (!actualOldText) { + throw new Error(`在 ${input.path} 中没有找到要替换的原文;请先用 ReadFile 读取最新内容,确认 oldText 与文件内容完全一致,且不要包含行号前缀`) + } + + const occurrences = countOccurrences(currentContent, actualOldText) + + if (occurrences > 1 && !input.replaceAll) { + throw new Error(`在 ${input.path} 中找到 ${occurrences} 处匹配;如需全部替换请启用 replaceAll。如只改其中一处,请直接把目标行与相邻上一行或下一行一起放进 oldText,组成唯一片段后再试`) + } + + const actualNewText = preserveQuoteStyle(input.oldText, actualOldText, input.newText) + const nextContent = input.replaceAll + ? currentContent.split(actualOldText).join(actualNewText) + : currentContent.replace(actualOldText, actualNewText) + + await writeProjectTextFile(runtime.project.handle, input.path, nextContent) + runtime.readFileStates?.delete(input.path) + + return { + path: input.path, + occurrences: input.replaceAll ? occurrences : 1, + contentLength: nextContent.length, + linesAdded: countLines(actualNewText) - countLines(actualOldText), + linesRemoved: Math.max(countLines(actualOldText) - countLines(actualNewText), 0), + } + }, + summarizeInput(input) { + return input.replaceAll + ? `替换 ${input.path} 中所有匹配文本` + : `替换 ${input.path} 中一处匹配文本` + }, + summarizeOutput(output) { + return `已修改 ${output.path},替换 ${output.occurrences} 处,当前 ${output.contentLength} 个字符` + }, +} diff --git a/packages/core/src/core/tools/file-tools/index.ts b/packages/core/src/core/tools/file-tools/index.ts new file mode 100644 index 0000000..c06ee05 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/index.ts @@ -0,0 +1,5 @@ +export { createFileTool } from './create-file' +export { deleteFileTool } from './delete-file' +export { editFileTool } from './edit-file' +export { readFileTool } from './read-file' +export { renameFileTool } from './rename-file' diff --git a/packages/core/src/core/tools/file-tools/read-file-state.ts b/packages/core/src/core/tools/file-tools/read-file-state.ts new file mode 100644 index 0000000..9731ca5 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/read-file-state.ts @@ -0,0 +1,56 @@ +import { normalizeProjectPath } from '../path' +import type { ReadFileState } from '../types' +import { asRecord, readString } from './common' + +export function readReadFileState(value: unknown, label: string): ReadFileState { + const state = asRecord(value) + const path = normalizeProjectPath(readString(state.path, `${label}.path`)) + const contentHash = readString(state.contentHash, `${label}.contentHash`) + const lastModified = readString(state.lastModified, `${label}.lastModified`) + const fileSizeBytes = state.fileSizeBytes + + if (!Number.isInteger(fileSizeBytes) || Number(fileSizeBytes) < 0) { + throw new Error(`${label}.fileSizeBytes 必须是非负整数`) + } + + return { + path, + contentHash, + lastModified, + fileSizeBytes: Number(fileSizeBytes), + } +} + +export function createReadFileState(path: string, content: string, file: File): ReadFileState { + return { + path, + contentHash: hashContent(content), + lastModified: new Date(file.lastModified).toISOString(), + fileSizeBytes: file.size, + } +} + +export function assertFreshReadFileState( + path: string, + expectedState: ReadFileState, + currentState: ReadFileState, +) { + if (expectedState.path !== path) { + throw new Error(`EditFile.readFileState.path 与目标文件不一致:读取的是 ${expectedState.path},准备修改的是 ${path}`) + } + + if (expectedState.contentHash !== currentState.contentHash) { + throw new Error(`文件 ${path} 已在 ReadFile 之后发生变化;请重新 ReadFile 获取最新内容后再 EditFile,避免覆盖他人或其他工具的修改`) + } +} + +function hashContent(content: string) { + let hash = 2166136261 + + for (let index = 0; index < content.length; index += 1) { + hash ^= content.charCodeAt(index) + hash = Math.imul(hash, 16777619) + } + + return `h${(hash >>> 0).toString(16)}` +} diff --git a/packages/core/src/core/tools/file-tools/read-file.ts b/packages/core/src/core/tools/file-tools/read-file.ts new file mode 100644 index 0000000..7bf2964 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/read-file.ts @@ -0,0 +1,154 @@ +import { getProjectTextFile } from '../../fs/project-fs' +import type { ReadFileInput, ReadFileOutput, ToolDefinition } from '../types' +import { asRecord, readString } from './common' +import { createReadFileState } from './read-file-state' +import { assertTextFilePath, normalizeProjectPath } from '../path' + +const DEFAULT_READ_LIMIT = 2000 +const MAX_READ_LIMIT = 2000 +const MAX_FULL_READ_BYTES = 512 * 1024 + +export const readFileTool: ToolDefinition<'ReadFile', ReadFileInput, ReadFileOutput> = { + name: 'ReadFile', + description: '读取当前小说项目中的文本文件,返回带行号的内容。', + validateInput(input) { + const value = asRecord(input) + const path = normalizeProjectPath(readString(value.path, 'ReadFile.path')) + assertTextFilePath(path) + + const offset = readOptionalPositiveInteger(value.offset, 'ReadFile.offset') + const limit = readOptionalPositiveInteger(value.limit, 'ReadFile.limit') + + return { + path, + offset, + limit, + } + }, + async run(input, runtime) { + const file = await getProjectTextFile(runtime.project.handle, input.path) + const shouldReadWholeFile = input.offset === undefined && input.limit === undefined + + if (shouldReadWholeFile && file.size > MAX_FULL_READ_BYTES) { + throw new Error( + `文件 ${input.path} 大小为 ${formatBytes(file.size)},超过 ReadFile 单次完整读取上限 ${formatBytes(MAX_FULL_READ_BYTES)};请使用 offset 和 limit 分段读取,或先用 FindFiles 定位更具体的文件。`, + ) + } + + const content = await file.text() + const readFileState = createReadFileState(input.path, content, file) + runtime.readFileStates?.set(input.path, readFileState) + + const lines = splitLines(content) + const startLine = input.offset ?? 1 + const limit = input.limit ?? DEFAULT_READ_LIMIT + const startIndex = Math.max(startLine - 1, 0) + const selectedLines = lines.slice(startIndex, startIndex + limit) + const empty = content.length === 0 + const offsetBeyondEnd = !empty && startIndex >= lines.length + const endLine = selectedLines.length > 0 ? startIndex + selectedLines.length : startLine + const numberedContent = selectedLines + .map((line, index) => `${String(startIndex + index + 1).padStart(4, ' ')} | ${line}`) + .join('\n') + const notice = getReadNotice({ + empty, + offsetBeyondEnd, + startLine, + totalLines: empty ? 0 : lines.length, + truncated: startIndex + selectedLines.length < lines.length, + }) + + return { + path: input.path, + content: selectedLines.join('\n'), + numberedContent, + readFileState, + startLine, + endLine, + totalLines: empty ? 0 : lines.length, + truncated: startIndex + selectedLines.length < lines.length, + empty, + offsetBeyondEnd, + fileSizeBytes: file.size, + notice, + } + }, + summarizeInput(input) { + return input.offset || input.limit + ? `读取 ${input.path} 的部分内容` + : `读取 ${input.path}` + }, + summarizeOutput(output) { + if (output.empty) { + return `已读取 ${output.path},文件为空` + } + + if (output.offsetBeyondEnd) { + return `已读取 ${output.path},但文件只有 ${output.totalLines} 行,短于请求的起始行 ${output.startLine}` + } + + return output.truncated + ? `已读取 ${output.path} 第 ${output.startLine}-${output.endLine} 行,共 ${output.totalLines} 行,结果已截断` + : `已读取 ${output.path},共 ${output.totalLines} 行` + }, +} + +function readOptionalPositiveInteger(value: unknown, label: string) { + if (value === undefined) { + return undefined + } + + if (!Number.isInteger(value) || Number(value) < 1) { + throw new Error(`${label} 必须是正整数`) + } + + const numberValue = Number(value) + + if (numberValue > MAX_READ_LIMIT) { + throw new Error(`${label} 不能超过 ${MAX_READ_LIMIT} 行;请分多次使用 offset/limit 读取`) + } + + return numberValue +} + +function splitLines(content: string) { + if (!content) { + return [] + } + + return content.replace(/\r\n/g, '\n').split('\n') +} + +function getReadNotice(input: { + empty: boolean + offsetBeyondEnd: boolean + startLine: number + totalLines: number + truncated: boolean +}) { + if (input.empty) { + return 'Warning: 文件存在,但内容为空。' + } + + if (input.offsetBeyondEnd) { + return `Warning: 文件存在,但短于请求的起始行 ${input.startLine};当前文件共 ${input.totalLines} 行。` + } + + if (input.truncated) { + return '结果已截断;如需继续阅读,请使用 offset 和 limit 读取后续行。' + } + + return undefined +} + +function formatBytes(bytes: number) { + if (bytes < 1024) { + return `${bytes} B` + } + + if (bytes < 1024 * 1024) { + return `${(bytes / 1024).toFixed(1)} KB` + } + + return `${(bytes / 1024 / 1024).toFixed(1)} MB` +} diff --git a/packages/core/src/core/tools/file-tools/rename-file.ts b/packages/core/src/core/tools/file-tools/rename-file.ts new file mode 100644 index 0000000..eb98d93 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/rename-file.ts @@ -0,0 +1,52 @@ +import { moveProjectTextFile, readProjectTextFile } from '../../fs/project-fs' +import { isNotFoundError, normalizeProjectPath } from '../path' +import type { RenameFileInput, RenameFileOutput, ToolDefinition } from '../types' +import { asRecord, assertMutableDocumentPath, readString } from './common' + +export const renameFileTool: ToolDefinition<'RenameFile', RenameFileInput, RenameFileOutput> = { + name: 'RenameFile', + description: '重命名或移动当前小说项目中的单个文本文件;目标路径已存在时会失败。', + validateInput(input) { + const value = asRecord(input) + const fromPath = normalizeProjectPath(readString(value.fromPath, 'RenameFile.fromPath')) + const toPath = normalizeProjectPath(readString(value.toPath, 'RenameFile.toPath')) + + assertMutableDocumentPath(fromPath, 'RenameFile.fromPath') + assertMutableDocumentPath(toPath, 'RenameFile.toPath') + + if (fromPath === toPath) { + throw new Error('RenameFile.fromPath 和 RenameFile.toPath 不能相同') + } + + return { + fromPath, + toPath, + } + }, + async run(input, runtime) { + const content = await readProjectTextFile(runtime.project.handle, input.fromPath) + + try { + await readProjectTextFile(runtime.project.handle, input.toPath) + throw new Error(`目标文件已存在:${input.toPath};RenameFile 不会覆盖已有文件,请换一个新路径`) + } catch (error) { + if (!isNotFoundError(error)) { + throw error + } + } + + await moveProjectTextFile(runtime.project.handle, input.fromPath, input.toPath) + + return { + fromPath: input.fromPath, + toPath: input.toPath, + contentLength: content.length, + } + }, + summarizeInput(input) { + return `将 ${input.fromPath} 重命名或移动到 ${input.toPath}` + }, + summarizeOutput(output) { + return `已将 ${output.fromPath} 移动到 ${output.toPath},共 ${output.contentLength} 个字符` + }, +} diff --git a/packages/core/src/core/tools/file-tools/text-replace.ts b/packages/core/src/core/tools/file-tools/text-replace.ts new file mode 100644 index 0000000..d153296 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/text-replace.ts @@ -0,0 +1,76 @@ +const LEFT_SINGLE_CURLY_QUOTE = '‘' +const RIGHT_SINGLE_CURLY_QUOTE = '’' +const LEFT_DOUBLE_CURLY_QUOTE = '“' +const RIGHT_DOUBLE_CURLY_QUOTE = '”' + +export function countOccurrences(source: string, needle: string) { + if (!needle) { + return 0 + } + + return source.split(needle).length - 1 +} + +export function findActualText(source: string, searchText: string) { + if (source.includes(searchText)) { + return searchText + } + + const normalizedSource = normalizeQuotes(source) + const normalizedSearchText = normalizeQuotes(searchText) + const startIndex = normalizedSource.indexOf(normalizedSearchText) + + if (startIndex === -1) { + return null + } + + return source.slice(startIndex, startIndex + searchText.length) +} + +export function preserveQuoteStyle(oldText: string, actualOldText: string, newText: string) { + if (oldText === actualOldText) { + return newText + } + + let nextText = newText + + if (actualOldText.includes(LEFT_DOUBLE_CURLY_QUOTE) || actualOldText.includes(RIGHT_DOUBLE_CURLY_QUOTE)) { + nextText = applyCurlyDoubleQuotes(nextText) + } + + if (actualOldText.includes(LEFT_SINGLE_CURLY_QUOTE) || actualOldText.includes(RIGHT_SINGLE_CURLY_QUOTE)) { + nextText = applyCurlySingleQuotes(nextText) + } + + return nextText +} + +function normalizeQuotes(text: string) { + return text + .split(LEFT_SINGLE_CURLY_QUOTE).join("'") + .split(RIGHT_SINGLE_CURLY_QUOTE).join("'") + .split(LEFT_DOUBLE_CURLY_QUOTE).join('"') + .split(RIGHT_DOUBLE_CURLY_QUOTE).join('"') +} + +function applyCurlyDoubleQuotes(text: string) { + return replaceStraightQuotes(text, '"', LEFT_DOUBLE_CURLY_QUOTE, RIGHT_DOUBLE_CURLY_QUOTE) +} + +function applyCurlySingleQuotes(text: string) { + return replaceStraightQuotes(text, "'", LEFT_SINGLE_CURLY_QUOTE, RIGHT_SINGLE_CURLY_QUOTE) +} + +function replaceStraightQuotes(text: string, straightQuote: string, leftQuote: string, rightQuote: string) { + let open = true + + return Array.from(text).map((char) => { + if (char !== straightQuote) { + return char + } + + const quote = open ? leftQuote : rightQuote + open = !open + return quote + }).join('') +} From 4d1295132a8c1a4925efcc3abcfc958067abc6fe Mon Sep 17 00:00:00 2001 From: honlnk Date: Sun, 24 May 2026 22:44:50 +0800 Subject: [PATCH 03/16] =?UTF-8?q?test(other):=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=B7=A5=E5=85=B7=E8=A1=8C=E4=B8=BA=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs | 2 +- package.json | 4 +- .../core/tools/file-tools/file-tools.test.ts | 319 ++++++++++++++++++ packages/core/tsconfig.json | 3 +- pnpm-lock.yaml | 235 +++++++++++++ vitest.config.ts | 8 + 6 files changed, 568 insertions(+), 3 deletions(-) create mode 100644 packages/core/src/core/tools/file-tools/file-tools.test.ts create mode 100644 vitest.config.ts diff --git a/docs b/docs index ac57a0a..f9b5950 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit ac57a0a709d33f26462c191edb6cb454791acbad +Subproject commit f9b5950a6f04b6cb0b35ccde6484e18e870d602c diff --git a/package.json b/package.json index 866b3c4..0dbf6ad 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "pnpm --filter @novai/app dev", "build": "pnpm --filter @novai/app build", + "test": "vitest run", "typecheck": "tsc --build", "commitlint": "commitlint --edit", "prepare": "husky" @@ -16,6 +17,7 @@ "commitlint-plugin-function-rules": "^4.3.2", "husky": "^9.1.7", "typescript": "^6.0.2", - "vite": "^6.2.0" + "vite": "^6.2.0", + "vitest": "^4.1.7" } } diff --git a/packages/core/src/core/tools/file-tools/file-tools.test.ts b/packages/core/src/core/tools/file-tools/file-tools.test.ts new file mode 100644 index 0000000..6e21c73 --- /dev/null +++ b/packages/core/src/core/tools/file-tools/file-tools.test.ts @@ -0,0 +1,319 @@ +import { describe, expect, it } from 'vitest' +import { + createFileTool, + deleteFileTool, + editFileTool, + readFileTool, + renameFileTool, +} from '../file-tools' +import type { ProjectSnapshot } from '../../../types/project' +import type { ToolRuntime } from '../types' + +describe('file tools', () => { + it('requires ReadFile state before EditFile and edits a fresh file', async () => { + const runtime = createRuntime({ + 'chapters/001.md': '第一段\n第二段', + }) + + await expect(editFileTool.run({ + path: 'chapters/001.md', + oldText: '第二段', + newText: '第二段修改', + }, runtime)).rejects.toThrow('必须先用 ReadFile') + + const readOutput = await readFileTool.run({ path: 'chapters/001.md' }, runtime) + + expect(readOutput.numberedContent).toContain('1 | 第一段') + + const editOutput = await editFileTool.run({ + path: 'chapters/001.md', + oldText: '第二段', + newText: '第二段修改', + }, runtime) + + expect(editOutput.occurrences).toBe(1) + await expect(readProjectText(runtime.project.handle, 'chapters/001.md')).resolves.toBe('第一段\n第二段修改') + }) + + it('rejects EditFile when the file changed after ReadFile', async () => { + const runtime = createRuntime({ + 'chapters/001.md': '旧内容', + }) + + await readFileTool.run({ path: 'chapters/001.md' }, runtime) + await writeProjectText(runtime.project.handle, 'chapters/001.md', '外部修改') + + await expect(editFileTool.run({ + path: 'chapters/001.md', + oldText: '旧内容', + newText: '新内容', + }, runtime)).rejects.toThrow('已在 ReadFile 之后发生变化') + }) + + it('creates new files but refuses to overwrite existing files', async () => { + const runtime = createRuntime({ + 'chapters/existing.md': '已有内容', + }) + + await createFileTool.run({ + path: 'chapters/new.md', + content: '新内容', + }, runtime) + + await expect(readProjectText(runtime.project.handle, 'chapters/new.md')).resolves.toBe('新内容') + await expect(createFileTool.run({ + path: 'chapters/existing.md', + content: '覆盖内容', + }, runtime)).rejects.toThrow('文件已存在') + }) + + it('renames files and refuses to overwrite destination files', async () => { + const runtime = createRuntime({ + 'chapters/source.md': '源内容', + 'chapters/existing.md': '已有内容', + }) + + await expect(renameFileTool.run({ + fromPath: 'chapters/source.md', + toPath: 'chapters/existing.md', + }, runtime)).rejects.toThrow('目标文件已存在') + + await renameFileTool.run({ + fromPath: 'chapters/source.md', + toPath: 'chapters/renamed.md', + }, runtime) + + await expect(readProjectText(runtime.project.handle, 'chapters/renamed.md')).resolves.toBe('源内容') + await expect(readProjectText(runtime.project.handle, 'chapters/source.md')).rejects.toThrow('Not found') + }) + + it('moves deleted files into the project trash', async () => { + const runtime = createRuntime({ + 'chapters/old.md': '废稿', + }) + + const output = await deleteFileTool.run({ path: 'chapters/old.md' }, runtime) + + expect(output.trashPath).toMatch(/^\.novel\/trash\/.+\/chapters\/old\.md$/) + await expect(readProjectText(runtime.project.handle, output.trashPath)).resolves.toBe('废稿') + await expect(readProjectText(runtime.project.handle, 'chapters/old.md')).rejects.toThrow('Not found') + }) +}) + +function createRuntime(files: Record): ToolRuntime { + const handle = createMemoryDirectory('novel') + + for (const [path, content] of Object.entries(files)) { + writeProjectTextSync(handle, path, content) + } + + return { + project: { + id: 'test-project', + name: 'Test Project', + rootName: 'novel', + handle, + config: {} as ProjectSnapshot['config'], + manifest: {} as ProjectSnapshot['manifest'], + tree: [], + metadata: {} as ProjectSnapshot['metadata'], + }, + readFileStates: new Map(), + } +} + +type MemoryFileEntry = { + kind: 'file' + name: string + content: string + lastModified: number +} + +type MemoryDirectoryEntry = { + kind: 'directory' + name: string + entries: Map +} + +type MemoryEntry = MemoryFileEntry | MemoryDirectoryEntry + +type MemoryDirectoryHandle = FileSystemDirectoryHandle & { + __entry: MemoryDirectoryEntry +} + +function createMemoryDirectory(name: string): MemoryDirectoryHandle { + return createDirectoryHandle({ + kind: 'directory', + name, + entries: new Map(), + }) +} + +function createDirectoryHandle(entry: MemoryDirectoryEntry): MemoryDirectoryHandle { + return { + kind: 'directory', + name: entry.name, + __entry: entry, + async getDirectoryHandle(name: string, options?: FileSystemGetDirectoryOptions) { + const current = entry.entries.get(name) + + if (current?.kind === 'directory') { + return createDirectoryHandle(current) + } + + if (current) { + throw new DOMException(`Not a directory: ${name}`, 'TypeMismatchError') + } + + if (!options?.create) { + throw new DOMException(`Not found: ${name}`, 'NotFoundError') + } + + const next: MemoryDirectoryEntry = { + kind: 'directory', + name, + entries: new Map(), + } + entry.entries.set(name, next) + return createDirectoryHandle(next) + }, + async getFileHandle(name: string, options?: FileSystemGetFileOptions) { + const current = entry.entries.get(name) + + if (current?.kind === 'file') { + return createFileHandle(current) + } + + if (current) { + throw new DOMException(`Not a file: ${name}`, 'TypeMismatchError') + } + + if (!options?.create) { + throw new DOMException(`Not found: ${name}`, 'NotFoundError') + } + + const next: MemoryFileEntry = { + kind: 'file', + name, + content: '', + lastModified: Date.now(), + } + entry.entries.set(name, next) + return createFileHandle(next) + }, + async removeEntry(name: string) { + if (!entry.entries.delete(name)) { + throw new DOMException(`Not found: ${name}`, 'NotFoundError') + } + }, + async *values() { + for (const child of entry.entries.values()) { + yield child.kind === 'directory' + ? createDirectoryHandle(child) + : createFileHandle(child) + } + }, + } as unknown as MemoryDirectoryHandle +} + +function createFileHandle(entry: MemoryFileEntry): FileSystemFileHandle { + return { + kind: 'file', + name: entry.name, + async getFile() { + return new File([entry.content], entry.name, { + type: 'text/plain', + lastModified: entry.lastModified, + }) + }, + async createWritable() { + let nextContent = '' + + return { + async write(data: FileSystemWriteChunkType) { + nextContent = typeof data === 'string' + ? data + : data instanceof Blob + ? await data.text() + : String(data) + }, + async close() { + entry.content = nextContent + entry.lastModified = Date.now() + }, + } as FileSystemWritableFileStream + }, + } as unknown as FileSystemFileHandle +} + +function writeProjectTextSync(rootHandle: MemoryDirectoryHandle, path: string, content: string) { + const segments = path.split('/').filter(Boolean) + const fileName = segments.pop() + + if (!fileName) { + throw new Error(`Invalid file path: ${path}`) + } + + let current = rootHandle.__entry + + for (const segment of segments) { + const existing = current.entries.get(segment) + + if (existing?.kind === 'file') { + throw new Error(`Not a directory: ${segment}`) + } + + if (existing?.kind === 'directory') { + current = existing + continue + } + + const next: MemoryDirectoryEntry = { + kind: 'directory', + name: segment, + entries: new Map(), + } + current.entries.set(segment, next) + current = next + } + + current.entries.set(fileName, { + kind: 'file', + name: fileName, + content, + lastModified: Date.now(), + }) +} + +async function writeProjectText(rootHandle: FileSystemDirectoryHandle, path: string, content: string) { + const fileHandle = await resolveMemoryFileHandle(rootHandle, path, true) + const writable = await fileHandle.createWritable() + await writable.write(content) + await writable.close() +} + +async function readProjectText(rootHandle: FileSystemDirectoryHandle, path: string) { + const fileHandle = await resolveMemoryFileHandle(rootHandle, path, false) + return (await fileHandle.getFile()).text() +} + +async function resolveMemoryFileHandle( + rootHandle: FileSystemDirectoryHandle, + path: string, + create: boolean, +) { + const segments = path.split('/').filter(Boolean) + const fileName = segments.pop() + + if (!fileName) { + throw new Error(`Invalid file path: ${path}`) + } + + let current = rootHandle + + for (const segment of segments) { + current = await current.getDirectoryHandle(segment, { create }) + } + + return current.getFileHandle(fileName, { create }) +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index e8e4dec..62dcf6c 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -16,5 +16,6 @@ "rootDir": "./src", "types": ["vite/client"] }, - "include": ["src/**/*.ts"] + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.test.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37e24db..241c2a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: vite: specifier: ^6.2.0 version: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0) + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@25.9.1)(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0)) packages/app: dependencies: @@ -585,6 +588,9 @@ packages: resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==} engines: {node: '>=18'} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tailwindcss/node@4.3.0': resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} @@ -675,6 +681,12 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -691,6 +703,35 @@ packages: vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 + '@vitest/expect@4.1.7': + resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} + + '@vitest/mocker@4.1.7': + resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.7': + resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} + + '@vitest/runner@4.1.7': + resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} + + '@vitest/snapshot@4.1.7': + resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} + + '@vitest/spy@4.1.7': + resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} + + '@vitest/utils@4.1.7': + resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} + '@volar/language-core@2.4.28': resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} @@ -784,6 +825,10 @@ packages: array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-kit@2.2.0: resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} engines: {node: '>=20.19.0'} @@ -799,6 +844,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -846,6 +895,9 @@ packages: engines: {node: '>=18'} hasBin: true + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + copy-anything@4.0.5: resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} engines: {node: '>=18'} @@ -896,6 +948,9 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-toolkit@1.46.1: resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} @@ -911,6 +966,13 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -1138,6 +1200,9 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -1232,6 +1297,9 @@ packages: engines: {node: '>=10'} hasBin: true + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1240,6 +1308,12 @@ packages: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} engines: {node: '>=0.10.0'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1259,6 +1333,9 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@1.1.2: resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} @@ -1267,6 +1344,10 @@ packages: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} @@ -1326,6 +1407,47 @@ packages: yaml: optional: true + vitest@4.1.7: + resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.7 + '@vitest/browser-preview': 4.1.7 + '@vitest/browser-webdriverio': 4.1.7 + '@vitest/coverage-istanbul': 4.1.7 + '@vitest/coverage-v8': 4.1.7 + '@vitest/ui': 4.1.7 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -1361,6 +1483,11 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -1782,6 +1909,8 @@ snapshots: '@simple-libs/stream-utils@1.2.0': {} + '@standard-schema/spec@1.1.0': {} + '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 @@ -1850,6 +1979,13 @@ snapshots: tailwindcss: 4.3.0 vite: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0) + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + '@types/estree@1.0.8': {} '@types/jsesc@2.5.1': {} @@ -1863,6 +1999,47 @@ snapshots: vite: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0) vue: 3.5.34(typescript@6.0.3) + '@vitest/expect@4.1.7': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.7(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0))': + dependencies: + '@vitest/spy': 4.1.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0) + + '@vitest/pretty-format@4.1.7': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.7': + dependencies: + '@vitest/utils': 4.1.7 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + '@vitest/utils': 4.1.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.7': {} + + '@vitest/utils@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + '@volar/language-core@2.4.28': dependencies: '@volar/source-map': 2.4.28 @@ -2001,6 +2178,8 @@ snapshots: array-ify@1.0.0: {} + assertion-error@2.0.1: {} + ast-kit@2.2.0: dependencies: '@babel/parser': 7.29.3 @@ -2015,6 +2194,8 @@ snapshots: callsites@3.1.0: {} + chai@6.2.2: {} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -2061,6 +2242,8 @@ snapshots: '@simple-libs/stream-utils': 1.2.0 meow: 13.2.0 + convert-source-map@2.0.0: {} + copy-anything@4.0.5: dependencies: is-what: 5.5.0 @@ -2104,6 +2287,8 @@ snapshots: dependencies: is-arrayish: 0.2.1 + es-module-lexer@2.1.0: {} + es-toolkit@1.46.1: {} esbuild@0.25.12: @@ -2139,6 +2324,12 @@ snapshots: estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + expect-type@1.3.0: {} + exsolve@1.0.8: {} fast-deep-equal@3.1.3: {} @@ -2304,6 +2495,8 @@ snapshots: node-addon-api@7.1.1: optional: true + obug@2.1.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -2411,10 +2604,16 @@ snapshots: semver@7.8.0: {} + siginfo@2.0.0: {} + source-map-js@1.2.1: {} speakingurl@14.0.1: {} + stackback@0.0.2: {} + + std-env@4.1.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -2433,6 +2632,8 @@ snapshots: tapable@2.3.3: {} + tinybench@2.9.0: {} + tinyexec@1.1.2: {} tinyglobby@0.2.16: @@ -2440,6 +2641,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyrainbow@3.1.0: {} + typescript@6.0.3: {} ufo@1.6.4: {} @@ -2473,6 +2676,33 @@ snapshots: sass: 1.99.0 yaml: 2.9.0 + vitest@4.1.7(@types/node@25.9.1)(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0)): + dependencies: + '@vitest/expect': 4.1.7 + '@vitest/mocker': 4.1.7(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.7 + '@vitest/runner': 4.1.7 + '@vitest/snapshot': 4.1.7 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.99.0)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.9.1 + transitivePeerDependencies: + - msw + vscode-uri@3.1.0: {} vue-router@5.0.7(@vue/compiler-sfc@3.5.34)(pinia@3.0.4(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3)): @@ -2517,6 +2747,11 @@ snapshots: webpack-virtual-modules@0.6.2: {} + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..96300bc --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['packages/**/src/**/*.test.ts'], + exclude: ['**/dist/**', '**/node_modules/**'], + }, +}) From e00ce7cb15c2fa0d460786a213ddef39ed4ef297 Mon Sep 17 00:00:00 2001 From: honlnk Date: Mon, 25 May 2026 23:26:34 +0800 Subject: [PATCH 04/16] =?UTF-8?q?refactor(other):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E6=8B=86=E5=88=86=E5=90=8E=E7=9A=84=E6=97=A7=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/core/src/core/tools/file-tools.ts | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 packages/core/src/core/tools/file-tools.ts diff --git a/packages/core/src/core/tools/file-tools.ts b/packages/core/src/core/tools/file-tools.ts deleted file mode 100644 index 08a300d..0000000 --- a/packages/core/src/core/tools/file-tools.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { - createFileTool, - deleteFileTool, - editFileTool, - readFileTool, - renameFileTool, -} from './file-tools/index' From 3e9d4c392ad99a8e7f715e94d78d22c47a289b38 Mon Sep 17 00:00:00 2001 From: honlnk Date: Mon, 1 Jun 2026 01:17:35 +0800 Subject: [PATCH 05/16] =?UTF-8?q?feat(ui):=20=E6=90=AD=E5=BB=BA=E6=AD=A3?= =?UTF-8?q?=E5=BC=8F=20UI=20=E9=A1=B5=E9=9D=A2=E9=AA=A8=E6=9E=B6=E5=92=8C?= =?UTF-8?q?=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增首页 HomeView(项目列表、新建/打开项目) - 新增主工作区 ProjectView(三栏布局:文件树 + 对话 + 内容预览) - 新增设置页 SettingsView(LLM/Embedding/Rerank 配置) - 新增布局组件:FileTreeSidebar、ChatPanel、ContentPanel - 新增全局样式 style.css(Tailwind + 自定义滚动条) - 更新路由配置,添加三个新页面路由 - 更新 chatStore,添加 messages、createSession、sendMessage --- packages/app/src/app/router.ts | 16 +- .../app/src/components/layout/ChatPanel.vue | 171 +++++++++ .../src/components/layout/ContentPanel.vue | 53 +++ .../src/components/layout/FileTreeSidebar.vue | 166 +++++++++ packages/app/src/main.ts | 1 + packages/app/src/stores/chat.ts | 20 ++ packages/app/src/style.css | 51 +++ packages/app/src/views/HomeView.vue | 170 +++++++++ packages/app/src/views/ProjectView.vue | 90 +++++ packages/app/src/views/SettingsView.vue | 329 ++++++++++++++++++ 10 files changed, 1066 insertions(+), 1 deletion(-) create mode 100644 packages/app/src/components/layout/ChatPanel.vue create mode 100644 packages/app/src/components/layout/ContentPanel.vue create mode 100644 packages/app/src/components/layout/FileTreeSidebar.vue create mode 100644 packages/app/src/style.css create mode 100644 packages/app/src/views/HomeView.vue create mode 100644 packages/app/src/views/ProjectView.vue create mode 100644 packages/app/src/views/SettingsView.vue diff --git a/packages/app/src/app/router.ts b/packages/app/src/app/router.ts index 7bade65..77dfbae 100644 --- a/packages/app/src/app/router.ts +++ b/packages/app/src/app/router.ts @@ -1,5 +1,8 @@ import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' +import ProjectView from '../views/ProjectView.vue' +import SettingsView from '../views/SettingsView.vue' import SessionTestView from '../views/SessionTestView.vue' import TestLabView from '../views/TestLabView.vue' @@ -8,7 +11,18 @@ export const router = createRouter({ routes: [ { path: '/', - redirect: '/test', + name: 'home', + component: HomeView, + }, + { + path: '/project/:id', + name: 'project', + component: ProjectView, + }, + { + path: '/project/:id/settings', + name: 'settings', + component: SettingsView, }, { path: '/test', diff --git a/packages/app/src/components/layout/ChatPanel.vue b/packages/app/src/components/layout/ChatPanel.vue new file mode 100644 index 0000000..3f893df --- /dev/null +++ b/packages/app/src/components/layout/ChatPanel.vue @@ -0,0 +1,171 @@ + + + diff --git a/packages/app/src/components/layout/ContentPanel.vue b/packages/app/src/components/layout/ContentPanel.vue new file mode 100644 index 0000000..b2fb45b --- /dev/null +++ b/packages/app/src/components/layout/ContentPanel.vue @@ -0,0 +1,53 @@ + + + diff --git a/packages/app/src/components/layout/FileTreeSidebar.vue b/packages/app/src/components/layout/FileTreeSidebar.vue new file mode 100644 index 0000000..2b82ce1 --- /dev/null +++ b/packages/app/src/components/layout/FileTreeSidebar.vue @@ -0,0 +1,166 @@ + + + diff --git a/packages/app/src/main.ts b/packages/app/src/main.ts index f359f1c..c8f1341 100644 --- a/packages/app/src/main.ts +++ b/packages/app/src/main.ts @@ -1,6 +1,7 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' +import './style.css' import App from './App.vue' import { router } from './app/router' diff --git a/packages/app/src/stores/chat.ts b/packages/app/src/stores/chat.ts index c820f4e..14b6fb0 100644 --- a/packages/app/src/stores/chat.ts +++ b/packages/app/src/stores/chat.ts @@ -10,6 +10,7 @@ import { import type { AgentUiEvent, ChangedFileView, + ChatMessageView, ChatSessionView, ChatTargetView, RunAgentTurnInput, @@ -25,6 +26,7 @@ export const useChatStore = defineStore('chat', () => { const hasSessionView = computed(() => sessionView.value !== null) const currentTarget = computed(() => defaultTarget.value) + const messages = computed(() => sessionView.value?.messages ?? []) async function ensureSessionView(projectId: string) { if (!sessionView.value || sessionView.value.projectId !== projectId) { @@ -132,15 +134,33 @@ export const useChatStore = defineStore('chat', () => { } } + async function createSession(projectId: string) { + return ensureSessionView(projectId) + } + + async function sendMessage(text: string) { + if (!sessionView.value) { + throw new Error('没有活跃的会话') + } + + return runServiceTurn({ + projectId: sessionView.value.projectId, + instruction: text, + }) + } + return { agentEvents, changedFiles, + messages, sessionView, runStatus, hasSessionView, currentTarget, defaultTarget, + createSession, ensureSessionView, + sendMessage, runServiceTurn, syncDefaultTarget, resetSession, diff --git a/packages/app/src/style.css b/packages/app/src/style.css new file mode 100644 index 0000000..0136bd0 --- /dev/null +++ b/packages/app/src/style.css @@ -0,0 +1,51 @@ +@import "tailwindcss"; + +* { + scrollbar-width: thin; + scrollbar-color: transparent transparent; +} + +*:hover { + scrollbar-color: rgba(155, 155, 155, 0.4) transparent; +} + +*::-webkit-scrollbar { + width: 5px; + height: 5px; +} + +*::-webkit-scrollbar-track { + background: transparent; +} + +*::-webkit-scrollbar-thumb { + background-color: transparent; + border-radius: 9999px; + transition: background-color 0.2s; +} + +*:hover::-webkit-scrollbar-thumb { + background-color: rgba(155, 155, 155, 0.4); +} + +*::-webkit-scrollbar-thumb:hover { + background-color: rgba(120, 120, 120, 0.6); +} + +*::-webkit-scrollbar-corner { + background: transparent; +} + +.overflow-y-auto, +.overflow-x-auto, +.overflow-auto { + overflow: overlay; +} + +.overflow-y-auto { + overflow-y: overlay; +} + +.overflow-x-auto { + overflow-x: overlay; +} diff --git a/packages/app/src/views/HomeView.vue b/packages/app/src/views/HomeView.vue new file mode 100644 index 0000000..dbfc8cc --- /dev/null +++ b/packages/app/src/views/HomeView.vue @@ -0,0 +1,170 @@ + + + diff --git a/packages/app/src/views/ProjectView.vue b/packages/app/src/views/ProjectView.vue new file mode 100644 index 0000000..6f74eaf --- /dev/null +++ b/packages/app/src/views/ProjectView.vue @@ -0,0 +1,90 @@ + + + diff --git a/packages/app/src/views/SettingsView.vue b/packages/app/src/views/SettingsView.vue new file mode 100644 index 0000000..bd9e597 --- /dev/null +++ b/packages/app/src/views/SettingsView.vue @@ -0,0 +1,329 @@ + + + From 527a200b710aee169e1df7760130757d9a36930d Mon Sep 17 00:00:00 2001 From: honlnk Date: Mon, 1 Jun 2026 01:35:06 +0800 Subject: [PATCH 06/16] =?UTF-8?q?feat(ui):=20=E5=AE=8C=E5=96=84=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E5=8A=9F=E8=83=BD=E5=92=8C=E6=9C=80=E8=BF=91=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 改进 recent-projects.ts,支持保存和读取最近项目列表(最多 8 个) - 添加 readRecentProjects、forgetRecentProject 方法 - 添加 cleanupOldProjects 自动清理旧记录 - 更新 project-service.ts,暴露 getRecentProjects、forgetRecentProject - 更新 projectStore,添加 loadRecentProjects 方法 - 更新 HomeView,页面加载时自动加载最近项目列表 - 更新数据库版本从 1 到 2 --- packages/app/src/stores/project.ts | 19 +++++ packages/app/src/views/HomeView.vue | 1 + packages/app/tsconfig.tsbuildinfo | 2 +- .../core/src/core/project/recent-projects.ts | 84 +++++++++++++++++-- packages/core/src/services/project-service.ts | 10 +++ packages/core/tsconfig.tsbuildinfo | 2 +- 6 files changed, 109 insertions(+), 9 deletions(-) diff --git a/packages/app/src/stores/project.ts b/packages/app/src/stores/project.ts index 16db127..4e213ea 100644 --- a/packages/app/src/stores/project.ts +++ b/packages/app/src/stores/project.ts @@ -6,6 +6,7 @@ import { createProject, forgetLastProject, getLastProjectSummary, + getRecentProjects, isProjectAccessSupported, openProject, restoreLastProject, @@ -78,6 +79,23 @@ export const useProjectStore = defineStore('project', () => { } } + async function loadRecentProjects() { + try { + const summaries = await getRecentProjects() + recentProjects.value = summaries.map((summary) => ({ + id: summary.projectId, + name: summary.name, + updatedAt: summary.lastOpenedAt, + chapterCount: 0, + wordCount: 0, + })) + return recentProjects.value + } catch (error) { + errorMessage.value = toMessage(error, '读取最近项目列表失败') + return [] + } + } + async function forgetLastOpenedProject() { return runProjectAction(async () => { await forgetLastProject() @@ -191,6 +209,7 @@ export const useProjectStore = defineStore('project', () => { createNewProject, forgetLastOpenedProject, loadLastProjectSummary, + loadRecentProjects, openExistingProject, openFile, refreshTree, diff --git a/packages/app/src/views/HomeView.vue b/packages/app/src/views/HomeView.vue index dbfc8cc..a4463a2 100644 --- a/packages/app/src/views/HomeView.vue +++ b/packages/app/src/views/HomeView.vue @@ -11,6 +11,7 @@ const isCreating = ref(false) onMounted(async () => { await projectStore.loadLastProjectSummary() + await projectStore.loadRecentProjects() }) async function handleOpenProject() { diff --git a/packages/app/tsconfig.tsbuildinfo b/packages/app/tsconfig.tsbuildinfo index 8560ab9..c95ea84 100644 --- a/packages/app/tsconfig.tsbuildinfo +++ b/packages/app/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hmrpayload.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/customevent.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hot.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importglob.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importmeta.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/client.d.ts","../../node_modules/.pnpm/@vue+shared@3.5.34/node_modules/@vue/shared/dist/shared.d.ts","../../node_modules/.pnpm/@babel+types@8.0.0-rc.5/node_modules/@babel/types/lib/index.d.ts","../../node_modules/.pnpm/@babel+types@7.29.0/node_modules/@babel/types/lib/index.d.ts","../../node_modules/.pnpm/@babel+parser@7.29.3/node_modules/@babel/parser/typings/babel-parser.d.ts","../../node_modules/.pnpm/@vue+compiler-core@3.5.34/node_modules/@vue/compiler-core/dist/compiler-core.d.ts","../../node_modules/.pnpm/@vue+compiler-dom@3.5.34/node_modules/@vue/compiler-dom/dist/compiler-dom.d.ts","../../node_modules/.pnpm/@vue+reactivity@3.5.34/node_modules/@vue/reactivity/dist/reactivity.d.ts","../../node_modules/.pnpm/@vue+runtime-core@3.5.34/node_modules/@vue/runtime-core/dist/runtime-core.d.ts","../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@vue+runtime-dom@3.5.34/node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts","../../node_modules/.pnpm/vue@3.5.34_typescript@6.0.3/node_modules/vue/dist/vue.d.mts","./src/env.d.ts","../../node_modules/.pnpm/pinia@3.0.4_typescript@6.0.3_vue@3.5.34_typescript@6.0.3_/node_modules/pinia/dist/pinia.d.ts","../../node_modules/.pnpm/@vue+language-core@3.3.1/node_modules/@vue/language-core/types/template-helpers.d.ts","../../node_modules/.pnpm/@vue+language-core@3.3.1/node_modules/@vue/language-core/types/props-fallback.d.ts","../../node_modules/.pnpm/vue@3.5.34_typescript@6.0.3/node_modules/vue/jsx-runtime/index.d.ts","./src/app.vue","../../node_modules/.pnpm/vue-router@5.0.7_@vue+compiler-sfc@3.5.34_pinia@3.0.4_typescript@6.0.3_vue@3.5.34_types_f357d1e940226713debf99bc42fbe5c2/node_modules/vue-router/dist/useapi-d6ckosfy.d.ts","../../node_modules/.pnpm/vue-router@5.0.7_@vue+compiler-sfc@3.5.34_pinia@3.0.4_typescript@6.0.3_vue@3.5.34_types_f357d1e940226713debf99bc42fbe5c2/node_modules/vue-router/dist/vue-router.d.ts","../core/dist/services/types.d.ts","../core/dist/services/agent-service.d.ts","./src/stores/chat.ts","../core/dist/services/project-service.d.ts","../core/dist/services/file-service.d.ts","../core/dist/types/project.d.ts","./src/stores/project.ts","../core/dist/services/settings-service.d.ts","./src/stores/settings.ts","./src/views/sessiontestview.vue","../core/dist/services/element-service.d.ts","../core/dist/services/generation-service.d.ts","../core/dist/services/rag-service.d.ts","./src/views/testlabview.vue","./src/app/router.ts","./src/main.ts"],"fileIdsList":[[56],[54,55,57],[58],[54],[54,60,61,63],[60,61,62,63],[64,66,72],[52],[48],[49],[50,51],[64,66,71],[59,63],[63],[64,66,67,68,69,72],[72,82,86],[53,64,66,72],[64,66,70,72,87],[64,66,72,73,74],[64,66,72,73,76,77,78],[64,66,72,73,80],[64,66,67,68,69,72,73,75,79,81],[64,66,67,68,69,72,73,77,79,81,83,84,85],[73]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"11443a1dcfaaa404c68d53368b5b818712b95dd19f188cab1669c39bee8b84b3","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"19efad8495a7a6b064483fccd1d2b427403dd84e67819f86d1c6ee3d7abf749c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1eef826bc4a19de22155487984e345a34c9cd511dd1170edc7a447cb8231dd4a","affectsGlobalScope":true,"impliedFormat":99},{"version":"f468b74459f1ad4473b36a36d49f2b255f3c6b5d536c81239c2b2971df089eaf","impliedFormat":1},{"version":"e19fc27b55bda55e22503b87a0088eb3f29e993d99ebee0d241484b18fae9e88","impliedFormat":99},{"version":"556ccd493ec36c7d7cb130d51be66e147b91cc1415be383d71da0f1e49f742a9","impliedFormat":1},{"version":"95aba78013d782537cc5e23868e736bec5d377b918990e28ed56110e3ae8b958","impliedFormat":1},{"version":"524a409ad72186b7f6cb16898c349465cfa876f641d6cb6137b3123d5cfca619","impliedFormat":1},{"version":"ebe84ad8344962b7117a3b95065f47383215020eaf1b626463863b45b4d16e62","impliedFormat":1},{"version":"8fa68a409acbfc169f88bc6763ffb2df73b49346a938fd7b75397261995db523","impliedFormat":1},{"version":"3e74c6f34a28b7c948bfdaf19172000d589093660b3605f8c21c1b30173c729b","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"88ad1af02cacc61bf79683b021d326eeafc91231660a06495c5046d4649ec3a2","impliedFormat":1},{"version":"c0191592be8eb7906f99ac4b8798d80a585b94001ea1a5f50d6ce5b0d13a5c62","impliedFormat":99},{"version":"7fa7622afe198960b201179bc83c50ef77f3f1edf14033add6c4ca1bc20ae88b","affectsGlobalScope":true},{"version":"dce3621e6c42ff85a85c26f827081feb317a2b45bc35007b7158964a2a9e1ed4","impliedFormat":99},{"version":"29b484e9f5db01367687a1034a8fe578c2781fde30be8c26bd468ed0c9ce1489","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b346992df6d898a855dc7c681864f8f05f701e7f3ddfbf4686747b4788d54aa","affectsGlobalScope":true,"impliedFormat":1},{"version":"318d19118bf6bf8d088441c948990f53cafc79ed581b78f3d41a0f7a3f5f145c","impliedFormat":1},{"version":"0b8a4870148802a2a9b3037b443fb2cd1019b3b8855fc17cb656ae9ab8ac3838","signature":"720c2acbad2528546f9260e00b918ba43830a5f1497e24d738c9125ca36063d0"},{"version":"7154bb6c4454128fcabb83cd963f5307b8410ef9130dddca015195d850b41eeb","impliedFormat":99},{"version":"295c68f2873f5366c1ea52efb166685bc1659bd15c18d70c9cc426ec60ef68ba","impliedFormat":99},"8f20963ec6f7ae8760d0b469bba9b7dae1ad429aab6ea0c3ae279e15e0572787","87ea6c2cecc8422526ea7e585a23935ad90997be8fee9be8924458231a01b88e",{"version":"804ddbc053351009d8c9e9db85899df2761e115f405ae68c3399779c8c1b3b82","signature":"0c07e7bb386f838469e175f19357c79f490fe92b0a11f534771fe0338ee19084"},"b53609d061652d412054f8ee5b2a49af0cd35641255b677e2cd309f881facafd","8f8332d5643c6c13e4924ba980e59d87f80a008a8609b0c7baa690408d19c698","0085499168f9de37efeddef62e5a2bbdcd5152b91b687087195d3f9b1a9c922b",{"version":"e27b4a690f41da47cc970f712c0f023b24d1448dcbf868dd640faf02ad68e4e9","signature":"576662648ee67abb3f676296d44de67a6b66f0500b52ff5301317f3fcf049264"},"3e3e10f3ebf23bfec47d0d2d6db0b7bdcbbd889d71d701455e32fc6a760bac57",{"version":"3871faade7ac4521b653a4de3a33bce173e2ccb005e265e9f213af1779b6e742","signature":"a01afcceddbefcb761eb6e90a2e443c2a45a745aa162e5f0bc2e20ed261c9b23"},{"version":"228963fc9f7f0c24c9a419038fb6cfa0190d23aa27b8be9090dbfa16ced65bfd","signature":"720c2acbad2528546f9260e00b918ba43830a5f1497e24d738c9125ca36063d0"},"3611aa813d1f93dc13442515cb8dbcc1a17316c8e436c7452b7bf5c0961851b9","82f55cbd01275d4375acc18dafa9b72251844b638cd2b5bd7efe8d20a64833e1","05da64738e1628634ee52939320168d44b8a06a9c86dcab0fd52f5d0a448161b",{"version":"2758a1c9f91dc2433fcaa0bc47b50e1ec4d4cf7e9345b1acb3e6bde4b250c526","signature":"720c2acbad2528546f9260e00b918ba43830a5f1497e24d738c9125ca36063d0"},{"version":"3fca6ac2af9e0cc0b9bd3844ca1e32edd8d9a0b4c4a878fc8efeee05d11a2116","signature":"160b37c5f96761b5535fe25fdbfb3c6dd7b24327c9542918633db70d7527de9b"},{"version":"0a793daf5af74504ecdd6609a4019045ea0639d5d2354df2c7a7cb277a6265d4","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"}],"root":[65,70,75,79,81,82,[86,88]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":99,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"target":7},"referencedMap":[[57,1],[58,2],[59,3],[60,4],[61,5],[63,6],[66,7],[53,8],[49,9],[50,10],[52,11],[71,7],[72,12],[64,13],[69,14],[70,15],[87,16],[65,17],[88,18],[75,19],[79,20],[81,21],[82,22],[86,23],[74,24],[83,24],[77,24],[84,24],[76,24],[85,24],[80,24]],"affectedFilesPendingEmit":[[70,49],[87,49],[88,49],[75,49],[79,49],[81,49],[82,49],[86,49]],"emitSignatures":[70,82,86],"latestChangedDtsFile":"./dist/stores/settings.d.ts","version":"6.0.3"} \ No newline at end of file +{"fileNames":["../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hmrpayload.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/customevent.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hot.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importglob.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importmeta.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/client.d.ts","../../node_modules/.pnpm/@vue+shared@3.5.34/node_modules/@vue/shared/dist/shared.d.ts","../../node_modules/.pnpm/@babel+types@8.0.0-rc.5/node_modules/@babel/types/lib/index.d.ts","../../node_modules/.pnpm/@babel+types@7.29.0/node_modules/@babel/types/lib/index.d.ts","../../node_modules/.pnpm/@babel+parser@7.29.3/node_modules/@babel/parser/typings/babel-parser.d.ts","../../node_modules/.pnpm/@vue+compiler-core@3.5.34/node_modules/@vue/compiler-core/dist/compiler-core.d.ts","../../node_modules/.pnpm/@vue+compiler-dom@3.5.34/node_modules/@vue/compiler-dom/dist/compiler-dom.d.ts","../../node_modules/.pnpm/@vue+reactivity@3.5.34/node_modules/@vue/reactivity/dist/reactivity.d.ts","../../node_modules/.pnpm/@vue+runtime-core@3.5.34/node_modules/@vue/runtime-core/dist/runtime-core.d.ts","../../node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","../../node_modules/.pnpm/@vue+runtime-dom@3.5.34/node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts","../../node_modules/.pnpm/vue@3.5.34_typescript@6.0.3/node_modules/vue/dist/vue.d.mts","./src/env.d.ts","../../node_modules/.pnpm/pinia@3.0.4_typescript@6.0.3_vue@3.5.34_typescript@6.0.3_/node_modules/pinia/dist/pinia.d.ts","../../node_modules/.pnpm/@vue+language-core@3.3.1/node_modules/@vue/language-core/types/template-helpers.d.ts","../../node_modules/.pnpm/@vue+language-core@3.3.1/node_modules/@vue/language-core/types/props-fallback.d.ts","../../node_modules/.pnpm/vue@3.5.34_typescript@6.0.3/node_modules/vue/jsx-runtime/index.d.ts","./src/app.vue","../../node_modules/.pnpm/vue-router@5.0.7_@vue+compiler-sfc@3.5.34_pinia@3.0.4_typescript@6.0.3_vue@3.5.34_types_f357d1e940226713debf99bc42fbe5c2/node_modules/vue-router/dist/useapi-d6ckosfy.d.ts","../../node_modules/.pnpm/vue-router@5.0.7_@vue+compiler-sfc@3.5.34_pinia@3.0.4_typescript@6.0.3_vue@3.5.34_types_f357d1e940226713debf99bc42fbe5c2/node_modules/vue-router/dist/vue-router.d.ts","../core/dist/services/types.d.ts","../core/dist/services/project-service.d.ts","../core/dist/services/file-service.d.ts","../core/dist/types/project.d.ts","./src/stores/project.ts","./src/views/homeview.vue","../core/dist/services/agent-service.d.ts","./src/stores/chat.ts","../core/dist/types/ai.d.ts","../core/dist/types/rag.d.ts","../core/dist/core/agent/messages.d.ts","../core/dist/types/chat.d.ts","../core/dist/types/elements.d.ts","../core/dist/services/element-service.d.ts","../core/dist/services/generation-service.d.ts","../core/dist/services/rag-service.d.ts","../core/dist/services/settings-service.d.ts","../core/dist/services/project-runtime.d.ts","../core/dist/index.d.ts","./src/components/layout/filetreesidebar.vue","./src/components/layout/chatpanel.vue","./src/components/layout/contentpanel.vue","./src/views/projectview.vue","./src/stores/settings.ts","./src/views/settingsview.vue","./src/views/sessiontestview.vue","./src/views/testlabview.vue","./src/app/router.ts","./src/main.ts"],"fileIdsList":[[56],[54,55,57],[58],[54],[54,60,61,63],[60,61,62,63],[64,66,72],[52],[48],[49],[50,51],[64,66,71],[59,63],[63],[64,66,67,68,69,72],[72,78,95,97,98,99],[64,66,67,68,69,72,80],[64,66,67,68,69,72,91],[53,64,66,72],[53,64,66,70,72,100],[64,66,72,73,79],[64,66,72,73,74,75,76],[64,66,72,73,89],[64,66,67,68,69,72,77],[64,66,67,68,69,72,77,80,92,93,94],[64,66,67,68,69,72,73,77,80,96],[64,66,67,68,69,72,77,96],[64,66,67,68,69,72,73,75,77,86,87,88,96],[73,74,75,76,79,81,82,84,85,86,87,88,89,90],[73],[76],[76,82,83],[82]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"11443a1dcfaaa404c68d53368b5b818712b95dd19f188cab1669c39bee8b84b3","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"19efad8495a7a6b064483fccd1d2b427403dd84e67819f86d1c6ee3d7abf749c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1eef826bc4a19de22155487984e345a34c9cd511dd1170edc7a447cb8231dd4a","affectsGlobalScope":true,"impliedFormat":99},{"version":"f468b74459f1ad4473b36a36d49f2b255f3c6b5d536c81239c2b2971df089eaf","impliedFormat":1},{"version":"e19fc27b55bda55e22503b87a0088eb3f29e993d99ebee0d241484b18fae9e88","impliedFormat":99},{"version":"556ccd493ec36c7d7cb130d51be66e147b91cc1415be383d71da0f1e49f742a9","impliedFormat":1},{"version":"95aba78013d782537cc5e23868e736bec5d377b918990e28ed56110e3ae8b958","impliedFormat":1},{"version":"524a409ad72186b7f6cb16898c349465cfa876f641d6cb6137b3123d5cfca619","impliedFormat":1},{"version":"ebe84ad8344962b7117a3b95065f47383215020eaf1b626463863b45b4d16e62","impliedFormat":1},{"version":"8fa68a409acbfc169f88bc6763ffb2df73b49346a938fd7b75397261995db523","impliedFormat":1},{"version":"3e74c6f34a28b7c948bfdaf19172000d589093660b3605f8c21c1b30173c729b","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"88ad1af02cacc61bf79683b021d326eeafc91231660a06495c5046d4649ec3a2","impliedFormat":1},{"version":"c0191592be8eb7906f99ac4b8798d80a585b94001ea1a5f50d6ce5b0d13a5c62","impliedFormat":99},{"version":"7fa7622afe198960b201179bc83c50ef77f3f1edf14033add6c4ca1bc20ae88b","affectsGlobalScope":true},{"version":"dce3621e6c42ff85a85c26f827081feb317a2b45bc35007b7158964a2a9e1ed4","impliedFormat":99},{"version":"29b484e9f5db01367687a1034a8fe578c2781fde30be8c26bd468ed0c9ce1489","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b346992df6d898a855dc7c681864f8f05f701e7f3ddfbf4686747b4788d54aa","affectsGlobalScope":true,"impliedFormat":1},{"version":"318d19118bf6bf8d088441c948990f53cafc79ed581b78f3d41a0f7a3f5f145c","impliedFormat":1},{"version":"0b8a4870148802a2a9b3037b443fb2cd1019b3b8855fc17cb656ae9ab8ac3838","signature":"720c2acbad2528546f9260e00b918ba43830a5f1497e24d738c9125ca36063d0"},{"version":"7154bb6c4454128fcabb83cd963f5307b8410ef9130dddca015195d850b41eeb","impliedFormat":99},{"version":"295c68f2873f5366c1ea52efb166685bc1659bd15c18d70c9cc426ec60ef68ba","impliedFormat":99},"8f20963ec6f7ae8760d0b469bba9b7dae1ad429aab6ea0c3ae279e15e0572787","076a04f22f43c90975397208426922b5c03b89c3fe36d2c936446645f09b195b","8f8332d5643c6c13e4924ba980e59d87f80a008a8609b0c7baa690408d19c698","0085499168f9de37efeddef62e5a2bbdcd5152b91b687087195d3f9b1a9c922b",{"version":"dee312b8f87970b0403f95f7ce98821c81d425ea780a6fa2d472381c55ccf7cd","signature":"6ffcab3a7d8f7595f5b4e5117ca51aa47bc384388d0a8e3829c41c3d022a08ee"},"6080b4b58f412870a5c81477ad74395716670d820aa38c8ac8f234c434774d8f","87ea6c2cecc8422526ea7e585a23935ad90997be8fee9be8924458231a01b88e",{"version":"a7a8e3a3a083990053e30689756eb3eca97ffe066c14cc6500faaa988363014e","signature":"234f1be8ef09b52aa7363000eba5ed898846720b036bf8f5784d22c1a4cdfa66"},"9a8d5ee2f3e3046860461283b2702cf9d7fa8ca97e31f6aa0fb8df321ce47ff6","05738a9eb9d1dcd4a18ca5e9bcd6eca022bc719ee95ea6083ad20db40aa750e9","a728f0d0f2c5a28978e3f0cf6beca9ee5d69d746c7c4c5ede32eaace652d9bf8","7518de7f3a9ac1c7aa26422e211c4107c3e462856b9d9f1a5af49965b0ef7ab8","a60dac8e4a952db827558e08792f1b356df1a33a0f860990c829be623273a5a8","3611aa813d1f93dc13442515cb8dbcc1a17316c8e436c7452b7bf5c0961851b9","82f55cbd01275d4375acc18dafa9b72251844b638cd2b5bd7efe8d20a64833e1","05da64738e1628634ee52939320168d44b8a06a9c86dcab0fd52f5d0a448161b","3e3e10f3ebf23bfec47d0d2d6db0b7bdcbbd889d71d701455e32fc6a760bac57","066971c44cc55d9a3db5aeeb31df5b8b7f05e43cd4da9178dfbc595c17dfd9bc","d8d51f4bdd3130bafd993a6052504c42024f60a88bd04f8c291e6e593ded62a9",{"version":"5c664a6f73409742ad91341c6ba8e073de1f75900814fa84cae18c8b2c1f827a","signature":"04b3fc94a40366f725f8f19f202dacf44a0cfa704722f2bd686495cdfb513cc4"},"d42a0a60080601281cd20c9251286500b0d8785959f0250abc3ffedf350515b7",{"version":"a7a2de4260bd89644f7cdb7a60fdd11ddd299c4adb943a27568e0175734af717","signature":"e59eb109afd40aa497cca3b8736a30bcc5890e857ca65bf37f57a4d80ebd1bdc"},"96daeb6578bf4aad1e95593ec0cb39d9c30f844d22d36d699b2876addb64ae9f",{"version":"3871faade7ac4521b653a4de3a33bce173e2ccb005e265e9f213af1779b6e742","signature":"a01afcceddbefcb761eb6e90a2e443c2a45a745aa162e5f0bc2e20ed261c9b23"},"ea9ee713d98dd8aa0732d1dfa1ce895165c8703f7294a28cd58ac2a39f52f9d4",{"version":"228963fc9f7f0c24c9a419038fb6cfa0190d23aa27b8be9090dbfa16ced65bfd","signature":"720c2acbad2528546f9260e00b918ba43830a5f1497e24d738c9125ca36063d0"},{"version":"2758a1c9f91dc2433fcaa0bc47b50e1ec4d4cf7e9345b1acb3e6bde4b250c526","signature":"720c2acbad2528546f9260e00b918ba43830a5f1497e24d738c9125ca36063d0"},"09bdeae94a34d9c3ea59fc37eac2a2af2a3efda433be3444e947a2b2f99ba00c","a88724c6026972cec3ac138dd1170a352fc8abd2bd500dceae91441e342fbda5"],"root":[65,70,77,78,80,[92,101]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":99,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"target":7},"referencedMap":[[57,1],[58,2],[59,3],[60,4],[61,5],[63,6],[66,7],[53,8],[49,9],[50,10],[52,11],[71,7],[72,12],[64,13],[69,14],[70,15],[100,16],[93,17],[94,15],[92,18],[65,19],[101,20],[80,21],[77,22],[96,23],[78,24],[95,25],[98,26],[97,27],[99,28],[91,29],[79,30],[86,30],[75,30],[87,30],[90,31],[74,30],[88,30],[89,30],[84,32],[85,33]],"affectedFilesPendingEmit":[[70,49],[100,49],[93,49],[94,49],[92,49],[101,49],[80,49],[77,49],[96,49],[78,49],[95,49],[98,49],[97,49],[99,49]],"emitSignatures":[70,77,78,80,92,93,94,95,96,97,98,99,100,101],"version":"6.0.3"} \ No newline at end of file diff --git a/packages/core/src/core/project/recent-projects.ts b/packages/core/src/core/project/recent-projects.ts index b4d276e..3b10a37 100644 --- a/packages/core/src/core/project/recent-projects.ts +++ b/packages/core/src/core/project/recent-projects.ts @@ -1,7 +1,8 @@ const DATABASE_NAME = 'novai-projects' -const DATABASE_VERSION = 1 +const DATABASE_VERSION = 2 const STORE_NAME = 'recent-projects' const LAST_PROJECT_KEY = 'last-opened' +const MAX_RECENT_PROJECTS = 8 type PermissionMode = 'read' | 'readwrite' @@ -15,7 +16,7 @@ type PersistableDirectoryHandle = FileSystemDirectoryHandle & { } export type LastProjectRecord = { - key: typeof LAST_PROJECT_KEY + key: typeof LAST_PROJECT_KEY | `project-${string}` projectId: string name: string rootName: string @@ -31,21 +32,38 @@ export async function saveLastProject(input: { rootName: string handle: FileSystemDirectoryHandle }): Promise { - const record: LastProjectRecord = { + const database = await openDatabase() + const now = new Date().toISOString() + + // 保存为最后一个项目 + const lastRecord: LastProjectRecord = { key: LAST_PROJECT_KEY, projectId: input.projectId, name: input.name, rootName: input.rootName, - lastOpenedAt: new Date().toISOString(), + lastOpenedAt: now, handle: input.handle, } - const database = await openDatabase() + // 保存到最近项目列表 + const recentRecord: LastProjectRecord = { + key: `project-${input.projectId}`, + projectId: input.projectId, + name: input.name, + rootName: input.rootName, + lastOpenedAt: now, + handle: input.handle, + } + + await runStoreRequest(database, 'readwrite', (store) => store.put(lastRecord)) + await runStoreRequest(database, 'readwrite', (store) => store.put(recentRecord)) + + // 清理超过限制的旧记录 + await cleanupOldProjects(database) - await runStoreRequest(database, 'readwrite', (store) => store.put(record)) database.close() - return record + return lastRecord } export async function readLastProject(): Promise { @@ -60,6 +78,30 @@ export async function readLastProject(): Promise { return record ?? null } +export async function readRecentProjects(): Promise { + const database = await openDatabase() + const allRecords = await runStoreRequest( + database, + 'readonly', + (store) => store.getAll(), + ) + + database.close() + + // 过滤出最近项目记录(排除 last-opened),按时间倒序 + const recentRecords = allRecords + .filter((record) => record.key !== LAST_PROJECT_KEY) + .sort((a, b) => new Date(b.lastOpenedAt).getTime() - new Date(a.lastOpenedAt).getTime()) + .slice(0, MAX_RECENT_PROJECTS) + + return recentRecords.map((record) => ({ + projectId: record.projectId, + name: record.name, + rootName: record.rootName, + lastOpenedAt: record.lastOpenedAt, + })) +} + export async function forgetLastProject() { const database = await openDatabase() @@ -67,6 +109,13 @@ export async function forgetLastProject() { database.close() } +export async function forgetRecentProject(projectId: string) { + const database = await openDatabase() + + await runStoreRequest(database, 'readwrite', (store) => store.delete(`project-${projectId}`)) + database.close() +} + export async function hasProjectPermission(handle: FileSystemDirectoryHandle) { const target = handle as PersistableDirectoryHandle @@ -117,6 +166,27 @@ function openDatabase(): Promise { }) } +async function cleanupOldProjects(database: IDBDatabase): Promise { + const allRecords = await runStoreRequest( + database, + 'readonly', + (store) => store.getAll(), + ) + + // 过滤出最近项目记录 + const recentRecords = allRecords + .filter((record) => record.key !== LAST_PROJECT_KEY) + .sort((a, b) => new Date(b.lastOpenedAt).getTime() - new Date(a.lastOpenedAt).getTime()) + + // 删除超过限制的旧记录 + if (recentRecords.length > MAX_RECENT_PROJECTS) { + const recordsToDelete = recentRecords.slice(MAX_RECENT_PROJECTS) + for (const record of recordsToDelete) { + await runStoreRequest(database, 'readwrite', (store) => store.delete(record.key)) + } + } +} + function runStoreRequest( database: IDBDatabase, mode: IDBTransactionMode, diff --git a/packages/core/src/services/project-service.ts b/packages/core/src/services/project-service.ts index 8092fc9..ca9e48d 100644 --- a/packages/core/src/services/project-service.ts +++ b/packages/core/src/services/project-service.ts @@ -11,8 +11,10 @@ import { import { writeAgentLog } from '../core/logging/agent-log' import { forgetLastProject as forgetStoredLastProject, + forgetRecentProject as forgetStoredRecentProject, hasProjectPermission, readLastProject, + readRecentProjects, requestProjectPermission, saveLastProject, toLastProjectSummary, @@ -91,10 +93,18 @@ export async function getLastProjectSummary(): Promise { + return readRecentProjects() +} + export async function forgetLastProject(): Promise { await forgetStoredLastProject() } +export async function forgetRecentProject(projectId: string): Promise { + await forgetStoredRecentProject(projectId) +} + export async function closeProject(projectId: string): Promise { const project = getRuntimeProject(projectId) diff --git a/packages/core/tsconfig.tsbuildinfo b/packages/core/tsconfig.tsbuildinfo index e67990a..b7ce15d 100644 --- a/packages/core/tsconfig.tsbuildinfo +++ b/packages/core/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hmrpayload.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/customevent.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hot.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importglob.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importmeta.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/client.d.ts","./src/env.d.ts","./src/types/ai.ts","./src/types/project.ts","./src/types/rag.ts","./src/core/agent/messages.ts","./src/types/chat.ts","./src/types/elements.ts","./src/core/project/defaults.ts","./src/core/fs/project-fs.ts","./src/core/agent/prompt.ts","./src/core/ai/shared.ts","./src/core/agent/llm.ts","./src/core/tools/path.ts","./src/core/tools/types.ts","./src/core/tools/file-tools.ts","./src/core/tools/directory-tools.ts","./src/core/agent/tools.ts","./src/core/agent/tool-execution.ts","./src/core/agent/tool-orchestration.ts","./src/core/agent/query.ts","./src/core/logging/agent-log.ts","./src/core/chat/target.ts","./src/core/embedding/client.ts","./src/core/rag/index-store.ts","./src/core/rag/search.ts","./src/core/chat/tools.ts","./src/core/chat/session.ts","./src/services/project-runtime.ts","./src/services/types.ts","./src/services/agent-service.ts","./src/core/elements/extractor.ts","./src/services/element-service.ts","./src/services/mappers.ts","./src/services/file-service.ts","./src/core/llm/client.ts","./src/services/generation-service.ts","./src/core/project/recent-projects.ts","./src/services/project-service.ts","./src/core/rag/context.ts","./src/core/rag/explain.ts","./src/core/elements/parser.ts","./src/core/rag/retrieval-text.ts","./src/core/rag/indexer.ts","./src/core/ai/rerank-client.ts","./src/core/rag/rerank.ts","./src/services/rag-service.ts","./src/services/settings-service.ts","./src/index.ts","./src/core/elements/writer.ts","./src/core/tools/index.ts","./src/services/index.ts"],"fileIdsList":[[52],[48],[49],[50,51],[58,64],[56,59],[56,58,65,70,71,72],[56,58,70],[56,58,70,71],[58,67,68,69],[55,57,64],[58,59,62,63,70,73,74,75,79],[59],[57,59,67,68,78],[60],[57,60,62],[55,64],[56,61],[56],[57],[56,57,62,76,77,94,95],[56,57,97],[56,57,76,77],[66,67],[62,66,67],[67,68,69],[53],[55,56,57,59,60,81,82,83,85,87,89,91,99,100],[58,59,62,75,80,81,82],[82,84],[62,81,82,86],[82,88],[81,82,83,85,87,89,91,99,100],[56,82],[56,62,74,81,82,86,90],[78,81,82,92,93,96,98],[62,76,81,82,86,88,97],[56,57,58]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"11443a1dcfaaa404c68d53368b5b818712b95dd19f188cab1669c39bee8b84b3","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"19efad8495a7a6b064483fccd1d2b427403dd84e67819f86d1c6ee3d7abf749c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1eef826bc4a19de22155487984e345a34c9cd511dd1170edc7a447cb8231dd4a","affectsGlobalScope":true,"impliedFormat":99},{"version":"836accf738fb52244a954116f26a573a0fd1d6f81b8a11fa19312e56f5da68f2","affectsGlobalScope":true},{"version":"e528ce045403b7526cd307ab542f93a5509c060853dd17811d683e9efaf67ec2","signature":"9a8d5ee2f3e3046860461283b2702cf9d7fa8ca97e31f6aa0fb8df321ce47ff6"},{"version":"2f479776ef770db58868e2a71be2f9c0466f176847a334bbe03ed1312273bf11","signature":"0085499168f9de37efeddef62e5a2bbdcd5152b91b687087195d3f9b1a9c922b"},{"version":"eef79b77c06ce92c9489542658050507167e35611c92e270e74921d31854bfd9","signature":"05738a9eb9d1dcd4a18ca5e9bcd6eca022bc719ee95ea6083ad20db40aa750e9"},{"version":"4dab05a495b93af768191462e43e219d5401d73e69605422d39c4e1c9574058f","signature":"a728f0d0f2c5a28978e3f0cf6beca9ee5d69d746c7c4c5ede32eaace652d9bf8"},{"version":"af90afb25c9bd034c657b9e62da90e9d3dbebeb0aa5ae8ad1cc43092d2cec435","signature":"7518de7f3a9ac1c7aa26422e211c4107c3e462856b9d9f1a5af49965b0ef7ab8"},{"version":"f35f8f677f62018a708b46a76c92ced2b2210f0af3280f2724be6b4a16d0d4f6","signature":"a60dac8e4a952db827558e08792f1b356df1a33a0f860990c829be623273a5a8"},{"version":"335560cecdaff7f030a81553dfad8c49cb83ab9aa6d7054b9baa56a82f4cdb13","signature":"e3e7a5ba06faeb9f97eaaa59a7b813e3e6c4618188ec084f9fa931d5558f85a3"},{"version":"03b52c5402cb11b76e6e8399ada2581ca6c9345fd90af9ce8123a3b86ad35c12","signature":"abdee50db583d4fa094ad339e1ac12372cac0cb32c02e4a54832d0726a84371d"},{"version":"068c3f4d6f2043770be35b43a059c41c25650485ac543f175241ab299be823bf","signature":"7799d6baf9c40e7e0fe32b9dbd4c0ea783b36a23458e67873ed19802bebdab04"},{"version":"df6f111f61bd54da6565a61da34d4aa558346a6a7766dbc8bad8218d6c9d39c8","signature":"829b37289858b8526dcd1f4f5beb9d7cc653d5afe93234a74c2a617ea2c6ab90"},{"version":"8c02551cc4c36ecb3c1dc5ea994638519ff31349a053147590f34c361126e055","signature":"83e79d50d2af6da5b26cd791f3d95d651c53f44fc0c5b85462b915a0f4207f50"},{"version":"051836fff7206cd1e70d8d74c1d1fa824e4f2babd120426b10956ee551c6855c","signature":"e19c0c49aeafdd064fb0df9d05f5ee376d71e9d42bf50d77b0e15438cce3ce20"},{"version":"560aab82f8c1d210b78e397f1c4f7792909671a384741811a8933cc715f3a6a8","signature":"6479a032ab9507b84d47fb4f227f65918de8dac6a43419f730f35c9bb3a6f62a"},{"version":"21f102066e102cd4fb8a2ffac6b3a2d55998c8d1d73c1ccd7b8aae236e174a43","signature":"2f01365a8bafaf5714fe602fa1113539abaf90cca143bd18e88e731e90bb166c"},{"version":"90adb00dd46aebbd7fa3b06c096382a1c874d453c31ce698702075f23a0d607d","signature":"a0ec99b251cb15da1add9bc85b93ef0e68ec0595b875aad778264b402b70f3b4"},{"version":"489abadd34101ccbb87529b2a91c1f317d991a3790625ee244754a68a7070abc","signature":"55a9effc58d45f28f38ad87a16e5349679c2daf530c7b7a29ea85893cc7a962d"},{"version":"f490a892043cf47f819c3e28c8c0f4b7b5f397d788df94191e85161f990904e1","signature":"3596d5444d49a85e2dfdff344aa976979267112fac4025d70248aa187e5e82c8"},{"version":"3b87317e45f2640d23aef180d14bd262d3dc61d99209d286fd74c399fb231a07","signature":"a987084956688b88adbde2a9da59a4cab414f53da023a6a4a6c3b13257c4e5ae"},{"version":"88c136fafa260d8e8a6ce74bf63e966c87961c8517dd2ed36e0509c7a2211c78","signature":"fa1ed94344cdee8a6eb7764b4175d8d7692bf00ad95acc8c2f81ab9c431c34f5"},{"version":"fc0d90f36753034129651f7744aa0372877e2824c86f626eabe6d51295247df0","signature":"ca18c328753d33fcf8eb589e411d078fa8d62bc0974df3121818857a88d0dafb"},{"version":"bd1eb7d451777e985118eecde7104fd396381714e36b30cc0218ba5b21cca53e","signature":"e06d5371e747df158a0f220cec71bd421971f5a7458dae4ed6cae48f4db1e29d"},{"version":"83e77e9d1de3c2dd2bcde872800b5dd5c1a8bf69b7fa642c4f383b0f5dcb5dd3","signature":"21fd89f13902fe7572a7e78ebb735869589f4b4adc9f0297928614e880cf0eb3"},{"version":"6102d8789d2db62e349abc88075a3b4558e6e9954935a9f08fa0866ae3d261f7","signature":"18d300252daaf68f09e5796ffb578dbceffaa962ec81b3620893200c2dc17ef9"},{"version":"2bc9b6a2604582bddb35f4aacd7d1f303398130c2ee586c1440379ceafdfdd6f","signature":"a2322c9f673394a823ee2b8923df8c7705c1c134f3210c715b33b4651573e010"},{"version":"003b11010637771703f4fb639e132e54ecc986a0244c4b66f76d202896a4a31d","signature":"3d53f7262fd8b08de5133c960c5feb72254dbf76c4c66c0f83b4da490756427f"},{"version":"1f2e96f53ba742746ed140be8cac06aed1c69318a3a34141c630b3a9f792b64a","signature":"6855f5cb53c7ba56851b6d7669c2037512dc43bf48342d8614febc72ae430e0f"},{"version":"82aa160c3a8b4e738a8ec284b6f65eaa43c47fcd20ebbe77010737a96f5204d7","signature":"066971c44cc55d9a3db5aeeb31df5b8b7f05e43cd4da9178dfbc595c17dfd9bc"},{"version":"03ef5f2e31c5b6013594da548c23d309c13bf4ab608524cb3deae8d77e5ffd98","signature":"8f20963ec6f7ae8760d0b469bba9b7dae1ad429aab6ea0c3ae279e15e0572787"},{"version":"18e0eae1196599f6dbc153126f02e5de5969f804bb0f5ae01f3dad2f095abc97","signature":"87ea6c2cecc8422526ea7e585a23935ad90997be8fee9be8924458231a01b88e"},{"version":"d582df80e809ca632bbe46cf565d47926cacb18db2c5a3506bb0950b81eee981","signature":"bacdac6736d3f469a025afcc5547099eda522858a55fe287294efa24b0af55a1"},{"version":"ce254fe1c00d7edb30d58b033e3c42c728d644ce500d4c31bb6bd820b6640df9","signature":"3611aa813d1f93dc13442515cb8dbcc1a17316c8e436c7452b7bf5c0961851b9"},{"version":"37d79d5efacffdf084149f41c959127c659c2f251b7b9b728ed1524e7938ed3c","signature":"a1c00f4e736fd85beae3cd799d0c7364ef95f0caf3ae82583ffd26b5d6c9590d"},{"version":"db27970741be54435447e757c3f89dfce5c202a6d967d31ec3f093a574460984","signature":"8f8332d5643c6c13e4924ba980e59d87f80a008a8609b0c7baa690408d19c698"},{"version":"f814dcf34d3369397472acd62753af7ab6c6ca096d700fcfc2004bc38c63f161","signature":"55b944653a72facbea581777c785f35ee1a45f5619ae2b0ea2fbe49f9b2401fc"},{"version":"a8ee27972462e3957b0931778e2866f54a7d465553e44a44d219d3bb98852884","signature":"82f55cbd01275d4375acc18dafa9b72251844b638cd2b5bd7efe8d20a64833e1"},{"version":"efb186223310021405d06412b6b8ba9c938dcfc93415eba790df63b9bffb276c","signature":"04a941eea50ddaf9adaa1ba0106069678f6ff6932e307da6e280ac3b099d23c7"},{"version":"cccca21eddd2dc723d7b50873e7f17ceb331dc4a94c0c64d4baaaf603a46b511","signature":"b53609d061652d412054f8ee5b2a49af0cd35641255b677e2cd309f881facafd"},{"version":"f209f66a7c856cf3e7b71683e6806d786a350a1cce30b254c03c98b5c4c6f8d9","signature":"4897c9428d3c6e9649e256e6935ca78d947ccc1bbb9c3f22f691b4f384b46f47"},{"version":"1dfb32781c37ef52915869f78c9745d483f4256ebbaa6561c6a49db457f57d56","signature":"ab320d8de97da70f010db470f3d4c92d45afdfda927161be6097e21b69c25d38"},{"version":"b4185cf1ed3f1154927003acb25b669467805d99311d7e877a2839b69dbb9418","signature":"8a8630ce7e419e36d314b48a263e9c1f0f74e9c6510d27a719022354bd3ad963"},{"version":"bce19be35e3bfa9ed6408035a01bb36241ffd4b8032b4db76e0cfb723f90132b","signature":"146e3fce375357e62689a22c5de28c6435004d1299b6445d20ee2fb10afc2e5b"},{"version":"e585bf55958dbd0beb2f7797bcaffa99ea25881db8f9e774ab6e7962ee3ea680","signature":"ca7a33a6153cffd7a35dfa4b2a672805d0e0229dcddd81481f6db77ca2aaa598"},{"version":"5dce93b23af5adc5f6d0ed34b73a6be98e0558adc610b0292296dfad28bc9bcf","signature":"cde17fa0e72858a52bad88c02bdec864ed11ea431a35d12c994d0d54b5b68280"},{"version":"697d4d5e35eec79646f6d2001f60f16e842a76b31f79ca26315346bed40ff77e","signature":"ca1678645d0ceedc505ef4eaa0d346d1231464e80a617d9a230b24e9af79e705"},{"version":"860e52bdda09e3dc1c7df3918672713efb5fdd61e9740eeefef0578a4ef22088","signature":"05da64738e1628634ee52939320168d44b8a06a9c86dcab0fd52f5d0a448161b"},{"version":"8fcfee97594852ebc347dc767c243417a07ae6453e89b61af831f6b0a9710190","signature":"3e3e10f3ebf23bfec47d0d2d6db0b7bdcbbd889d71d701455e32fc6a760bac57"},{"version":"eb937969ab54e95609fe6104b3bd580b3df464f888b7d6d1aea10685326f81b1","signature":"d8d51f4bdd3130bafd993a6052504c42024f60a88bd04f8c291e6e593ded62a9"},{"version":"b9ffdf1712c38b6b15611455bd9dc4cbbbb1b494a1338bf9ca3546fb8a6edfe9","signature":"34b3e2f7a2f91881906b483c2ba0b73122989f27d406ac9c7cda17dac154f806"},{"version":"ed7424b0c077a33321f012c3976ba03849768cfd891f03b5653ff62fd2bc432b","signature":"a08e470198212fd1fa57599abdc3caafa6e80968066a4157a203f207d802b755"},{"version":"e0d7ee9b96393f7195dda7d6b0974459fe7ce8c90c3de650420718dd71f8348c","signature":"7566157980837bf91b3b98739ffada01b82891770c00bdd7d697ec85bf40d16a"}],"root":[[54,104]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":99,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"target":7},"referencedMap":[[53,1],[49,2],[50,3],[52,4],[65,5],[63,6],[73,7],[71,8],[72,9],[70,10],[97,11],[80,12],[75,13],[79,14],[84,15],[94,15],[102,16],[76,17],[62,18],[88,17],[74,19],[92,20],[93,20],[77,20],[96,21],[98,22],[95,15],[78,23],[69,24],[68,25],[103,26],[67,19],[54,27],[101,28],[83,29],[85,30],[87,31],[89,32],[104,33],[86,34],[81,19],[91,35],[99,36],[100,37],[59,38],[60,20]],"latestChangedDtsFile":"./dist/core/fs/project-fs.d.ts","version":"6.0.3"} \ No newline at end of file +{"fileNames":["../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hmrpayload.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/customevent.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/hot.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importglob.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/types/importmeta.d.ts","../../node_modules/.pnpm/vite@6.4.2_@types+node@25.9.1_jiti@2.7.0_lightningcss@1.32.0_sass@1.99.0_yaml@2.9.0/node_modules/vite/client.d.ts","./src/env.d.ts","./src/types/ai.ts","./src/types/project.ts","./src/types/rag.ts","./src/core/agent/messages.ts","./src/types/chat.ts","./src/types/elements.ts","./src/core/project/defaults.ts","./src/core/fs/project-fs.ts","./src/core/agent/prompt.ts","./src/core/ai/shared.ts","./src/core/agent/llm.ts","./src/core/tools/path.ts","./src/core/tools/types.ts","./src/core/tools/file-tools/common.ts","./src/core/tools/file-tools/create-file.ts","./src/core/tools/file-tools/delete-file.ts","./src/core/tools/file-tools/read-file-state.ts","./src/core/tools/file-tools/text-replace.ts","./src/core/tools/file-tools/edit-file.ts","./src/core/tools/file-tools/read-file.ts","./src/core/tools/file-tools/rename-file.ts","./src/core/tools/file-tools/index.ts","./src/core/tools/directory-tools.ts","./src/core/agent/tools.ts","./src/core/agent/tool-execution.ts","./src/core/agent/tool-orchestration.ts","./src/core/agent/query.ts","./src/core/logging/agent-log.ts","./src/core/chat/target.ts","./src/core/embedding/client.ts","./src/core/rag/index-store.ts","./src/core/rag/search.ts","./src/core/chat/tools.ts","./src/core/chat/session.ts","./src/services/project-runtime.ts","./src/services/types.ts","./src/services/agent-service.ts","./src/core/elements/extractor.ts","./src/services/element-service.ts","./src/services/mappers.ts","./src/services/file-service.ts","./src/core/llm/client.ts","./src/services/generation-service.ts","./src/core/project/recent-projects.ts","./src/services/project-service.ts","./src/core/rag/context.ts","./src/core/rag/explain.ts","./src/core/elements/parser.ts","./src/core/rag/retrieval-text.ts","./src/core/rag/indexer.ts","./src/core/ai/rerank-client.ts","./src/core/rag/rerank.ts","./src/services/rag-service.ts","./src/services/settings-service.ts","./src/index.ts","./src/core/elements/writer.ts","./src/core/tools/index.ts","./src/services/index.ts"],"fileIdsList":[[52],[48],[49],[50,51],[58,64],[56,59],[56,58,65,67,78,79,80],[56,58,67,78],[56,58,67,78,79],[58,67,76,77],[55,57,64],[58,59,62,63,78,81,82,83,87],[59],[57,59,67,76,86],[60],[57,60,62],[55,64],[56,61],[56],[57],[56,57,62,84,85,102,103],[56,57,105],[56,57,84,85],[66,67],[66],[62,66,67,68],[62,66,67,68,71,72],[69,70,73,74,75],[66,67,68],[62,66,67,68,71],[67,76,77],[53],[55,56,57,59,60,89,90,91,93,95,97,99,107,108],[58,59,62,83,88,89,90],[90,92],[62,89,90,94],[90,96],[89,90,91,93,95,97,99,107,108],[56,90],[56,62,82,89,90,94,98],[86,89,90,100,101,104,106],[62,84,89,90,94,96,105],[56,57,58]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"11443a1dcfaaa404c68d53368b5b818712b95dd19f188cab1669c39bee8b84b3","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"19efad8495a7a6b064483fccd1d2b427403dd84e67819f86d1c6ee3d7abf749c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1eef826bc4a19de22155487984e345a34c9cd511dd1170edc7a447cb8231dd4a","affectsGlobalScope":true,"impliedFormat":99},{"version":"836accf738fb52244a954116f26a573a0fd1d6f81b8a11fa19312e56f5da68f2","affectsGlobalScope":true},{"version":"e528ce045403b7526cd307ab542f93a5509c060853dd17811d683e9efaf67ec2","signature":"9a8d5ee2f3e3046860461283b2702cf9d7fa8ca97e31f6aa0fb8df321ce47ff6"},{"version":"2f479776ef770db58868e2a71be2f9c0466f176847a334bbe03ed1312273bf11","signature":"0085499168f9de37efeddef62e5a2bbdcd5152b91b687087195d3f9b1a9c922b"},{"version":"eef79b77c06ce92c9489542658050507167e35611c92e270e74921d31854bfd9","signature":"05738a9eb9d1dcd4a18ca5e9bcd6eca022bc719ee95ea6083ad20db40aa750e9"},{"version":"4dab05a495b93af768191462e43e219d5401d73e69605422d39c4e1c9574058f","signature":"a728f0d0f2c5a28978e3f0cf6beca9ee5d69d746c7c4c5ede32eaace652d9bf8"},{"version":"af90afb25c9bd034c657b9e62da90e9d3dbebeb0aa5ae8ad1cc43092d2cec435","signature":"7518de7f3a9ac1c7aa26422e211c4107c3e462856b9d9f1a5af49965b0ef7ab8"},{"version":"f35f8f677f62018a708b46a76c92ced2b2210f0af3280f2724be6b4a16d0d4f6","signature":"a60dac8e4a952db827558e08792f1b356df1a33a0f860990c829be623273a5a8"},{"version":"335560cecdaff7f030a81553dfad8c49cb83ab9aa6d7054b9baa56a82f4cdb13","signature":"e3e7a5ba06faeb9f97eaaa59a7b813e3e6c4618188ec084f9fa931d5558f85a3"},{"version":"03b52c5402cb11b76e6e8399ada2581ca6c9345fd90af9ce8123a3b86ad35c12","signature":"abdee50db583d4fa094ad339e1ac12372cac0cb32c02e4a54832d0726a84371d"},{"version":"068c3f4d6f2043770be35b43a059c41c25650485ac543f175241ab299be823bf","signature":"7799d6baf9c40e7e0fe32b9dbd4c0ea783b36a23458e67873ed19802bebdab04"},{"version":"df6f111f61bd54da6565a61da34d4aa558346a6a7766dbc8bad8218d6c9d39c8","signature":"829b37289858b8526dcd1f4f5beb9d7cc653d5afe93234a74c2a617ea2c6ab90"},{"version":"8c02551cc4c36ecb3c1dc5ea994638519ff31349a053147590f34c361126e055","signature":"83e79d50d2af6da5b26cd791f3d95d651c53f44fc0c5b85462b915a0f4207f50"},{"version":"051836fff7206cd1e70d8d74c1d1fa824e4f2babd120426b10956ee551c6855c","signature":"e19c0c49aeafdd064fb0df9d05f5ee376d71e9d42bf50d77b0e15438cce3ce20"},{"version":"e58d4878793d9a26505be1dc874116616756dbbd97664b035baeeb5230a0710a","signature":"b74ed3188cf7100a26479e12a1110924e4047eda59ff4f89b74d8c7ff8b5cc08"},{"version":"d699b4a7b9f17c46b655961874fa2f166d0e52f52f7c31e31d2eb0a1a82b24ee","signature":"bbf160c6c77a8c61198f5fe7323abf0b5f83fb9e0ce3ea8a5e34aa4b2ceed21c"},{"version":"2289ceaed03f816dc2ac926ecad833d5e3b6911f40ad159e67172cef13aeffe1","signature":"17f921a91fb4df810326915ec8000bc2d4804da0726a56704bc9937e570d4197"},{"version":"4b8a28b62e39232685bf188a276b06b8ad3609ef36a78e01c0ace4f01f41510a","signature":"4256645998ce237dcd822b1623796956349028ea590b3325a370c0b0a5981d39"},{"version":"a5ffd93aadddbe1e64f1620b8020056b52610f62e696349b780683a19f79de46","signature":"152e641b22f73a353114aebf5c2fa58772c09020279cb7d0839a11df20e78254"},{"version":"ed54addf33d94f3317ab1759cbe7c114a318e4c8b45b193eacfc1071826bf7d1","signature":"7dec088d4a9f8b852631e13a4ae8e73bc549288baf9148ffb9bdbb4a801b4021"},{"version":"8e20549a10018f15d46dc054e08540d68f3f87c374cbee065e88e9a24bd05be0","signature":"249b979a6fc1b883fa259ac29a356b0824fb034494e600aee8bb158aa5f6da20"},{"version":"be55ad422c5e7956930e941f2dbfa9af2d1ea17e92b471fd4c308c32928b2449","signature":"2647caa7b354cf39476dff18fe73f998e6cf515bda9a9e79da24788d96714f9c"},{"version":"bfcafcd8d6b4ca1378f6cfc9b35d3553be5007c8b6e2018d380d7dbb3de21219","signature":"18f6e4c69b46dd7ad6d445f1b2bd8485519ee2ddc3bbd483632a9e7674f043b0"},{"version":"d6265f034bb16d779b28457a4839d1f1a1b8b6cdcfcb01823a6650a91f35a688","signature":"12300e3e0852b2123c5dcdbe31bb7a611bf91d98ea630b5520c73e992e4cd80d"},{"version":"90adb00dd46aebbd7fa3b06c096382a1c874d453c31ce698702075f23a0d607d","signature":"a0ec99b251cb15da1add9bc85b93ef0e68ec0595b875aad778264b402b70f3b4"},{"version":"489abadd34101ccbb87529b2a91c1f317d991a3790625ee244754a68a7070abc","signature":"55a9effc58d45f28f38ad87a16e5349679c2daf530c7b7a29ea85893cc7a962d"},{"version":"a83b212c5740b4a5dda5f3c57218d533a58bc26c96184e10d7cfcd99eb34ffd8","signature":"cdb4c016d3cbbf881fbe40413cbce41ae6d8fbf4f8ac3461376f02d08de4343f"},{"version":"23fc47fbcb113654db15bdcf500dab1df682adfcb7d700213e31fa008dd5a312","signature":"c71207bd346307bda35cde8d7c8ac0fe0d4674232690be5c4884ed13c22fab99"},{"version":"17caf502a4327eb070cd61978489b5cd477500330a0512ed4768db0248f526da","signature":"fa1ed94344cdee8a6eb7764b4175d8d7692bf00ad95acc8c2f81ab9c431c34f5"},{"version":"fc0d90f36753034129651f7744aa0372877e2824c86f626eabe6d51295247df0","signature":"ca18c328753d33fcf8eb589e411d078fa8d62bc0974df3121818857a88d0dafb"},{"version":"bd1eb7d451777e985118eecde7104fd396381714e36b30cc0218ba5b21cca53e","signature":"e06d5371e747df158a0f220cec71bd421971f5a7458dae4ed6cae48f4db1e29d"},{"version":"83e77e9d1de3c2dd2bcde872800b5dd5c1a8bf69b7fa642c4f383b0f5dcb5dd3","signature":"21fd89f13902fe7572a7e78ebb735869589f4b4adc9f0297928614e880cf0eb3"},{"version":"6102d8789d2db62e349abc88075a3b4558e6e9954935a9f08fa0866ae3d261f7","signature":"18d300252daaf68f09e5796ffb578dbceffaa962ec81b3620893200c2dc17ef9"},{"version":"2bc9b6a2604582bddb35f4aacd7d1f303398130c2ee586c1440379ceafdfdd6f","signature":"a2322c9f673394a823ee2b8923df8c7705c1c134f3210c715b33b4651573e010"},{"version":"003b11010637771703f4fb639e132e54ecc986a0244c4b66f76d202896a4a31d","signature":"3d53f7262fd8b08de5133c960c5feb72254dbf76c4c66c0f83b4da490756427f"},{"version":"1f2e96f53ba742746ed140be8cac06aed1c69318a3a34141c630b3a9f792b64a","signature":"6855f5cb53c7ba56851b6d7669c2037512dc43bf48342d8614febc72ae430e0f"},{"version":"82aa160c3a8b4e738a8ec284b6f65eaa43c47fcd20ebbe77010737a96f5204d7","signature":"066971c44cc55d9a3db5aeeb31df5b8b7f05e43cd4da9178dfbc595c17dfd9bc"},{"version":"03ef5f2e31c5b6013594da548c23d309c13bf4ab608524cb3deae8d77e5ffd98","signature":"8f20963ec6f7ae8760d0b469bba9b7dae1ad429aab6ea0c3ae279e15e0572787"},{"version":"18e0eae1196599f6dbc153126f02e5de5969f804bb0f5ae01f3dad2f095abc97","signature":"87ea6c2cecc8422526ea7e585a23935ad90997be8fee9be8924458231a01b88e"},{"version":"d582df80e809ca632bbe46cf565d47926cacb18db2c5a3506bb0950b81eee981","signature":"bacdac6736d3f469a025afcc5547099eda522858a55fe287294efa24b0af55a1"},{"version":"ce254fe1c00d7edb30d58b033e3c42c728d644ce500d4c31bb6bd820b6640df9","signature":"3611aa813d1f93dc13442515cb8dbcc1a17316c8e436c7452b7bf5c0961851b9"},{"version":"37d79d5efacffdf084149f41c959127c659c2f251b7b9b728ed1524e7938ed3c","signature":"a1c00f4e736fd85beae3cd799d0c7364ef95f0caf3ae82583ffd26b5d6c9590d"},{"version":"db27970741be54435447e757c3f89dfce5c202a6d967d31ec3f093a574460984","signature":"8f8332d5643c6c13e4924ba980e59d87f80a008a8609b0c7baa690408d19c698"},{"version":"f814dcf34d3369397472acd62753af7ab6c6ca096d700fcfc2004bc38c63f161","signature":"55b944653a72facbea581777c785f35ee1a45f5619ae2b0ea2fbe49f9b2401fc"},{"version":"a8ee27972462e3957b0931778e2866f54a7d465553e44a44d219d3bb98852884","signature":"82f55cbd01275d4375acc18dafa9b72251844b638cd2b5bd7efe8d20a64833e1"},{"version":"9b512b1acf81dae53a7e5080ced5d8c26df6cd19e3a228a97a2db16726a14c35","signature":"3715397488ae73c0236c02916262276985e21966fd7ed62c12a5f9364c7f954d"},{"version":"87c09df249f4496b68189f2e4ebda8682c2bd107de1774aa748a43b859122355","signature":"076a04f22f43c90975397208426922b5c03b89c3fe36d2c936446645f09b195b"},{"version":"f209f66a7c856cf3e7b71683e6806d786a350a1cce30b254c03c98b5c4c6f8d9","signature":"4897c9428d3c6e9649e256e6935ca78d947ccc1bbb9c3f22f691b4f384b46f47"},{"version":"1dfb32781c37ef52915869f78c9745d483f4256ebbaa6561c6a49db457f57d56","signature":"ab320d8de97da70f010db470f3d4c92d45afdfda927161be6097e21b69c25d38"},{"version":"b4185cf1ed3f1154927003acb25b669467805d99311d7e877a2839b69dbb9418","signature":"8a8630ce7e419e36d314b48a263e9c1f0f74e9c6510d27a719022354bd3ad963"},{"version":"bce19be35e3bfa9ed6408035a01bb36241ffd4b8032b4db76e0cfb723f90132b","signature":"146e3fce375357e62689a22c5de28c6435004d1299b6445d20ee2fb10afc2e5b"},{"version":"e585bf55958dbd0beb2f7797bcaffa99ea25881db8f9e774ab6e7962ee3ea680","signature":"ca7a33a6153cffd7a35dfa4b2a672805d0e0229dcddd81481f6db77ca2aaa598"},{"version":"5dce93b23af5adc5f6d0ed34b73a6be98e0558adc610b0292296dfad28bc9bcf","signature":"cde17fa0e72858a52bad88c02bdec864ed11ea431a35d12c994d0d54b5b68280"},{"version":"697d4d5e35eec79646f6d2001f60f16e842a76b31f79ca26315346bed40ff77e","signature":"ca1678645d0ceedc505ef4eaa0d346d1231464e80a617d9a230b24e9af79e705"},{"version":"860e52bdda09e3dc1c7df3918672713efb5fdd61e9740eeefef0578a4ef22088","signature":"05da64738e1628634ee52939320168d44b8a06a9c86dcab0fd52f5d0a448161b"},{"version":"8fcfee97594852ebc347dc767c243417a07ae6453e89b61af831f6b0a9710190","signature":"3e3e10f3ebf23bfec47d0d2d6db0b7bdcbbd889d71d701455e32fc6a760bac57"},{"version":"eb937969ab54e95609fe6104b3bd580b3df464f888b7d6d1aea10685326f81b1","signature":"d8d51f4bdd3130bafd993a6052504c42024f60a88bd04f8c291e6e593ded62a9"},{"version":"b9ffdf1712c38b6b15611455bd9dc4cbbbb1b494a1338bf9ca3546fb8a6edfe9","signature":"34b3e2f7a2f91881906b483c2ba0b73122989f27d406ac9c7cda17dac154f806"},{"version":"c31c4e0d303dc1a4786e929d89d92a357e758ce2886482668a1cea91fa2896ba","signature":"8811f7d1a528a55d276339d7a45207424376c146a7d03662544e4f2e575611fb"},{"version":"e0d7ee9b96393f7195dda7d6b0974459fe7ce8c90c3de650420718dd71f8348c","signature":"7566157980837bf91b3b98739ffada01b82891770c00bdd7d697ec85bf40d16a"}],"root":[[54,112]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":99,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"target":7},"referencedMap":[[53,1],[49,2],[50,3],[52,4],[65,5],[63,6],[81,7],[79,8],[80,9],[78,10],[105,11],[88,12],[83,13],[87,14],[92,15],[102,15],[110,16],[84,17],[62,18],[96,17],[82,19],[100,20],[101,20],[85,20],[104,21],[106,22],[103,15],[86,23],[77,24],[68,25],[69,26],[70,26],[73,27],[76,28],[71,29],[74,30],[75,26],[111,31],[67,19],[54,32],[109,33],[91,34],[93,35],[95,36],[97,37],[112,38],[94,39],[89,19],[99,40],[107,41],[108,42],[59,43],[60,20]],"latestChangedDtsFile":"./dist/types/rag.d.ts","version":"6.0.3"} \ No newline at end of file From cf1594475dfc342294a3499f8c83ad806dbacb8d Mon Sep 17 00:00:00 2001 From: honlnk Date: Mon, 1 Jun 2026 02:04:23 +0800 Subject: [PATCH 07/16] =?UTF-8?q?feat(ui):=20=E5=AE=9E=E7=8E=B0=E5=B7=A6?= =?UTF-8?q?=E4=BE=A7=E6=96=87=E4=BB=B6=E6=A0=91=E5=92=8C=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 TreeNode.vue 递归组件,支持任意层级的文件树 - 实现文件夹展开/折叠功能 - 实现文件点击选择,高亮当前选中文件 - 不同文件类型显示不同图标(md/json/通用文件) - 更新 FileTreeSidebar,使用真实项目文件树数据 - 更新 ContentPanel,显示选中文件的内容 - 更新 ProjectView,处理文件选择和右侧面板联动 --- .../app/src/components/file-tree/TreeNode.vue | 132 ++++++++++++++++++ .../src/components/layout/ContentPanel.vue | 16 ++- .../src/components/layout/FileTreeSidebar.vue | 85 +++-------- packages/app/src/views/ProjectView.vue | 13 ++ packages/app/tsconfig.tsbuildinfo | 2 +- 5 files changed, 177 insertions(+), 71 deletions(-) create mode 100644 packages/app/src/components/file-tree/TreeNode.vue diff --git a/packages/app/src/components/file-tree/TreeNode.vue b/packages/app/src/components/file-tree/TreeNode.vue new file mode 100644 index 0000000..7de3f99 --- /dev/null +++ b/packages/app/src/components/file-tree/TreeNode.vue @@ -0,0 +1,132 @@ + + + diff --git a/packages/app/src/components/layout/ContentPanel.vue b/packages/app/src/components/layout/ContentPanel.vue index b2fb45b..d74d49c 100644 --- a/packages/app/src/components/layout/ContentPanel.vue +++ b/packages/app/src/components/layout/ContentPanel.vue @@ -1,6 +1,9 @@