Fixes for build
This commit is contained in:
parent
f61cf08efd
commit
cb8ed95bcd
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
main.ts
4
main.ts
|
|
@ -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
1523
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ interface BaseNodeWrapperData {
|
||||||
interface BaseNodeWrapperProps {
|
interface BaseNodeWrapperProps {
|
||||||
data: BaseNodeWrapperData;
|
data: BaseNodeWrapperData;
|
||||||
isConnectable: boolean;
|
isConnectable: boolean;
|
||||||
// children: React.ReactNode; // Содержимое, специфичное для типа узла (например, метка)
|
children?: React.ReactNode; // Содержимое, специфичное для типа узла (например, метка)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 (this.plugin.app.vault.adapter as FileSystemAdapter).getBasePath() + '/' + cacheFolder;
|
||||||
|
}
|
||||||
|
|
||||||
return cacheFolder;
|
return cacheFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Проверяет, является ли путь абсолютным
|
* Проверяет, является ли путь абсолютным
|
||||||
*/
|
*/
|
||||||
private isAbsolutePath(path: string): boolean {
|
private isAbsolutePath(path: string): boolean {
|
||||||
// Windows: C:\, D:\, и т.д.
|
// Windows: C:\, D:\, и т.д.
|
||||||
if (/^[a-zA-Z]:\\/.test(path)) return true;
|
if (/^[a-zA-Z]:\\/.test(path)) return true;
|
||||||
// Unix: /
|
// Unix: /
|
||||||
if (path.startsWith('/')) return true;
|
if (path.startsWith('/')) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Создает папку кеша, если она не существует
|
* Создает папку кеша, если она не существует
|
||||||
*/
|
*/
|
||||||
private async ensureCacheFolderExists(): Promise<void> {
|
private async ensureCacheFolderExists(): Promise<void> {
|
||||||
const cachePath = this.getCacheFolderPath();
|
const cachePath = this.getCacheFolderPath();
|
||||||
|
|
||||||
if (!window.require) return; // Web версия
|
if (!window.require) return; // Web версия
|
||||||
|
|
||||||
const fs = window.require('fs').promises;
|
const fs = window.require('fs').promises;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.access(cachePath);
|
await fs.access(cachePath);
|
||||||
} catch {
|
} catch {
|
||||||
await fs.mkdir(cachePath, { recursive: true });
|
await fs.mkdir(cachePath, { recursive: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Кеширует файл из vault
|
* Кеширует файл из vault
|
||||||
*/
|
*/
|
||||||
async cacheVaultFile(file: TFile): Promise<{ uuid: string; cachedPath: string }> {
|
async cacheVaultFile(file: TFile): Promise<{ uuid: string; cachedPath: string }> {
|
||||||
await this.ensureCacheFolderExists();
|
await this.ensureCacheFolderExists();
|
||||||
|
|
||||||
const uuid = uuidv4();
|
const uuid = uuidv4();
|
||||||
const extension = file.extension;
|
const extension = file.extension;
|
||||||
const cachedFileName = `${file.basename}-${uuid}.${extension}`;
|
const cachedFileName = `${file.basename}-${uuid}.${extension}`;
|
||||||
|
|
||||||
const content = await this.plugin.app.vault.readBinary(file);
|
const content = await this.plugin.app.vault.readBinary(file);
|
||||||
|
|
||||||
const cacheFolderPath = this.getCacheFolderPath();
|
const cacheFolderPath = this.getCacheFolderPath();
|
||||||
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
|
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
|
||||||
|
|
||||||
if (!window.require) {
|
if (!window.require) {
|
||||||
throw new Error('Кеширование доступно только в desktop версии');
|
throw new Error('Кеширование доступно только в desktop версии');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fs = window.require('fs').promises;
|
const fs = window.require('fs').promises;
|
||||||
await fs.writeFile(cachedFilePath, Buffer.from(content));
|
await fs.writeFile(cachedFilePath, Buffer.from(content));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
cachedPath: cachedFileName // Относительный путь
|
cachedPath: cachedFileName // Относительный путь
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Кеширует внешний файл
|
* Кеширует внешний файл
|
||||||
*/
|
*/
|
||||||
async cacheExternalFile(absolutePath: string): Promise<{ uuid: string; cachedPath: string; name: string; mimeType: string }> {
|
async cacheExternalFile(absolutePath: string): Promise<{ uuid: string; cachedPath: string; name: string; mimeType: string }> {
|
||||||
await this.ensureCacheFolderExists();
|
await this.ensureCacheFolderExists();
|
||||||
|
|
||||||
if (!window.require) {
|
if (!window.require) {
|
||||||
throw new Error('Кеширование доступно только в desktop версии');
|
throw new Error('Кеширование доступно только в desktop версии');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fs = window.require('fs').promises;
|
const fs = window.require('fs').promises;
|
||||||
const path = window.require('path');
|
const path = window.require('path');
|
||||||
|
|
||||||
const content = await fs.readFile(absolutePath);
|
const content = await fs.readFile(absolutePath);
|
||||||
const fileName = path.basename(absolutePath);
|
const fileName = path.basename(absolutePath);
|
||||||
const extension = path.extname(fileName).substring(1);
|
const extension = path.extname(fileName).substring(1);
|
||||||
const baseName = path.basename(fileName, path.extname(fileName));
|
const baseName = path.basename(fileName, path.extname(fileName));
|
||||||
|
|
||||||
const uuid = uuidv4();
|
const uuid = uuidv4();
|
||||||
const cachedFileName = `${baseName}-${uuid}.${extension}`;
|
const cachedFileName = `${baseName}-${uuid}.${extension}`;
|
||||||
|
|
||||||
const cacheFolderPath = this.getCacheFolderPath();
|
const cacheFolderPath = this.getCacheFolderPath();
|
||||||
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
|
const cachedFilePath = `${cacheFolderPath}/${cachedFileName}`;
|
||||||
|
|
||||||
await fs.writeFile(cachedFilePath, content);
|
await fs.writeFile(cachedFilePath, content);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
cachedPath: cachedFileName,
|
cachedPath: cachedFileName,
|
||||||
name: fileName,
|
name: fileName,
|
||||||
mimeType: getMimeType(fileName)
|
mimeType: getMimeType(fileName)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Восстанавливает кеш из исходного файла
|
* Восстанавливает кеш из исходного файла
|
||||||
*/
|
*/
|
||||||
async restoreCache(sourcePath: string, type: 'file' | 'prompt' | 'external', uuid: string): Promise<string> {
|
async restoreCache(sourcePath: string, type: 'file' | 'prompt' | 'external', uuid: string): Promise<string> {
|
||||||
if (type === 'external') {
|
if (type === 'external') {
|
||||||
// Для внешних файлов sourcePath - абсолютный
|
// Для внешних файлов sourcePath - абсолютный
|
||||||
const result = await this.cacheExternalFile(sourcePath);
|
const result = await this.cacheExternalFile(sourcePath);
|
||||||
return result.cachedPath;
|
return result.cachedPath;
|
||||||
} else if (type === 'file') {
|
} else if (type === 'file') {
|
||||||
// Для внутренних файлов sourcePath - относительный
|
// Для внутренних файлов sourcePath - относительный
|
||||||
const file = this.plugin.app.vault.getAbstractFileByPath(sourcePath);
|
const file = this.plugin.app.vault.getAbstractFileByPath(sourcePath);
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
const result = await this.cacheVaultFile(file);
|
const result = await this.cacheVaultFile(file);
|
||||||
return result.cachedPath;
|
return result.cachedPath;
|
||||||
}
|
}
|
||||||
} else if (type === 'prompt') {
|
} else if (type === 'prompt') {
|
||||||
// Для промптов
|
// Для промптов
|
||||||
const promptsFolder = this.plugin.settings.promptsFolder;
|
const promptsFolder = this.plugin.settings.promptsFolder;
|
||||||
const fullPath = this.isAbsolutePath(sourcePath)
|
const fullPath = this.isAbsolutePath(sourcePath) ? sourcePath : `${promptsFolder}/${sourcePath}`;
|
||||||
? sourcePath
|
|
||||||
: `${promptsFolder}/${sourcePath}`;
|
|
||||||
|
|
||||||
const file = this.plugin.app.vault.getAbstractFileByPath(fullPath);
|
const file = this.plugin.app.vault.getAbstractFileByPath(fullPath);
|
||||||
if (file instanceof TFile) {
|
if (file instanceof TFile) {
|
||||||
const result = await this.cacheVaultFile(file);
|
const result = await this.cacheVaultFile(file);
|
||||||
return result.cachedPath;
|
return result.cachedPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Не удалось восстановить кеш для ${sourcePath}`);
|
throw new Error(`Не удалось восстановить кеш для ${sourcePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Читает содержимое из кеша
|
* Читает содержимое из кеша
|
||||||
*/
|
*/
|
||||||
async readCachedFile(cachedPath: string): Promise<ArrayBuffer> {
|
async readCachedFile(cachedPath: string): Promise<ArrayBuffer> {
|
||||||
const cacheFolderPath = this.getCacheFolderPath();
|
const cacheFolderPath = this.getCacheFolderPath();
|
||||||
const fullPath = `${cacheFolderPath}/${cachedPath}`;
|
const fullPath = `${cacheFolderPath}/${cachedPath}`;
|
||||||
|
|
||||||
if (!window.require) {
|
if (!window.require) {
|
||||||
throw new Error('Чтение кеша доступно только в desktop версии');
|
throw new Error('Чтение кеша доступно только в desktop версии');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fs = window.require('fs').promises;
|
const fs = window.require('fs').promises;
|
||||||
const buffer = await fs.readFile(fullPath);
|
const buffer = await fs.readFile(fullPath);
|
||||||
return buffer.buffer;
|
return buffer.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Проверяет существование кешированного файла
|
* Проверяет существование кешированного файла
|
||||||
*/
|
*/
|
||||||
async cachedFileExists(cachedPath: string): Promise<boolean> {
|
async cachedFileExists(cachedPath: string): Promise<boolean> {
|
||||||
const cacheFolderPath = this.getCacheFolderPath();
|
const cacheFolderPath = this.getCacheFolderPath();
|
||||||
const fullPath = `${cacheFolderPath}/${cachedPath}`;
|
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 {
|
try {
|
||||||
await fs.access(fullPath);
|
await fs.access(fullPath);
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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, '\\$&');
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/types/electron.d.ts
vendored
18
src/types/electron.d.ts
vendored
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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
1411
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user