@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +15 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,544 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File Attachment Service
|
|
3
|
-
* Manages file attachments for agents with CRUD operations and reference counting
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { randomUUID } from 'crypto';
|
|
9
|
-
import FileProcessor from '../utilities/fileProcessor.js';
|
|
10
|
-
import AttachmentValidator from '../utilities/attachmentValidator.js';
|
|
11
|
-
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = path.dirname(__filename);
|
|
14
|
-
|
|
15
|
-
const ATTACHMENTS_DIR = path.join(process.cwd(), 'loxia-state', 'attachments');
|
|
16
|
-
const INDEX_FILE = path.join(ATTACHMENTS_DIR, 'attachments-index.json');
|
|
17
|
-
|
|
18
|
-
class FileAttachmentService {
|
|
19
|
-
constructor(config = {}, logger = null) {
|
|
20
|
-
this.config = config;
|
|
21
|
-
this.logger = logger;
|
|
22
|
-
this.fileProcessor = new FileProcessor(config, logger);
|
|
23
|
-
this.validator = new AttachmentValidator(config, logger);
|
|
24
|
-
this.index = null; // Lazy loaded
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Initialize service (create directories, load index)
|
|
29
|
-
* @returns {Promise<void>}
|
|
30
|
-
*/
|
|
31
|
-
async initialize() {
|
|
32
|
-
try {
|
|
33
|
-
await this.fileProcessor.createDirectory(ATTACHMENTS_DIR);
|
|
34
|
-
await this.loadIndex();
|
|
35
|
-
this.logger?.info('FileAttachmentService initialized', { attachmentsDir: ATTACHMENTS_DIR });
|
|
36
|
-
} catch (error) {
|
|
37
|
-
this.logger?.error('Error initializing FileAttachmentService', { error: error.message });
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Load index file
|
|
44
|
-
* @returns {Promise<Object>}
|
|
45
|
-
*/
|
|
46
|
-
async loadIndex() {
|
|
47
|
-
try {
|
|
48
|
-
const exists = await this.fileProcessor.fileExists(INDEX_FILE);
|
|
49
|
-
if (!exists) {
|
|
50
|
-
this.index = { attachments: {}, agentRefs: {} };
|
|
51
|
-
await this.saveIndex();
|
|
52
|
-
} else {
|
|
53
|
-
const content = await this.fileProcessor.readFile(INDEX_FILE, 'utf8');
|
|
54
|
-
this.index = JSON.parse(content);
|
|
55
|
-
}
|
|
56
|
-
return this.index;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
this.logger?.error('Error loading index', { error: error.message });
|
|
59
|
-
this.index = { attachments: {}, agentRefs: {} };
|
|
60
|
-
return this.index;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Save index file
|
|
66
|
-
* @returns {Promise<void>}
|
|
67
|
-
*/
|
|
68
|
-
async saveIndex() {
|
|
69
|
-
try {
|
|
70
|
-
await this.fileProcessor.writeFile(INDEX_FILE, JSON.stringify(this.index, null, 2), 'utf8');
|
|
71
|
-
} catch (error) {
|
|
72
|
-
this.logger?.error('Error saving index', { error: error.message });
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Upload file attachment
|
|
79
|
-
* @param {Object} options
|
|
80
|
-
* @param {string} options.agentId - Agent ID
|
|
81
|
-
* @param {string} options.filePath - Source file path
|
|
82
|
-
* @param {string} options.mode - 'content' or 'reference'
|
|
83
|
-
* @param {string} options.fileName - Optional custom file name
|
|
84
|
-
* @returns {Promise<Object>} Attachment metadata
|
|
85
|
-
*/
|
|
86
|
-
async uploadFile({ agentId, filePath, mode = 'content', fileName = null }) {
|
|
87
|
-
if (!this.index) {
|
|
88
|
-
await this.loadIndex();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
// Validate file exists
|
|
93
|
-
const exists = await this.fileProcessor.fileExists(filePath);
|
|
94
|
-
if (!exists) {
|
|
95
|
-
throw new Error(`File not found: ${filePath}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Get file stats
|
|
99
|
-
const stats = await this.fileProcessor.getFileStats(filePath);
|
|
100
|
-
const actualFileName = fileName || path.basename(filePath);
|
|
101
|
-
const fileExtension = path.extname(actualFileName);
|
|
102
|
-
|
|
103
|
-
// Validate
|
|
104
|
-
const validation = this.validator.validate({
|
|
105
|
-
fileName: actualFileName,
|
|
106
|
-
size: stats.size,
|
|
107
|
-
mode,
|
|
108
|
-
path: mode === 'reference' ? filePath : null
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
if (!validation.valid) {
|
|
112
|
-
throw new Error(`Validation failed: ${validation.errors.join(', ')}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Generate file ID
|
|
116
|
-
const fileId = randomUUID();
|
|
117
|
-
|
|
118
|
-
// Calculate hash
|
|
119
|
-
const hash = await this.fileProcessor.calculateHash(filePath);
|
|
120
|
-
|
|
121
|
-
// Determine content type
|
|
122
|
-
const contentType = this.validator.getContentType(actualFileName);
|
|
123
|
-
|
|
124
|
-
// Create attachment directory
|
|
125
|
-
const attachmentDir = path.join(ATTACHMENTS_DIR, agentId, fileId);
|
|
126
|
-
await this.fileProcessor.createDirectory(attachmentDir);
|
|
127
|
-
|
|
128
|
-
// Process and save content (for content mode)
|
|
129
|
-
let tokenEstimate = 0;
|
|
130
|
-
let contentFileName = null;
|
|
131
|
-
|
|
132
|
-
if (mode === 'content') {
|
|
133
|
-
const processResult = await this.fileProcessor.processFile(filePath, contentType);
|
|
134
|
-
const content = processResult.content;
|
|
135
|
-
|
|
136
|
-
// Determine content file name based on type
|
|
137
|
-
if (contentType === 'text') {
|
|
138
|
-
contentFileName = 'content.txt';
|
|
139
|
-
} else if (contentType === 'image') {
|
|
140
|
-
contentFileName = 'content.base64';
|
|
141
|
-
} else if (contentType === 'pdf') {
|
|
142
|
-
contentFileName = 'content.txt';
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Save content
|
|
146
|
-
const contentFilePath = path.join(attachmentDir, contentFileName);
|
|
147
|
-
await this.fileProcessor.writeFile(contentFilePath, content, 'utf8');
|
|
148
|
-
|
|
149
|
-
// Estimate tokens
|
|
150
|
-
tokenEstimate = this.fileProcessor.estimateTokens(content);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Create metadata
|
|
154
|
-
const metadata = {
|
|
155
|
-
fileId,
|
|
156
|
-
agentId,
|
|
157
|
-
fileName: actualFileName,
|
|
158
|
-
originalPath: filePath,
|
|
159
|
-
fileType: this.validator.getMimeType(actualFileName),
|
|
160
|
-
fileExtension,
|
|
161
|
-
size: stats.size,
|
|
162
|
-
mode,
|
|
163
|
-
active: true,
|
|
164
|
-
uploadedAt: new Date().toISOString(),
|
|
165
|
-
lastModified: stats.modified.toISOString(),
|
|
166
|
-
hash,
|
|
167
|
-
tokenEstimate,
|
|
168
|
-
contentType,
|
|
169
|
-
contentFileName,
|
|
170
|
-
warnings: validation.warnings,
|
|
171
|
-
sizeLevel: validation.sizeLevel,
|
|
172
|
-
importedFrom: null,
|
|
173
|
-
referencedBy: [agentId] // Reference counting
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// Save metadata
|
|
177
|
-
const metadataPath = path.join(attachmentDir, 'metadata.json');
|
|
178
|
-
await this.fileProcessor.writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
|
|
179
|
-
|
|
180
|
-
// Update index
|
|
181
|
-
this.index.attachments[fileId] = {
|
|
182
|
-
fileId,
|
|
183
|
-
agentId,
|
|
184
|
-
fileName: actualFileName,
|
|
185
|
-
mode,
|
|
186
|
-
active: metadata.active,
|
|
187
|
-
referencedBy: metadata.referencedBy
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
if (!this.index.agentRefs[agentId]) {
|
|
191
|
-
this.index.agentRefs[agentId] = [];
|
|
192
|
-
}
|
|
193
|
-
this.index.agentRefs[agentId].push(fileId);
|
|
194
|
-
|
|
195
|
-
await this.saveIndex();
|
|
196
|
-
|
|
197
|
-
this.logger?.info('File uploaded', { fileId, agentId, fileName: actualFileName, mode });
|
|
198
|
-
|
|
199
|
-
return metadata;
|
|
200
|
-
} catch (error) {
|
|
201
|
-
this.logger?.error('Error uploading file', { agentId, filePath, error: error.message });
|
|
202
|
-
throw error;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Get attachments for an agent
|
|
208
|
-
* @param {string} agentId - Agent ID
|
|
209
|
-
* @param {Object} filters - Optional filters { active, mode }
|
|
210
|
-
* @returns {Promise<Array>} Array of attachment metadata
|
|
211
|
-
*/
|
|
212
|
-
async getAttachments(agentId, filters = {}) {
|
|
213
|
-
if (!this.index) {
|
|
214
|
-
await this.loadIndex();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
const fileIds = this.index.agentRefs[agentId] || [];
|
|
219
|
-
const attachments = [];
|
|
220
|
-
|
|
221
|
-
for (const fileId of fileIds) {
|
|
222
|
-
const metadata = await this.getAttachment(fileId);
|
|
223
|
-
if (metadata) {
|
|
224
|
-
// Apply filters
|
|
225
|
-
if (filters.active !== undefined && metadata.active !== filters.active) {
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
if (filters.mode && metadata.mode !== filters.mode) {
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
attachments.push(metadata);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return attachments;
|
|
236
|
-
} catch (error) {
|
|
237
|
-
this.logger?.error('Error getting attachments', { agentId, error: error.message });
|
|
238
|
-
throw error;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Get single attachment
|
|
244
|
-
* @param {string} fileId - File ID
|
|
245
|
-
* @returns {Promise<Object|null>} Attachment metadata or null
|
|
246
|
-
*/
|
|
247
|
-
async getAttachment(fileId) {
|
|
248
|
-
if (!this.index) {
|
|
249
|
-
await this.loadIndex();
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
const indexEntry = this.index.attachments[fileId];
|
|
254
|
-
if (!indexEntry) {
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const metadataPath = path.join(ATTACHMENTS_DIR, indexEntry.agentId, fileId, 'metadata.json');
|
|
259
|
-
const exists = await this.fileProcessor.fileExists(metadataPath);
|
|
260
|
-
|
|
261
|
-
if (!exists) {
|
|
262
|
-
this.logger?.warn('Metadata file not found', { fileId });
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const content = await this.fileProcessor.readFile(metadataPath, 'utf8');
|
|
267
|
-
return JSON.parse(content);
|
|
268
|
-
} catch (error) {
|
|
269
|
-
this.logger?.error('Error getting attachment', { fileId, error: error.message });
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Get attachment content
|
|
276
|
-
* @param {string} fileId - File ID
|
|
277
|
-
* @returns {Promise<string|null>} File content or null
|
|
278
|
-
*/
|
|
279
|
-
async getAttachmentContent(fileId) {
|
|
280
|
-
try {
|
|
281
|
-
const metadata = await this.getAttachment(fileId);
|
|
282
|
-
if (!metadata || metadata.mode !== 'content') {
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const contentPath = path.join(ATTACHMENTS_DIR, metadata.agentId, fileId, metadata.contentFileName);
|
|
287
|
-
const exists = await this.fileProcessor.fileExists(contentPath);
|
|
288
|
-
|
|
289
|
-
if (!exists) {
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return await this.fileProcessor.readFile(contentPath, 'utf8');
|
|
294
|
-
} catch (error) {
|
|
295
|
-
this.logger?.error('Error getting attachment content', { fileId, error: error.message });
|
|
296
|
-
return null;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Toggle attachment active state
|
|
302
|
-
* @param {string} fileId - File ID
|
|
303
|
-
* @returns {Promise<Object>} Updated metadata
|
|
304
|
-
*/
|
|
305
|
-
async toggleActive(fileId) {
|
|
306
|
-
try {
|
|
307
|
-
const metadata = await this.getAttachment(fileId);
|
|
308
|
-
if (!metadata) {
|
|
309
|
-
throw new Error(`Attachment not found: ${fileId}`);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
metadata.active = !metadata.active;
|
|
313
|
-
metadata.lastModified = new Date().toISOString();
|
|
314
|
-
|
|
315
|
-
// Save updated metadata
|
|
316
|
-
const metadataPath = path.join(ATTACHMENTS_DIR, metadata.agentId, fileId, 'metadata.json');
|
|
317
|
-
await this.fileProcessor.writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
|
|
318
|
-
|
|
319
|
-
// Update index
|
|
320
|
-
if (this.index.attachments[fileId]) {
|
|
321
|
-
this.index.attachments[fileId].active = metadata.active;
|
|
322
|
-
await this.saveIndex();
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
this.logger?.info('Attachment active state toggled', { fileId, active: metadata.active });
|
|
326
|
-
|
|
327
|
-
return metadata;
|
|
328
|
-
} catch (error) {
|
|
329
|
-
this.logger?.error('Error toggling attachment', { fileId, error: error.message });
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Update attachment metadata
|
|
336
|
-
* @param {string} fileId - File ID
|
|
337
|
-
* @param {Object} updates - Fields to update
|
|
338
|
-
* @returns {Promise<Object>} Updated metadata
|
|
339
|
-
*/
|
|
340
|
-
async updateAttachment(fileId, updates) {
|
|
341
|
-
try {
|
|
342
|
-
const metadata = await this.getAttachment(fileId);
|
|
343
|
-
if (!metadata) {
|
|
344
|
-
throw new Error(`Attachment not found: ${fileId}`);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Allow only safe updates
|
|
348
|
-
const allowedFields = ['fileName', 'active'];
|
|
349
|
-
for (const field of allowedFields) {
|
|
350
|
-
if (updates[field] !== undefined) {
|
|
351
|
-
metadata[field] = updates[field];
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
metadata.lastModified = new Date().toISOString();
|
|
356
|
-
|
|
357
|
-
// Save updated metadata
|
|
358
|
-
const metadataPath = path.join(ATTACHMENTS_DIR, metadata.agentId, fileId, 'metadata.json');
|
|
359
|
-
await this.fileProcessor.writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
|
|
360
|
-
|
|
361
|
-
// Update index
|
|
362
|
-
if (this.index.attachments[fileId]) {
|
|
363
|
-
if (updates.fileName) {
|
|
364
|
-
this.index.attachments[fileId].fileName = updates.fileName;
|
|
365
|
-
}
|
|
366
|
-
if (updates.active !== undefined) {
|
|
367
|
-
this.index.attachments[fileId].active = updates.active;
|
|
368
|
-
}
|
|
369
|
-
await this.saveIndex();
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
this.logger?.info('Attachment updated', { fileId, updates });
|
|
373
|
-
|
|
374
|
-
return metadata;
|
|
375
|
-
} catch (error) {
|
|
376
|
-
this.logger?.error('Error updating attachment', { fileId, error: error.message });
|
|
377
|
-
throw error;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Delete attachment (with reference counting)
|
|
383
|
-
* @param {string} fileId - File ID
|
|
384
|
-
* @param {string} agentId - Agent ID requesting deletion
|
|
385
|
-
* @returns {Promise<boolean>} true if deleted, false if still referenced
|
|
386
|
-
*/
|
|
387
|
-
async deleteAttachment(fileId, agentId) {
|
|
388
|
-
try {
|
|
389
|
-
const metadata = await this.getAttachment(fileId);
|
|
390
|
-
if (!metadata) {
|
|
391
|
-
throw new Error(`Attachment not found: ${fileId}`);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Remove agent from referencedBy
|
|
395
|
-
metadata.referencedBy = metadata.referencedBy.filter(id => id !== agentId);
|
|
396
|
-
|
|
397
|
-
// If still referenced by other agents, just update metadata
|
|
398
|
-
if (metadata.referencedBy.length > 0) {
|
|
399
|
-
const metadataPath = path.join(ATTACHMENTS_DIR, metadata.agentId, fileId, 'metadata.json');
|
|
400
|
-
await this.fileProcessor.writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
|
|
401
|
-
|
|
402
|
-
// Update index
|
|
403
|
-
if (this.index.attachments[fileId]) {
|
|
404
|
-
this.index.attachments[fileId].referencedBy = metadata.referencedBy;
|
|
405
|
-
}
|
|
406
|
-
if (this.index.agentRefs[agentId]) {
|
|
407
|
-
this.index.agentRefs[agentId] = this.index.agentRefs[agentId].filter(id => id !== fileId);
|
|
408
|
-
}
|
|
409
|
-
await this.saveIndex();
|
|
410
|
-
|
|
411
|
-
this.logger?.info('Attachment dereferenced', { fileId, agentId, remainingRefs: metadata.referencedBy.length });
|
|
412
|
-
return false;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// No more references, delete physical files
|
|
416
|
-
const attachmentDir = path.join(ATTACHMENTS_DIR, metadata.agentId, fileId);
|
|
417
|
-
await this.fileProcessor.deleteDirectory(attachmentDir);
|
|
418
|
-
|
|
419
|
-
// Remove from index
|
|
420
|
-
delete this.index.attachments[fileId];
|
|
421
|
-
if (this.index.agentRefs[agentId]) {
|
|
422
|
-
this.index.agentRefs[agentId] = this.index.agentRefs[agentId].filter(id => id !== fileId);
|
|
423
|
-
}
|
|
424
|
-
await this.saveIndex();
|
|
425
|
-
|
|
426
|
-
this.logger?.info('Attachment deleted', { fileId, agentId });
|
|
427
|
-
return true;
|
|
428
|
-
} catch (error) {
|
|
429
|
-
this.logger?.error('Error deleting attachment', { fileId, agentId, error: error.message });
|
|
430
|
-
throw error;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Delete all attachments for an agent
|
|
436
|
-
* @param {string} agentId - Agent ID
|
|
437
|
-
* @returns {Promise<Object>} { deleted: number, dereferenced: number }
|
|
438
|
-
*/
|
|
439
|
-
async deleteAgentAttachments(agentId) {
|
|
440
|
-
try {
|
|
441
|
-
const fileIds = this.index.agentRefs[agentId] || [];
|
|
442
|
-
let deleted = 0;
|
|
443
|
-
let dereferenced = 0;
|
|
444
|
-
|
|
445
|
-
for (const fileId of fileIds) {
|
|
446
|
-
const wasDeleted = await this.deleteAttachment(fileId, agentId);
|
|
447
|
-
if (wasDeleted) {
|
|
448
|
-
deleted++;
|
|
449
|
-
} else {
|
|
450
|
-
dereferenced++;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
this.logger?.info('Agent attachments deleted', { agentId, deleted, dereferenced });
|
|
455
|
-
|
|
456
|
-
return { deleted, dereferenced };
|
|
457
|
-
} catch (error) {
|
|
458
|
-
this.logger?.error('Error deleting agent attachments', { agentId, error: error.message });
|
|
459
|
-
throw error;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Import attachment from another agent
|
|
465
|
-
* @param {string} sourceFileId - Source file ID
|
|
466
|
-
* @param {string} targetAgentId - Target agent ID
|
|
467
|
-
* @returns {Promise<Object>} New attachment metadata
|
|
468
|
-
*/
|
|
469
|
-
async importFromAgent(sourceFileId, targetAgentId) {
|
|
470
|
-
try {
|
|
471
|
-
const sourceMetadata = await this.getAttachment(sourceFileId);
|
|
472
|
-
if (!sourceMetadata) {
|
|
473
|
-
throw new Error(`Source attachment not found: ${sourceFileId}`);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// Add target agent to referencedBy
|
|
477
|
-
if (!sourceMetadata.referencedBy.includes(targetAgentId)) {
|
|
478
|
-
sourceMetadata.referencedBy.push(targetAgentId);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
sourceMetadata.lastModified = new Date().toISOString();
|
|
482
|
-
sourceMetadata.importedFrom = sourceMetadata.agentId;
|
|
483
|
-
|
|
484
|
-
// Save updated metadata
|
|
485
|
-
const metadataPath = path.join(ATTACHMENTS_DIR, sourceMetadata.agentId, sourceFileId, 'metadata.json');
|
|
486
|
-
await this.fileProcessor.writeFile(metadataPath, JSON.stringify(sourceMetadata, null, 2), 'utf8');
|
|
487
|
-
|
|
488
|
-
// Update index
|
|
489
|
-
if (this.index.attachments[sourceFileId]) {
|
|
490
|
-
this.index.attachments[sourceFileId].referencedBy = sourceMetadata.referencedBy;
|
|
491
|
-
}
|
|
492
|
-
if (!this.index.agentRefs[targetAgentId]) {
|
|
493
|
-
this.index.agentRefs[targetAgentId] = [];
|
|
494
|
-
}
|
|
495
|
-
if (!this.index.agentRefs[targetAgentId].includes(sourceFileId)) {
|
|
496
|
-
this.index.agentRefs[targetAgentId].push(sourceFileId);
|
|
497
|
-
}
|
|
498
|
-
await this.saveIndex();
|
|
499
|
-
|
|
500
|
-
this.logger?.info('Attachment imported', { sourceFileId, targetAgentId });
|
|
501
|
-
|
|
502
|
-
return sourceMetadata;
|
|
503
|
-
} catch (error) {
|
|
504
|
-
this.logger?.error('Error importing attachment', { sourceFileId, targetAgentId, error: error.message });
|
|
505
|
-
throw error;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Get active attachments for an agent
|
|
511
|
-
* @param {string} agentId - Agent ID
|
|
512
|
-
* @returns {Promise<Array>} Array of active attachment metadata
|
|
513
|
-
*/
|
|
514
|
-
async getActiveAttachments(agentId) {
|
|
515
|
-
return await this.getAttachments(agentId, { active: true });
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* Get attachment preview (first 1000 characters)
|
|
520
|
-
* @param {string} fileId - File ID
|
|
521
|
-
* @returns {Promise<string|null>} Preview text or null
|
|
522
|
-
*/
|
|
523
|
-
async getAttachmentPreview(fileId) {
|
|
524
|
-
try {
|
|
525
|
-
const content = await this.getAttachmentContent(fileId);
|
|
526
|
-
if (!content) {
|
|
527
|
-
return null;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// For base64 images, return metadata instead of content
|
|
531
|
-
if (content.startsWith('data:image')) {
|
|
532
|
-
return '[Image content - base64 encoded]';
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// Return first 1000 characters
|
|
536
|
-
return content.length > 1000 ? content.substring(0, 1000) + '...' : content;
|
|
537
|
-
} catch (error) {
|
|
538
|
-
this.logger?.error('Error getting attachment preview', { fileId, error: error.message });
|
|
539
|
-
return null;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
export default FileAttachmentService;
|
|
1
|
+
const a0_0x31774b=a0_0x4173;(function(_0x462c90,_0x12a14){const _0x3faf3b=a0_0x4173,_0x5d8b8b=_0x462c90();while(!![]){try{const _0x24f6f5=parseInt(_0x3faf3b(0x1ba))/0x1+parseInt(_0x3faf3b(0x1f7))/0x2*(parseInt(_0x3faf3b(0x1e2))/0x3)+parseInt(_0x3faf3b(0x1b9))/0x4+parseInt(_0x3faf3b(0x1bb))/0x5+-parseInt(_0x3faf3b(0x1fb))/0x6+parseInt(_0x3faf3b(0x1e6))/0x7*(-parseInt(_0x3faf3b(0x1c1))/0x8)+parseInt(_0x3faf3b(0x1f5))/0x9*(-parseInt(_0x3faf3b(0x1ea))/0xa);if(_0x24f6f5===_0x12a14)break;else _0x5d8b8b['push'](_0x5d8b8b['shift']());}catch(_0x32630f){_0x5d8b8b['push'](_0x5d8b8b['shift']());}}}(a0_0x5e1d,0xa9705));function a0_0x4173(_0x17dc47,_0x3fe104){_0x17dc47=_0x17dc47-0x1b9;const _0x5e1da6=a0_0x5e1d();let _0x417397=_0x5e1da6[_0x17dc47];if(a0_0x4173['oQhRgW']===undefined){var _0x4f2cef=function(_0x10c29d){const _0x381eee='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5c1fed='',_0x53e444='';for(let _0x16474b=0x0,_0x1bfe09,_0x271c52,_0xb0a00d=0x0;_0x271c52=_0x10c29d['charAt'](_0xb0a00d++);~_0x271c52&&(_0x1bfe09=_0x16474b%0x4?_0x1bfe09*0x40+_0x271c52:_0x271c52,_0x16474b++%0x4)?_0x5c1fed+=String['fromCharCode'](0xff&_0x1bfe09>>(-0x2*_0x16474b&0x6)):0x0){_0x271c52=_0x381eee['indexOf'](_0x271c52);}for(let _0x125e2a=0x0,_0x2fdbbc=_0x5c1fed['length'];_0x125e2a<_0x2fdbbc;_0x125e2a++){_0x53e444+='%'+('00'+_0x5c1fed['charCodeAt'](_0x125e2a)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x53e444);};a0_0x4173['MXPjph']=_0x4f2cef,a0_0x4173['AkYyxC']={},a0_0x4173['oQhRgW']=!![];}const _0x486dbd=_0x5e1da6[0x0],_0x5a71fe=_0x17dc47+_0x486dbd,_0x140ef6=a0_0x4173['AkYyxC'][_0x5a71fe];return!_0x140ef6?(_0x417397=a0_0x4173['MXPjph'](_0x417397),a0_0x4173['AkYyxC'][_0x5a71fe]=_0x417397):_0x417397=_0x140ef6,_0x417397;}import a0_0x5c1fed from'path';import{fileURLToPath}from'url';import{randomUUID}from'crypto';import a0_0x53e444 from'../utilities/fileProcessor.js';function a0_0x5e1d(){const _0x33e301=['yxr0ywnOBwvUDhm','ywDLBNrjza','C3vIC3rYAw5N','Aw5KzxG','y29UDgvUDa','DMfSAwrHDg9Y','C3rYAw5NAwz5','Bg9HzeLUzgv4','zgvSzxrLqwDLBNrbDhrHy2HTzw50CW','CMvMzxjLBMnLzej5','Bg9Nz2vY','zMLSzuv4Axn0CW','Aw1Hz2u','mtjjEM5Mzfy','z2v0rMLSzvn0yxrZ','rxjYB3iGDxbSB2fKAw5NigzPBgu','rxjYB3iGzgvSzxrPBMCGywDLBNqGyxr0ywnOBwvUDhm','nZu2n2zryvn3qG','zxH0BMfTzq','ChvZAa','qxr0ywnOBwvUDcb1CgrHDgvK','mJyZmZiZmhHvu2ThvG','rxjYB3iGBg9HzgLUzYbPBMrLEa','rxjYB3iGDxbKyxrPBMCGyxr0ywnOBwvUDa','rxjYB3iGC2f2Aw5NigLUzgv4','C2f2zuLUzgv4','zgvSzxrLqxr0ywnOBwvUDa','Dg9ju09tDhjPBMC','z2v0qxr0ywnOBwvUDfbYzxzPzxC','rxjYB3iGzgvSzxrPBMCGyxr0ywnOBwvUDa','Aw5MBW','y2fSy3vSyxrLsgfZAa','owDOthvwrW','DxrMoa','nJa0mZm2rMHhrKHH','z2v0qxr0ywnOBwvUDhm','BwvZC2fNzq','Bw9KAwzPzwq','nZG2nZq3mgriuMPJCG','z2v0q29UDgvUDfr5Cgu','ywDLBNrszwzZ','Bw9Kzq','vMfSAwrHDgLVBIbMywLSzwq6ia','BgvUz3rO','y29UDgvUDc50Ehq','y29UzMLN','C2L6zq','qxr0ywnOBwvUDcbUB3qGzM91BMq6ia','mta2nZKWnenrCuXMuG','mtaZmJe1ngfetfDMtq','ndC3nJq2mgndELzKCq','u291CMnLigf0DgfJAg1LBNqGBM90igzVDw5KoIa','CgrM','twv0ywrHDgeGzMLSzsbUB3qGzM91BMq','z2v0qxr0ywnOBwvUDa','y3jLyxrLrgLYzwn0B3j5','odG0mefSEKrKra','BgfZDe1VzgLMAwvK','D2fYBMLUz3m','lI4U','rxjYB3iGDg9Nz2XPBMCGyxr0ywnOBwvUDa','y3DK','w0LTywDLignVBNrLBNqGlsbIyxnLnJqGzw5JB2rLzf0','ywn0AxzL','rMLSzsbUB3qGzM91BMq6ia','DxbKyxrLqxr0ywnOBwvUDa','C3rHCNrZv2L0Aa','AM9PBG','rxjYB3iGz2v0DgLUzYbHDhrHy2HTzw50ihbYzxzPzxC','CMvMzxjLBMnL','zxjYB3i','Bwv0ywrHDgeUANnVBG','rMLSzsb1CgXVywrLza','zMLSzvbYB2nLC3nVCG','zMLSDgvY','D3jPDgvgAwXL'];a0_0x5e1d=function(){return _0x33e301;};return a0_0x5e1d();}import a0_0x16474b from'../utilities/attachmentValidator.js';const __filename=fileURLToPath(import.meta.url),__dirname=a0_0x5c1fed['dirname'](__filename),ATTACHMENTS_DIR=a0_0x5c1fed['join'](process[a0_0x31774b(0x1c6)](),'loxia-state',a0_0x31774b(0x1d5)),INDEX_FILE=a0_0x5c1fed[a0_0x31774b(0x1cc)](ATTACHMENTS_DIR,'attachments-index.json');class FileAttachmentService{constructor(_0x1bfe09={},_0x271c52=null){const _0x121171=a0_0x31774b;this[_0x121171(0x202)]=_0x1bfe09,this['logger']=_0x271c52,this[_0x121171(0x1d2)]=new a0_0x53e444(_0x1bfe09,_0x271c52),this[_0x121171(0x1da)]=new a0_0x16474b(_0x1bfe09,_0x271c52),this[_0x121171(0x1d8)]=null;}async['initialize'](){const _0x15bc7e=a0_0x31774b;try{await this['fileProcessor']['createDirectory'](ATTACHMENTS_DIR),await this[_0x15bc7e(0x1dc)](),this['logger']?.['info']('FileAttachmentService\x20initialized',{'attachmentsDir':ATTACHMENTS_DIR});}catch(_0xb0a00d){this[_0x15bc7e(0x1df)]?.['error']('Error\x20initializing\x20FileAttachmentService',{'error':_0xb0a00d['message']});throw _0xb0a00d;}}async[a0_0x31774b(0x1dc)](){const _0x36f9be=a0_0x31774b;try{const _0x125e2a=await this[_0x36f9be(0x1d2)][_0x36f9be(0x1e0)](INDEX_FILE);if(!_0x125e2a)this['index']={'attachments':{},'agentRefs':{}},await this[_0x36f9be(0x1ee)]();else{const _0x2fdbbc=await this[_0x36f9be(0x1d2)]['readFile'](INDEX_FILE,_0x36f9be(0x1f6));this['index']=JSON['parse'](_0x2fdbbc);}return this['index'];}catch(_0x458d0e){return this['logger']?.['error'](_0x36f9be(0x1eb),{'error':_0x458d0e[_0x36f9be(0x1f9)]}),this['index']={'attachments':{},'agentRefs':{}},this[_0x36f9be(0x1d8)];}}async[a0_0x31774b(0x1ee)](){const _0x454559=a0_0x31774b;try{await this[_0x454559(0x1d2)][_0x454559(0x1d4)](INDEX_FILE,JSON[_0x454559(0x1db)](this[_0x454559(0x1d8)],null,0x2),_0x454559(0x1f6));}catch(_0x74cf9){this[_0x454559(0x1df)]?.['error'](_0x454559(0x1ed),{'error':_0x74cf9[_0x454559(0x1f9)]});throw _0x74cf9;}}async['uploadFile']({agentId:_0x52aa03,filePath:_0x87542a,mode:mode=a0_0x31774b(0x1d9),fileName:fileName=null}){const _0x3194c6=a0_0x31774b;!this[_0x3194c6(0x1d8)]&&await this[_0x3194c6(0x1dc)]();try{const _0x4d0f17=await this['fileProcessor']['fileExists'](_0x87542a);if(!_0x4d0f17)throw new Error(_0x3194c6(0x1c9)+_0x87542a);const _0x792adb=await this['fileProcessor'][_0x3194c6(0x1e3)](_0x87542a),_0x5c9258=fileName||a0_0x5c1fed['basename'](_0x87542a),_0x2a2c47=a0_0x5c1fed[_0x3194c6(0x1e7)](_0x5c9258),_0xbe28=this[_0x3194c6(0x1da)]['validate']({'fileName':_0x5c9258,'size':_0x792adb['size'],'mode':mode,'path':mode===_0x3194c6(0x1ce)?_0x87542a:null});if(!_0xbe28['valid'])throw new Error(_0x3194c6(0x1ff)+_0xbe28['errors'][_0x3194c6(0x1cc)](',\x20'));const _0x20e843=randomUUID(),_0x181f4f=await this['fileProcessor'][_0x3194c6(0x1f4)](_0x87542a),_0x46f7b9=this['validator'][_0x3194c6(0x1fc)](_0x5c9258),_0x5a1e26=a0_0x5c1fed[_0x3194c6(0x1cc)](ATTACHMENTS_DIR,_0x52aa03,_0x20e843);await this['fileProcessor'][_0x3194c6(0x1c0)](_0x5a1e26);let _0x10c1fc=0x0,_0x13a5b0=null;if(mode==='content'){const processResult=await this['fileProcessor']['processFile'](_0x87542a,_0x46f7b9),_0x353659=processResult['content'];if(_0x46f7b9==='text')_0x13a5b0=_0x3194c6(0x201);else{if(_0x46f7b9===_0x3194c6(0x1e1))_0x13a5b0='content.base64';else _0x46f7b9===_0x3194c6(0x1bd)&&(_0x13a5b0=_0x3194c6(0x201));}const _0x370710=a0_0x5c1fed['join'](_0x5a1e26,_0x13a5b0);await this['fileProcessor'][_0x3194c6(0x1d4)](_0x370710,_0x353659,_0x3194c6(0x1f6)),_0x10c1fc=this['fileProcessor']['estimateTokens'](_0x353659);}const _0x4f81ae={'fileId':_0x20e843,'agentId':_0x52aa03,'fileName':_0x5c9258,'originalPath':_0x87542a,'fileType':this['validator']['getMimeType'](_0x5c9258),'fileExtension':_0x2a2c47,'size':_0x792adb[_0x3194c6(0x203)],'mode':mode,'active':!![],'uploadedAt':new Date()['toISOString'](),'lastModified':_0x792adb[_0x3194c6(0x1fa)]['toISOString'](),'hash':_0x181f4f,'tokenEstimate':_0x10c1fc,'contentType':_0x46f7b9,'contentFileName':_0x13a5b0,'warnings':_0xbe28[_0x3194c6(0x1c3)],'sizeLevel':_0xbe28['sizeLevel'],'importedFrom':null,'referencedBy':[_0x52aa03]},_0x34083a=a0_0x5c1fed[_0x3194c6(0x1cc)](_0x5a1e26,_0x3194c6(0x1d0));return await this[_0x3194c6(0x1d2)]['writeFile'](_0x34083a,JSON['stringify'](_0x4f81ae,null,0x2),'utf8'),this[_0x3194c6(0x1d8)][_0x3194c6(0x1d5)][_0x20e843]={'fileId':_0x20e843,'agentId':_0x52aa03,'fileName':_0x5c9258,'mode':mode,'active':_0x4f81ae['active'],'referencedBy':_0x4f81ae[_0x3194c6(0x1de)]},!this[_0x3194c6(0x1d8)]['agentRefs'][_0x52aa03]&&(this['index'][_0x3194c6(0x1fd)][_0x52aa03]=[]),this['index'][_0x3194c6(0x1fd)][_0x52aa03]['push'](_0x20e843),await this[_0x3194c6(0x1ee)](),this[_0x3194c6(0x1df)]?.[_0x3194c6(0x1f3)](_0x3194c6(0x1d1),{'fileId':_0x20e843,'agentId':_0x52aa03,'fileName':_0x5c9258,'mode':mode}),_0x4f81ae;}catch(_0x37fdb2){this[_0x3194c6(0x1df)]?.['error'](_0x3194c6(0x1e4),{'agentId':_0x52aa03,'filePath':_0x87542a,'error':_0x37fdb2[_0x3194c6(0x1f9)]});throw _0x37fdb2;}}async[a0_0x31774b(0x1f8)](_0x3ea19b,_0xba6611={}){const _0x11b1fb=a0_0x31774b;!this[_0x11b1fb(0x1d8)]&&await this['loadIndex']();try{const _0x3490a6=this[_0x11b1fb(0x1d8)][_0x11b1fb(0x1fd)][_0x3ea19b]||[],_0x1b8e2b=[];for(const _0x3cf02c of _0x3490a6){const _0x5aa304=await this[_0x11b1fb(0x1bf)](_0x3cf02c);if(_0x5aa304){if(_0xba6611['active']!==undefined&&_0x5aa304['active']!==_0xba6611[_0x11b1fb(0x1c8)])continue;if(_0xba6611[_0x11b1fb(0x1fe)]&&_0x5aa304['mode']!==_0xba6611['mode'])continue;_0x1b8e2b[_0x11b1fb(0x1e8)](_0x5aa304);}}return _0x1b8e2b;}catch(_0x3264cf){this[_0x11b1fb(0x1df)]?.['error']('Error\x20getting\x20attachments',{'agentId':_0x3ea19b,'error':_0x3264cf[_0x11b1fb(0x1f9)]});throw _0x3264cf;}}async['getAttachment'](_0x5a0cd8){const _0x3f83e4=a0_0x31774b;!this['index']&&await this[_0x3f83e4(0x1dc)]();try{const _0x5c3025=this['index']['attachments'][_0x5a0cd8];if(!_0x5c3025)return null;const _0x23961c=a0_0x5c1fed[_0x3f83e4(0x1cc)](ATTACHMENTS_DIR,_0x5c3025[_0x3f83e4(0x1d6)],_0x5a0cd8,'metadata.json'),_0x3db806=await this['fileProcessor'][_0x3f83e4(0x1e0)](_0x23961c);if(!_0x3db806)return this[_0x3f83e4(0x1df)]?.['warn'](_0x3f83e4(0x1be),{'fileId':_0x5a0cd8}),null;const _0x39aed2=await this['fileProcessor']['readFile'](_0x23961c,_0x3f83e4(0x1f6));return JSON['parse'](_0x39aed2);}catch(_0x937317){return this['logger']?.[_0x3f83e4(0x1cf)]('Error\x20getting\x20attachment',{'fileId':_0x5a0cd8,'error':_0x937317[_0x3f83e4(0x1f9)]}),null;}}async['getAttachmentContent'](_0xcc7f86){const _0x3bf9a1=a0_0x31774b;try{const _0x40c515=await this[_0x3bf9a1(0x1bf)](_0xcc7f86);if(!_0x40c515||_0x40c515['mode']!=='content')return null;const _0x2e5101=a0_0x5c1fed[_0x3bf9a1(0x1cc)](ATTACHMENTS_DIR,_0x40c515['agentId'],_0xcc7f86,_0x40c515['contentFileName']),_0x1a79d1=await this['fileProcessor']['fileExists'](_0x2e5101);if(!_0x1a79d1)return null;return await this['fileProcessor']['readFile'](_0x2e5101,'utf8');}catch(_0x254dab){return this[_0x3bf9a1(0x1df)]?.['error']('Error\x20getting\x20attachment\x20content',{'fileId':_0xcc7f86,'error':_0x254dab['message']}),null;}}async['toggleActive'](_0x45550e){const _0x3286b2=a0_0x31774b;try{const _0x501776=await this[_0x3286b2(0x1bf)](_0x45550e);if(!_0x501776)throw new Error('Attachment\x20not\x20found:\x20'+_0x45550e);_0x501776['active']=!_0x501776['active'],_0x501776[_0x3286b2(0x1c2)]=new Date()[_0x3286b2(0x1f0)]();const _0xa3efc5=a0_0x5c1fed[_0x3286b2(0x1cc)](ATTACHMENTS_DIR,_0x501776[_0x3286b2(0x1d6)],_0x45550e,'metadata.json');return await this['fileProcessor']['writeFile'](_0xa3efc5,JSON[_0x3286b2(0x1db)](_0x501776,null,0x2),'utf8'),this['index']['attachments'][_0x45550e]&&(this[_0x3286b2(0x1d8)][_0x3286b2(0x1d5)][_0x45550e][_0x3286b2(0x1c8)]=_0x501776['active'],await this['saveIndex']()),this['logger']?.['info']('Attachment\x20active\x20state\x20toggled',{'fileId':_0x45550e,'active':_0x501776['active']}),_0x501776;}catch(_0x37f951){this[_0x3286b2(0x1df)]?.[_0x3286b2(0x1cf)](_0x3286b2(0x1c5),{'fileId':_0x45550e,'error':_0x37f951['message']});throw _0x37f951;}}async[a0_0x31774b(0x1ca)](_0x21290a,_0x300362){const _0x430570=a0_0x31774b;try{const _0x3bc55e=await this[_0x430570(0x1bf)](_0x21290a);if(!_0x3bc55e)throw new Error(_0x430570(0x204)+_0x21290a);const _0x153b2f=['fileName','active'];for(const _0x13495e of _0x153b2f){_0x300362[_0x13495e]!==undefined&&(_0x3bc55e[_0x13495e]=_0x300362[_0x13495e]);}_0x3bc55e['lastModified']=new Date()['toISOString']();const _0x3890e3=a0_0x5c1fed['join'](ATTACHMENTS_DIR,_0x3bc55e[_0x430570(0x1d6)],_0x21290a,'metadata.json');return await this[_0x430570(0x1d2)][_0x430570(0x1d4)](_0x3890e3,JSON[_0x430570(0x1db)](_0x3bc55e,null,0x2),_0x430570(0x1f6)),this[_0x430570(0x1d8)][_0x430570(0x1d5)][_0x21290a]&&(_0x300362['fileName']&&(this['index']['attachments'][_0x21290a]['fileName']=_0x300362['fileName']),_0x300362['active']!==undefined&&(this[_0x430570(0x1d8)][_0x430570(0x1d5)][_0x21290a][_0x430570(0x1c8)]=_0x300362[_0x430570(0x1c8)]),await this[_0x430570(0x1ee)]()),this[_0x430570(0x1df)]?.[_0x430570(0x1f3)](_0x430570(0x1e9),{'fileId':_0x21290a,'updates':_0x300362}),_0x3bc55e;}catch(_0x2ca493){this['logger']?.['error'](_0x430570(0x1ec),{'fileId':_0x21290a,'error':_0x2ca493[_0x430570(0x1f9)]});throw _0x2ca493;}}async['deleteAttachment'](_0x56dc97,_0x4aefbe){const _0x2f4d91=a0_0x31774b;try{const _0xb2b144=await this[_0x2f4d91(0x1bf)](_0x56dc97);if(!_0xb2b144)throw new Error(_0x2f4d91(0x204)+_0x56dc97);_0xb2b144[_0x2f4d91(0x1de)]=_0xb2b144[_0x2f4d91(0x1de)][_0x2f4d91(0x1d3)](_0x14c9ca=>_0x14c9ca!==_0x4aefbe);if(_0xb2b144['referencedBy']['length']>0x0){const _0x41a595=a0_0x5c1fed[_0x2f4d91(0x1cc)](ATTACHMENTS_DIR,_0xb2b144[_0x2f4d91(0x1d6)],_0x56dc97,_0x2f4d91(0x1d0));return await this[_0x2f4d91(0x1d2)][_0x2f4d91(0x1d4)](_0x41a595,JSON[_0x2f4d91(0x1db)](_0xb2b144,null,0x2),_0x2f4d91(0x1f6)),this[_0x2f4d91(0x1d8)]['attachments'][_0x56dc97]&&(this[_0x2f4d91(0x1d8)][_0x2f4d91(0x1d5)][_0x56dc97][_0x2f4d91(0x1de)]=_0xb2b144['referencedBy']),this[_0x2f4d91(0x1d8)][_0x2f4d91(0x1fd)][_0x4aefbe]&&(this['index'][_0x2f4d91(0x1fd)][_0x4aefbe]=this['index'][_0x2f4d91(0x1fd)][_0x4aefbe]['filter'](_0x7521d3=>_0x7521d3!==_0x56dc97)),await this[_0x2f4d91(0x1ee)](),this['logger']?.[_0x2f4d91(0x1f3)]('Attachment\x20dereferenced',{'fileId':_0x56dc97,'agentId':_0x4aefbe,'remainingRefs':_0xb2b144[_0x2f4d91(0x1de)][_0x2f4d91(0x200)]}),![];}const _0x11cb30=a0_0x5c1fed[_0x2f4d91(0x1cc)](ATTACHMENTS_DIR,_0xb2b144[_0x2f4d91(0x1d6)],_0x56dc97);return await this[_0x2f4d91(0x1d2)]['deleteDirectory'](_0x11cb30),delete this['index'][_0x2f4d91(0x1d5)][_0x56dc97],this[_0x2f4d91(0x1d8)]['agentRefs'][_0x4aefbe]&&(this['index'][_0x2f4d91(0x1fd)][_0x4aefbe]=this['index']['agentRefs'][_0x4aefbe]['filter'](_0xb0fa00=>_0xb0fa00!==_0x56dc97)),await this['saveIndex'](),this[_0x2f4d91(0x1df)]?.[_0x2f4d91(0x1f3)]('Attachment\x20deleted',{'fileId':_0x56dc97,'agentId':_0x4aefbe}),!![];}catch(_0x153455){this['logger']?.[_0x2f4d91(0x1cf)](_0x2f4d91(0x1f2),{'fileId':_0x56dc97,'agentId':_0x4aefbe,'error':_0x153455[_0x2f4d91(0x1f9)]});throw _0x153455;}}async[a0_0x31774b(0x1dd)](_0x1d0904){const _0x57289b=a0_0x31774b;try{const _0x232887=this[_0x57289b(0x1d8)][_0x57289b(0x1fd)][_0x1d0904]||[];let _0x19b28e=0x0,_0x2c6b99=0x0;for(const _0x1800e7 of _0x232887){const _0xa746bc=await this[_0x57289b(0x1ef)](_0x1800e7,_0x1d0904);_0xa746bc?_0x19b28e++:_0x2c6b99++;}return this[_0x57289b(0x1df)]?.[_0x57289b(0x1f3)]('Agent\x20attachments\x20deleted',{'agentId':_0x1d0904,'deleted':_0x19b28e,'dereferenced':_0x2c6b99}),{'deleted':_0x19b28e,'dereferenced':_0x2c6b99};}catch(_0x48ffbc){this[_0x57289b(0x1df)]?.[_0x57289b(0x1cf)](_0x57289b(0x1e5),{'agentId':_0x1d0904,'error':_0x48ffbc[_0x57289b(0x1f9)]});throw _0x48ffbc;}}async['importFromAgent'](_0x2daa83,_0x18b58c){const _0x122c55=a0_0x31774b;try{const _0x44328d=await this[_0x122c55(0x1bf)](_0x2daa83);if(!_0x44328d)throw new Error(_0x122c55(0x1bc)+_0x2daa83);!_0x44328d['referencedBy']['includes'](_0x18b58c)&&_0x44328d[_0x122c55(0x1de)][_0x122c55(0x1e8)](_0x18b58c);_0x44328d['lastModified']=new Date()[_0x122c55(0x1f0)](),_0x44328d['importedFrom']=_0x44328d['agentId'];const _0x5b7b9d=a0_0x5c1fed[_0x122c55(0x1cc)](ATTACHMENTS_DIR,_0x44328d[_0x122c55(0x1d6)],_0x2daa83,_0x122c55(0x1d0));return await this[_0x122c55(0x1d2)]['writeFile'](_0x5b7b9d,JSON[_0x122c55(0x1db)](_0x44328d,null,0x2),'utf8'),this[_0x122c55(0x1d8)]['attachments'][_0x2daa83]&&(this['index'][_0x122c55(0x1d5)][_0x2daa83][_0x122c55(0x1de)]=_0x44328d[_0x122c55(0x1de)]),!this['index'][_0x122c55(0x1fd)][_0x18b58c]&&(this[_0x122c55(0x1d8)][_0x122c55(0x1fd)][_0x18b58c]=[]),!this['index'][_0x122c55(0x1fd)][_0x18b58c]['includes'](_0x2daa83)&&this[_0x122c55(0x1d8)][_0x122c55(0x1fd)][_0x18b58c]['push'](_0x2daa83),await this['saveIndex'](),this[_0x122c55(0x1df)]?.['info']('Attachment imported',{'sourceFileId':_0x2daa83,'targetAgentId':_0x18b58c}),_0x44328d;}catch(_0x467b3a){this[_0x122c55(0x1df)]?.[_0x122c55(0x1cf)]('Error importing attachment',{'sourceFileId':_0x2daa83,'targetAgentId':_0x18b58c,'error':_0x467b3a[_0x122c55(0x1f9)]});throw _0x467b3a;}}async['getActiveAttachments'](_0x5e43a4){const _0x5ab3a5=a0_0x31774b;return await this[_0x5ab3a5(0x1f8)](_0x5e43a4,{'active':!![]});}async[a0_0x31774b(0x1f1)](_0x16f686){const _0xe11fec=a0_0x31774b;try{const _0x3396f4=await this['getAttachmentContent'](_0x16f686);if(!_0x3396f4)return null;if(_0x3396f4[_0xe11fec(0x1cb)]('data:image'))return _0xe11fec(0x1c7);return _0x3396f4['length']>0x3e8?_0x3396f4[_0xe11fec(0x1d7)](0x0,0x3e8)+_0xe11fec(0x1c4):_0x3396f4;}catch(_0x32d47f){return this['logger']?.[_0xe11fec(0x1cf)](_0xe11fec(0x1cd),{'fileId':_0x16f686,'error':_0x32d47f[_0xe11fec(0x1f9)]}),null;}}}export default FileAttachmentService;
|