Fixes for build

This commit is contained in:
dimitrievgs 2025-11-25 23:07:38 +03:00
parent f61cf08efd
commit cb8ed95bcd
14 changed files with 1824 additions and 47996 deletions

View File

@ -3,6 +3,7 @@ import process from 'process'
import builtins from 'builtin-modules' import builtins from 'builtin-modules'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { ObfuscatorPlugin } from 'esbuild-plugin-obfuscator' // Импорт плагина
const banner = `/* const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
@ -10,63 +11,99 @@ if you want to view the source, please visit the github repository of this plugi
*/ */
` `
const prod = process.argv[2] === 'production' const arg = process.argv[2] || ''
const prod = arg === 'production'
const obfuscate = arg === 'dev-obfuscate'
const outputFolder = '../llm-agent-plugin-build';
console.log(arg)
console.log(obfuscate)
const renameCssPlugin = () => ({ const renameCssPlugin = () => ({
name: 'rename-css', name: 'rename-css',
setup (build) { setup (build) {
build.onEnd(() => { build.onEnd(() => {
const outDir = path.dirname(build.initialOptions.outfile || 'main.js') const outDir = path.dirname(build.initialOptions.outfile || 'main.js')
const mainCss = path.join(outDir, 'main.css') const mainCss = path.join(outDir, 'main.css')
const stylesCss = path.join(outDir, 'styles.css') const stylesCss = path.join(outDir, 'styles.css')
if (fs.existsSync(mainCss)) { if (fs.existsSync(mainCss)) {
fs.renameSync(mainCss, stylesCss) fs.renameSync(mainCss, stylesCss)
console.log(`Renamed ${mainCss} to ${stylesCss}`) console.log(`Renamed ${mainCss} to ${stylesCss}`)
} }
}) })
} }
}) })
const copyManifestPlugin = () => ({
name: 'copy-manifest',
setup(build) {
build.onEnd(() => {
const outDir = path.dirname(build.initialOptions.outfile || 'main.js'); // Целевая директория сборки
const manifestSourcePath = path.join(process.cwd(), 'src', 'json', 'manifest.json'); // Исходный путь к manifest.json
const manifestDestPath = path.join(outDir, 'manifest.json'); // Целевой путь в папке сборки
if (fs.existsSync(manifestSourcePath)) {
fs.copyFileSync(manifestSourcePath, manifestDestPath);
console.log(`Copied manifest.json from ${manifestSourcePath} to ${manifestDestPath}`);
} else {
console.warn(`Warning: manifest.json not found at ${manifestSourcePath}, skipping copy.`);
}
});
},
});
const context = await esbuild.context({ const context = await esbuild.context({
banner: { banner: {
js: banner js: banner
}, },
entryPoints: ['main.ts'], entryPoints: ['main.ts'],
bundle: true, bundle: true,
external: [ external: [
'obsidian', 'obsidian',
'electron', 'electron',
'@codemirror/autocomplete', '@codemirror/autocomplete',
'@codemirror/collab', '@codemirror/collab',
'@codemirror/commands', '@codemirror/commands',
'@codemirror/language', '@codemirror/language',
'@codemirror/lint', '@codemirror/lint',
'@codemirror/search', '@codemirror/search',
'@codemirror/state', '@codemirror/state',
'@codemirror/view', '@codemirror/view',
'@lezer/common', '@lezer/common',
'@lezer/highlight', '@lezer/highlight',
'@lezer/lr', '@lezer/lr',
...builtins ...builtins
], ],
format: 'cjs', format: 'cjs',
target: 'es2019', // Обновляем таргет до es2019 target: 'es2019',
logLevel: 'info', logLevel: 'info',
sourcemap: prod ? false : 'inline', sourcemap: prod ? false : 'inline',
treeShaking: true, treeShaking: true,
outfile: 'main.js', outfile: path.join(outputFolder, 'main.js'),
minify: prod, minify: prod,
// ДОБАВЛЕНО: Загрузчик для CSS файлов loader: {
loader: { '.css': 'css'
'.css': 'css' },
}, plugins: [
plugins: [renameCssPlugin()] renameCssPlugin(),
copyManifestPlugin(),
...(prod || obfuscate ? [ObfuscatorPlugin({
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
debugProtection: true,
debugProtectionInterval: true,
disableConsoleOutput: true,
// Можно добавить filter, чтобы обфусцировать только нужные файлы, например ['**/*.js']
})] : [])
]
}) })
if (prod) { if (prod) {
await context.rebuild() await context.rebuild()
process.exit(0) process.exit(0)
} else { } else {
await context.watch() await context.watch()
} }

46304
main.js

File diff suppressed because one or more lines are too long

View File

@ -22,11 +22,11 @@ interface LLMAgentSettings {
const DEFAULT_SETTINGS: LLMAgentSettings = { const DEFAULT_SETTINGS: LLMAgentSettings = {
apiBaseUrl: 'http://localhost:5000/api', apiBaseUrl: 'http://localhost:5000/api',
systemPrompt: 'Ты полезный ИИ ассистент.', systemPrompt: 'Ты полезный ИИ ассистент.',
defaultModel: 'gemini-2.5-flash', defaultModel: 'gemini-2.5-flash-r',
promptsFolder: 'prompts', // Папка с промптами по умолчанию promptsFolder: 'prompts', // Папка с промптами по умолчанию
enableFileReferences: true, enableFileReferences: true,
enablePromptReferences: true, enablePromptReferences: true,
excludedFolders: ['templates'], // Папка "templates" по умолчанию исключена excludedFolders: ['.obsidian', 'llm-agent-backend', 'templates', 'ref-cache'], // Папка "templates" по умолчанию исключена
refCacheFolder: 'ref-cache' // По умолчанию относительно vault refCacheFolder: 'ref-cache' // По умолчанию относительно vault
}; };

1523
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,10 @@
"description": "This is a sample plugin for Obsidian (https://obsidian.md)", "description": "This is a sample plugin for Obsidian (https://obsidian.md)",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
"dev": "node esbuild.config.mjs && move main.css styles.css", "dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production && move main.css styles.css", "devo": "node esbuild.config.mjs dev-obfuscate",
"version": "node version-bump.mjs && git add manifest.json versions.json" "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
@ -21,6 +22,7 @@
"builtin-modules": "3.3.0", "builtin-modules": "3.3.0",
"dagre": "^0.8.5", "dagre": "^0.8.5",
"esbuild": "0.17.3", "esbuild": "0.17.3",
"esbuild-plugin-obfuscator": "^1.1.0",
"obsidian": "latest", "obsidian": "latest",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",

View File

@ -12,7 +12,7 @@ import { ReferenceParser, FileReference, ReferenceMatch } from '../references/Re
import { ReferenceBox } from '../references/ReferenceBox'; import { ReferenceBox } from '../references/ReferenceBox';
import { AutocompleteItem } from '../references/AutocompleteManager'; import { AutocompleteItem } from '../references/AutocompleteManager';
import LLMAgentPlugin from 'main'; import LLMAgentPlugin from 'main';
import { MarkdownRenderer, setIcon, Notice, TFile } from 'obsidian'; import { MarkdownRenderer, setIcon, Notice, TFile, FileSystemAdapter } from 'obsidian';
import { Dialog } from 'src/utils/Dialog'; import { Dialog } from 'src/utils/Dialog';
import { CacheManager } from 'src/references/CacheManager'; import { CacheManager } from 'src/references/CacheManager';
@ -307,13 +307,21 @@ export class ChatPanel {
if (cacheExists) { if (cacheExists) {
// Открываем кешированный файл // Открываем кешированный файл
const cacheFolderPath = this.props.plugin.settings.refCacheFolder; const cacheFolderPath = this.props.plugin.settings.refCacheFolder;
pathToOpen = this.props.plugin.app.vault.adapter.getBasePath() + '/' + cacheFolderPath + '/' + attachment.cachedPath; if (!(this.props.plugin.app.vault.adapter instanceof FileSystemAdapter)) {
new Notice('Открытие кешированных файлов доступно только в desktop-версии', 3000);
return;
}
pathToOpen = (this.props.plugin.app.vault.adapter as FileSystemAdapter).getBasePath() + '/' + cacheFolderPath + '/' + attachment.cachedPath;
} else { } else {
// Кеш не найден, открываем исходный файл // Кеш не найден, открываем исходный файл
if (attachment.type === 'external') { if (attachment.type === 'external') {
pathToOpen = attachment.sourcePath; // Уже абсолютный pathToOpen = attachment.sourcePath; // Уже абсолютный
} else if (attachment.type === 'file') { } else if (attachment.type === 'file') {
pathToOpen = this.props.plugin.app.vault.adapter.getBasePath() + '/' + attachment.sourcePath; if (!(this.props.plugin.app.vault.adapter instanceof FileSystemAdapter)) {
new Notice('Открытие файлов промптов доступно только в desktop-версии', 3000);
return;
}
pathToOpen = (this.props.plugin.app.vault.adapter as FileSystemAdapter).getBasePath() + '/' + attachment.sourcePath;
} else { } else {
pathToOpen = this.props.plugin.settings.promptsFolder + '/' + attachment.sourcePath; pathToOpen = this.props.plugin.settings.promptsFolder + '/' + attachment.sourcePath;
} }

View File

@ -57,7 +57,7 @@ interface BaseNodeWrapperData {
interface BaseNodeWrapperProps { interface BaseNodeWrapperProps {
data: BaseNodeWrapperData; data: BaseNodeWrapperData;
isConnectable: boolean; isConnectable: boolean;
// children: React.ReactNode; // Содержимое, специфичное для типа узла (например, метка) children?: React.ReactNode; // Содержимое, специфичное для типа узла (например, метка)
} }
/** /**

View File

@ -11,7 +11,7 @@ import LLMAgentPlugin from 'main';
export interface AutocompleteItem { export interface AutocompleteItem {
name: string; name: string;
path: string; path: string;
type: 'file' | 'prompt'; type: 'file' | 'prompt' | 'external';
icon: string; // Obsidian icon name icon: string; // Obsidian icon name
file?: TFile; // Ссылка на файл Obsidian file?: TFile; // Ссылка на файл Obsidian
} }

View File

@ -3,186 +3,187 @@
* Сохраняет файлы в указанной папке с UUID в имени. * Сохраняет файлы в указанной папке с UUID в имени.
*/ */
import { TFile, normalizePath } from 'obsidian'; import { TFile, normalizePath, FileSystemAdapter } from 'obsidian';
import LLMAgentPlugin from 'main'; import LLMAgentPlugin from 'main';
import { v4 as uuidv4 } from 'uuid'; // Нужно установить: npm install uuid @types/uuid import { v4 as uuidv4 } from 'uuid'; // Нужно установить: npm install uuid @types/uuid
import { getMimeType } from 'src/utils/fileUtils'; import { getMimeType } from 'src/utils/fileUtils';
export class CacheManager { export class CacheManager {
private plugin: LLMAgentPlugin; private plugin: LLMAgentPlugin;
constructor(plugin: LLMAgentPlugin) { constructor(plugin: LLMAgentPlugin) {
this.plugin = plugin; this.plugin = plugin;
} }
/** /**
* Возвращает абсолютный путь к папке кеша * Возвращает абсолютный путь к папке кеша
*/ */
public getCacheFolderPath(): string { public getCacheFolderPath(): string {
const cacheFolder = this.plugin.settings.refCacheFolder; const cacheFolder = this.plugin.settings.refCacheFolder;
// Если путь относительный, делаем его относительно vault // Если путь относительный, делаем его относительно vault
if (!this.isAbsolutePath(cacheFolder)) { if (!this.isAbsolutePath(cacheFolder)) {
return this.plugin.app.vault.adapter.getBasePath() + '/' + cacheFolder; if (!(this.plugin.app.vault.adapter instanceof FileSystemAdapter)) {
} throw new Error('Can only resolve relative cache paths with FileSystemAdapter (desktop environment).');
}
return cacheFolder; return (this.plugin.app.vault.adapter as FileSystemAdapter).getBasePath() + '/' + cacheFolder;
} }
/** return cacheFolder;
* Проверяет, является ли путь абсолютным }
*/
private isAbsolutePath(path: string): boolean { /**
// Windows: C:\, D:\, и т.д. * Проверяет, является ли путь абсолютным
if (/^[a-zA-Z]:\\/.test(path)) return true; */
// Unix: / private isAbsolutePath(path: string): boolean {
if (path.startsWith('/')) return true; // Windows: C:\, D:\, и т.д.
return false; if (/^[a-zA-Z]:\\/.test(path)) return true;
} // Unix: /
if (path.startsWith('/')) return true;
/** return false;
* Создает папку кеша, если она не существует }
*/
private async ensureCacheFolderExists(): Promise<void> { /**
const cachePath = this.getCacheFolderPath(); * Создает папку кеша, если она не существует
*/
if (!window.require) return; // Web версия private async ensureCacheFolderExists(): Promise<void> {
const cachePath = this.getCacheFolderPath();
const fs = window.require('fs').promises;
if (!window.require) return; // Web версия
try {
await fs.access(cachePath); const fs = window.require('fs').promises;
} catch {
await fs.mkdir(cachePath, { recursive: true }); try {
} await fs.access(cachePath);
} } catch {
await fs.mkdir(cachePath, { recursive: true });
/** }
* Кеширует файл из vault }
*/
async cacheVaultFile(file: TFile): Promise<{ uuid: string; cachedPath: string }> { /**
await this.ensureCacheFolderExists(); * Кеширует файл из vault
*/
const uuid = uuidv4(); async cacheVaultFile(file: TFile): Promise<{ uuid: string; cachedPath: string }> {
const extension = file.extension; await this.ensureCacheFolderExists();
const cachedFileName = `${file.basename}-${uuid}.${extension}`;
const uuid = uuidv4();
const content = await this.plugin.app.vault.readBinary(file); const extension = file.extension;
const cachedFileName = `${file.basename}-${uuid}.${extension}`;
const cacheFolderPath = this.getCacheFolderPath();
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`; const content = await this.plugin.app.vault.readBinary(file);
if (!window.require) { const cacheFolderPath = this.getCacheFolderPath();
throw new Error('Кеширование доступно только в desktop версии'); const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
}
if (!window.require) {
const fs = window.require('fs').promises; throw new Error('Кеширование доступно только в desktop версии');
await fs.writeFile(cachedFilePath, Buffer.from(content)); }
return { const fs = window.require('fs').promises;
uuid: uuid, await fs.writeFile(cachedFilePath, Buffer.from(content));
cachedPath: cachedFileName // Относительный путь
}; return {
} uuid: uuid,
cachedPath: cachedFileName // Относительный путь
/** };
* Кеширует внешний файл }
*/
async cacheExternalFile(absolutePath: string): Promise<{ uuid: string; cachedPath: string; name: string; mimeType: string }> { /**
await this.ensureCacheFolderExists(); * Кеширует внешний файл
*/
if (!window.require) { async cacheExternalFile(absolutePath: string): Promise<{ uuid: string; cachedPath: string; name: string; mimeType: string }> {
throw new Error('Кеширование доступно только в desktop версии'); await this.ensureCacheFolderExists();
}
if (!window.require) {
const fs = window.require('fs').promises; throw new Error('Кеширование доступно только в desktop версии');
const path = window.require('path'); }
const content = await fs.readFile(absolutePath); const fs = window.require('fs').promises;
const fileName = path.basename(absolutePath); const path = window.require('path');
const extension = path.extname(fileName).substring(1);
const baseName = path.basename(fileName, path.extname(fileName)); const content = await fs.readFile(absolutePath);
const fileName = path.basename(absolutePath);
const uuid = uuidv4(); const extension = path.extname(fileName).substring(1);
const cachedFileName = `${baseName}-${uuid}.${extension}`; const baseName = path.basename(fileName, path.extname(fileName));
const cacheFolderPath = this.getCacheFolderPath(); const uuid = uuidv4();
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`; const cachedFileName = `${baseName}-${uuid}.${extension}`;
await fs.writeFile(cachedFilePath, content); const cacheFolderPath = this.getCacheFolderPath();
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
return {
uuid: uuid, await fs.writeFile(cachedFilePath, content);
cachedPath: cachedFileName,
name: fileName, return {
mimeType: getMimeType(fileName) uuid: uuid,
}; cachedPath: cachedFileName,
} name: fileName,
mimeType: getMimeType(fileName)
/** };
* Восстанавливает кеш из исходного файла }
*/
async restoreCache(sourcePath: string, type: 'file' | 'prompt' | 'external', uuid: string): Promise<string> { /**
if (type === 'external') { * Восстанавливает кеш из исходного файла
// Для внешних файлов sourcePath - абсолютный */
const result = await this.cacheExternalFile(sourcePath); async restoreCache(sourcePath: string, type: 'file' | 'prompt' | 'external', uuid: string): Promise<string> {
return result.cachedPath; if (type === 'external') {
} else if (type === 'file') { // Для внешних файлов sourcePath - абсолютный
// Для внутренних файлов sourcePath - относительный const result = await this.cacheExternalFile(sourcePath);
const file = this.plugin.app.vault.getAbstractFileByPath(sourcePath); return result.cachedPath;
if (file instanceof TFile) { } else if (type === 'file') {
const result = await this.cacheVaultFile(file); // Для внутренних файлов sourcePath - относительный
return result.cachedPath; const file = this.plugin.app.vault.getAbstractFileByPath(sourcePath);
} if (file instanceof TFile) {
} else if (type === 'prompt') { const result = await this.cacheVaultFile(file);
// Для промптов return result.cachedPath;
const promptsFolder = this.plugin.settings.promptsFolder; }
const fullPath = this.isAbsolutePath(sourcePath) } else if (type === 'prompt') {
? sourcePath // Для промптов
: `${promptsFolder}/${sourcePath}`; const promptsFolder = this.plugin.settings.promptsFolder;
const fullPath = this.isAbsolutePath(sourcePath) ? sourcePath : `${promptsFolder}/${sourcePath}`;
const file = this.plugin.app.vault.getAbstractFileByPath(fullPath);
if (file instanceof TFile) { const file = this.plugin.app.vault.getAbstractFileByPath(fullPath);
const result = await this.cacheVaultFile(file); if (file instanceof TFile) {
return result.cachedPath; const result = await this.cacheVaultFile(file);
} return result.cachedPath;
} }
}
throw new Error(`Не удалось восстановить кеш для ${sourcePath}`);
} throw new Error(`Не удалось восстановить кеш для ${sourcePath}`);
}
/**
* Читает содержимое из кеша /**
*/ * Читает содержимое из кеша
async readCachedFile(cachedPath: string): Promise<ArrayBuffer> { */
const cacheFolderPath = this.getCacheFolderPath(); async readCachedFile(cachedPath: string): Promise<ArrayBuffer> {
const fullPath = `${cacheFolderPath}/${cachedPath}`; const cacheFolderPath = this.getCacheFolderPath();
const fullPath = `${cacheFolderPath}/${cachedPath}`;
if (!window.require) {
throw new Error('Чтение кеша доступно только в desktop версии'); if (!window.require) {
} throw new Error('Чтение кеша доступно только в desktop версии');
}
const fs = window.require('fs').promises;
const buffer = await fs.readFile(fullPath); const fs = window.require('fs').promises;
return buffer.buffer; const buffer = await fs.readFile(fullPath);
} return buffer.buffer;
}
/**
* Проверяет существование кешированного файла /**
*/ * Проверяет существование кешированного файла
async cachedFileExists(cachedPath: string): Promise<boolean> { */
const cacheFolderPath = this.getCacheFolderPath(); async cachedFileExists(cachedPath: string): Promise<boolean> {
const fullPath = `${cacheFolderPath}/${cachedPath}`; const cacheFolderPath = this.getCacheFolderPath();
const fullPath = `${cacheFolderPath}/${cachedPath}`;
if (!window.require) return false;
if (!window.require) return false;
const fs = window.require('fs').promises;
const fs = window.require('fs').promises;
try {
await fs.access(fullPath); try {
return true; await fs.access(fullPath);
} catch { return true;
return false; } catch {
} return false;
} }
} }
}

View File

@ -32,7 +32,7 @@ export class ReferenceExpander {
* @param references - массив ссылок для обработки * @param references - массив ссылок для обработки
* @returns текст с развернутыми ссылками * @returns текст с развернутыми ссылками
*/ */
async expandReferences(text: string, references: FileReference[]): Promise<string> { /*async expandReferences(text: string, references: FileReference[]): Promise<string> {
if (references.length === 0) { if (references.length === 0) {
return text; return text;
} }
@ -53,14 +53,14 @@ export class ReferenceExpander {
} }
return expandedText; return expandedText;
} }*/
/** /**
* Обрабатывает историю сообщений, раскрывая постоянные ссылки (@@/##) * Обрабатывает историю сообщений, раскрывая постоянные ссылки (@@/##)
* @param messages - массив сообщений * @param messages - массив сообщений
* @returns обработанные сообщения * @returns обработанные сообщения
*/ */
async expandMessageHistory(messages: any[]): Promise<any[]> { /*async expandMessageHistory(messages: any[]): Promise<any[]> {
const expandedMessages = []; const expandedMessages = [];
for (const message of messages) { for (const message of messages) {
@ -76,7 +76,7 @@ export class ReferenceExpander {
} }
return expandedMessages; return expandedMessages;
} }*/
/** /**
* Извлекает вложения из текста и кеширует файлы * Извлекает вложения из текста и кеширует файлы
@ -158,7 +158,7 @@ export class ReferenceExpander {
* Подготавливает сообщения для LLM с учетом вложений. * Подготавливает сообщения для LLM с учетом вложений.
* Раскрывает только постоянные (@@/##) ссылки и ссылки в последнем сообщении. * Раскрывает только постоянные (@@/##) ссылки и ссылки в последнем сообщении.
*/ */
async prepareMessagesForLLM(messages: ChatHistoryItem[], isLastMessage: boolean = false): Promise<any[]> { /*async prepareMessagesForLLM(messages: ChatHistoryItem[], isLastMessage: boolean = false): Promise<any[]> {
const preparedMessages = []; const preparedMessages = [];
for (let i = 0; i < messages.length; i++) { for (let i = 0; i < messages.length; i++) {
@ -199,7 +199,7 @@ export class ReferenceExpander {
} }
return preparedMessages; return preparedMessages;
} }*/
// TODO: При реализации снапшотов - сохранять содержимое файлов // TODO: При реализации снапшотов - сохранять содержимое файлов
// async expandReferencesWithSnapshots(text: string, references: FileReference[], messageId: string): Promise<{expandedText: string, snapshots: Record<string, string>}> { // async expandReferencesWithSnapshots(text: string, references: FileReference[], messageId: string): Promise<{expandedText: string, snapshots: Record<string, string>}> {
@ -226,7 +226,7 @@ export class ReferenceExpander {
* @param preloadedContent - предзагруженное содержимое (для снапшотов) * @param preloadedContent - предзагруженное содержимое (для снапшотов)
* @returns текст с раскрытой ссылкой * @returns текст с раскрытой ссылкой
*/ */
private async expandSingleReference(text: string, reference: FileReference, preloadedContent?: string): Promise<string> { /*private async expandSingleReference(text: string, reference: FileReference, preloadedContent?: string): Promise<string> {
const content = preloadedContent || (await this.loadFileContent(reference)); const content = preloadedContent || (await this.loadFileContent(reference));
if (content === null) { if (content === null) {
@ -245,14 +245,14 @@ export class ReferenceExpander {
const formattedContent = this.formatContentForInsertion(content, reference); const formattedContent = this.formatContentForInsertion(content, reference);
return text.replace(pattern, formattedContent); return text.replace(pattern, formattedContent);
} }*/
/** /**
* Раскрывает только постоянные ссылки (@@/##) в тексте * Раскрывает только постоянные ссылки (@@/##) в тексте
* @param text - текст для обработки * @param text - текст для обработки
* @returns текст с раскрытыми постоянными ссылками * @returns текст с раскрытыми постоянными ссылками
*/ */
private async expandPermanentReferences(text: string): Promise<string> { /*private async expandPermanentReferences(text: string): Promise<string> {
const matches = ReferenceParser.parseReferences(text); const matches = ReferenceParser.parseReferences(text);
const permanentMatches = matches.filter((match) => match.prefix.length === 2); // @@ или ## const permanentMatches = matches.filter((match) => match.prefix.length === 2); // @@ или ##
@ -281,14 +281,14 @@ export class ReferenceExpander {
} }
return expandedText; return expandedText;
} }*/
/** /**
* Загружает содержимое файла * Загружает содержимое файла
* @param reference - ссылка на файл * @param reference - ссылка на файл
* @returns содержимое файла или null если не найден * @returns содержимое файла или null если не найден
*/ */
private async loadFileContent(reference: FileReference): Promise<string | null> { /*private async loadFileContent(reference: FileReference): Promise<string | null> {
try { try {
const file = this.findFile(reference.path, reference.type); const file = this.findFile(reference.path, reference.type);
if (!file) { if (!file) {
@ -307,7 +307,7 @@ export class ReferenceExpander {
console.error(`Ошибка загрузки файла ${reference.path}:`, error); console.error(`Ошибка загрузки файла ${reference.path}:`, error);
return null; return null;
} }
} }*/
/** /**
* Находит файл по пути * Находит файл по пути
@ -315,7 +315,7 @@ export class ReferenceExpander {
* @param type - тип файла * @param type - тип файла
* @returns файл или null * @returns файл или null
*/ */
private findFile(path: string, type: 'file' | 'prompt'): TFile | null { /*private findFile(path: string, type: 'file' | 'prompt'): TFile | null {
let file = this.plugin.app.vault.getAbstractFileByPath(path); let file = this.plugin.app.vault.getAbstractFileByPath(path);
if (!file && type === 'prompt') { if (!file && type === 'prompt') {
@ -328,7 +328,7 @@ export class ReferenceExpander {
} }
return file instanceof TFile ? file : null; return file instanceof TFile ? file : null;
} }*/
/** /**
* Разрешает полный путь к файлу по имени * Разрешает полный путь к файлу по имени
@ -336,7 +336,7 @@ export class ReferenceExpander {
* @param type - тип файла * @param type - тип файла
* @returns полный путь к файлу * @returns полный путь к файлу
*/ */
private async resolveFilePath(name: string, type: 'file' | 'prompt'): Promise<string> { /*private async resolveFilePath(name: string, type: 'file' | 'prompt'): Promise<string> {
if (type === 'prompt') { if (type === 'prompt') {
const promptsFolder = this.plugin.settings.promptsFolder; const promptsFolder = this.plugin.settings.promptsFolder;
return promptsFolder ? `${promptsFolder}/${name}.md` : `${name}.md`; return promptsFolder ? `${promptsFolder}/${name}.md` : `${name}.md`;
@ -346,7 +346,7 @@ export class ReferenceExpander {
const matchingFile = files.find((f) => f.basename === name); const matchingFile = files.find((f) => f.basename === name);
return matchingFile ? matchingFile.path : `${name}.md`; return matchingFile ? matchingFile.path : `${name}.md`;
} }
} }*/
/** /**
* Форматирует содержимое для вставки в сообщение * Форматирует содержимое для вставки в сообщение
@ -354,20 +354,20 @@ export class ReferenceExpander {
* @param reference - информация о ссылке * @param reference - информация о ссылке
* @returns отформатированное содержимое * @returns отформатированное содержимое
*/ */
private formatContentForInsertion(content: string, reference: FileReference): string { /*private formatContentForInsertion(content: string, reference: FileReference): string {
// Добавляем заголовок с информацией о файле // Добавляем заголовок с информацией о файле
const header = `\n\n--- Содержимое ${reference.type === 'prompt' ? 'промпта' : 'файла'}: ${reference.name} ---\n`; const header = `\n\n--- Содержимое ${reference.type === 'prompt' ? 'промпта' : 'файла'}: ${reference.name} ---\n`;
const footer = `\n--- Конец ${reference.type === 'prompt' ? 'промпта' : 'файла'}: ${reference.name} ---\n\n`; const footer = `\n--- Конец ${reference.type === 'prompt' ? 'промпта' : 'файла'}: ${reference.name} ---\n\n`;
return header + content.trim() + footer; return header + content.trim() + footer;
} }*/
/** /**
* Экранирует специальные символы для регулярного выражения * Экранирует специальные символы для регулярного выражения
* @param string - строка для экранирования * @param string - строка для экранирования
* @returns экранированная строка * @returns экранированная строка
*/ */
private escapeRegExp(string: string): string { /*private escapeRegExp(string: string): string {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
} }*/
} }

View File

@ -0,0 +1,18 @@
interface Window {
/**
* Electron API exposed to the renderer process.
* Available only in the desktop version of Obsidian.
*/
electron?: {
remote: {
dialog: {
showOpenDialog: (options: {
properties?: ('openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory')[];
title?: string;
defaultPath?: string;
}) => Promise<{ canceled: boolean; filePaths: string[] }>;
};
};
};
require?: NodeRequire;
}

View File

@ -348,7 +348,7 @@ export class ChatView extends ItemView {
}); });
if (data.reused) { if (data.reused) {
this.clearStreamingMessage(assistantNodeId); this.clearStreamingMessage(assistantNodeId!);
} }
this.plugin.eventBus.emit('graph-selected', { this.plugin.eventBus.emit('graph-selected', {
graphId: graphId, graphId: graphId,

1411
styles.css

File diff suppressed because one or more lines are too long