@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.3

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.
Files changed (120) hide show
  1. package/README.md +44 -54
  2. package/bin/cli.js +1 -115
  3. package/bin/loxia-terminal-v2.js +3 -0
  4. package/bin/loxia-terminal.js +3 -0
  5. package/bin/start-with-terminal.js +3 -0
  6. package/package.json +14 -15
  7. package/scripts/install-scanners.js +1 -235
  8. package/src/analyzers/CSSAnalyzer.js +1 -297
  9. package/src/analyzers/ConfigValidator.js +1 -690
  10. package/src/analyzers/ESLintAnalyzer.js +1 -320
  11. package/src/analyzers/JavaScriptAnalyzer.js +1 -261
  12. package/src/analyzers/PrettierFormatter.js +1 -247
  13. package/src/analyzers/PythonAnalyzer.js +1 -266
  14. package/src/analyzers/SecurityAnalyzer.js +1 -729
  15. package/src/analyzers/TypeScriptAnalyzer.js +1 -247
  16. package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
  17. package/src/analyzers/codeCloneDetector/detector.js +1 -203
  18. package/src/analyzers/codeCloneDetector/index.js +1 -160
  19. package/src/analyzers/codeCloneDetector/parser.js +1 -199
  20. package/src/analyzers/codeCloneDetector/reporter.js +1 -148
  21. package/src/analyzers/codeCloneDetector/scanner.js +1 -59
  22. package/src/core/agentPool.js +1 -1474
  23. package/src/core/agentScheduler.js +1 -2147
  24. package/src/core/contextManager.js +1 -709
  25. package/src/core/messageProcessor.js +1 -732
  26. package/src/core/orchestrator.js +1 -548
  27. package/src/core/stateManager.js +1 -877
  28. package/src/index.js +1 -631
  29. package/src/interfaces/cli.js +1 -549
  30. package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
  31. package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
  32. package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
  33. package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
  34. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
  35. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
  36. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
  37. package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
  38. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
  39. package/src/interfaces/terminal/api/apiClient.js +1 -0
  40. package/src/interfaces/terminal/api/messageRouter.js +1 -0
  41. package/src/interfaces/terminal/api/session.js +1 -0
  42. package/src/interfaces/terminal/api/websocket.js +1 -0
  43. package/src/interfaces/terminal/components/AgentCreator.js +1 -0
  44. package/src/interfaces/terminal/components/AgentEditor.js +1 -0
  45. package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
  46. package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
  47. package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
  48. package/src/interfaces/terminal/components/Header.js +1 -0
  49. package/src/interfaces/terminal/components/HelpPanel.js +1 -0
  50. package/src/interfaces/terminal/components/InputBox.js +1 -0
  51. package/src/interfaces/terminal/components/Layout.js +1 -0
  52. package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
  53. package/src/interfaces/terminal/components/MessageList.js +1 -0
  54. package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
  55. package/src/interfaces/terminal/components/SearchPanel.js +1 -0
  56. package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
  57. package/src/interfaces/terminal/components/StatusBar.js +1 -0
  58. package/src/interfaces/terminal/components/TextInput.js +1 -0
  59. package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
  60. package/src/interfaces/terminal/config/constants.js +1 -0
  61. package/src/interfaces/terminal/index.js +1 -0
  62. package/src/interfaces/terminal/state/useAgentControl.js +1 -0
  63. package/src/interfaces/terminal/state/useAgents.js +1 -0
  64. package/src/interfaces/terminal/state/useConnection.js +1 -0
  65. package/src/interfaces/terminal/state/useMessages.js +1 -0
  66. package/src/interfaces/terminal/state/useTools.js +1 -0
  67. package/src/interfaces/terminal/utils/debugLogger.js +1 -0
  68. package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
  69. package/src/interfaces/terminal/utils/theme.js +1 -0
  70. package/src/interfaces/webServer.js +1 -2162
  71. package/src/modules/fileExplorer/controller.js +1 -280
  72. package/src/modules/fileExplorer/index.js +1 -37
  73. package/src/modules/fileExplorer/middleware.js +1 -92
  74. package/src/modules/fileExplorer/routes.js +1 -125
  75. package/src/modules/fileExplorer/types.js +1 -44
  76. package/src/services/aiService.js +1 -1232
  77. package/src/services/apiKeyManager.js +1 -164
  78. package/src/services/benchmarkService.js +1 -366
  79. package/src/services/budgetService.js +1 -539
  80. package/src/services/contextInjectionService.js +1 -247
  81. package/src/services/conversationCompactionService.js +1 -637
  82. package/src/services/errorHandler.js +1 -810
  83. package/src/services/fileAttachmentService.js +1 -544
  84. package/src/services/modelRouterService.js +1 -366
  85. package/src/services/modelsService.js +1 -322
  86. package/src/services/qualityInspector.js +1 -796
  87. package/src/services/tokenCountingService.js +1 -536
  88. package/src/tools/agentCommunicationTool.js +1 -1344
  89. package/src/tools/agentDelayTool.js +1 -485
  90. package/src/tools/asyncToolManager.js +1 -604
  91. package/src/tools/baseTool.js +1 -800
  92. package/src/tools/browserTool.js +1 -920
  93. package/src/tools/cloneDetectionTool.js +1 -621
  94. package/src/tools/dependencyResolverTool.js +1 -1215
  95. package/src/tools/fileContentReplaceTool.js +1 -875
  96. package/src/tools/fileSystemTool.js +1 -1107
  97. package/src/tools/fileTreeTool.js +1 -853
  98. package/src/tools/imageTool.js +1 -901
  99. package/src/tools/importAnalyzerTool.js +1 -1060
  100. package/src/tools/jobDoneTool.js +1 -248
  101. package/src/tools/seekTool.js +1 -956
  102. package/src/tools/staticAnalysisTool.js +1 -1778
  103. package/src/tools/taskManagerTool.js +1 -2873
  104. package/src/tools/terminalTool.js +1 -2304
  105. package/src/tools/webTool.js +1 -1430
  106. package/src/types/agent.js +1 -519
  107. package/src/types/contextReference.js +1 -972
  108. package/src/types/conversation.js +1 -730
  109. package/src/types/toolCommand.js +1 -747
  110. package/src/utilities/attachmentValidator.js +1 -292
  111. package/src/utilities/configManager.js +1 -582
  112. package/src/utilities/constants.js +1 -722
  113. package/src/utilities/directoryAccessManager.js +1 -535
  114. package/src/utilities/fileProcessor.js +1 -307
  115. package/src/utilities/logger.js +1 -436
  116. package/src/utilities/tagParser.js +1 -1246
  117. package/src/utilities/toolConstants.js +1 -317
  118. package/web-ui/build/index.html +2 -2
  119. package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
  120. package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
@@ -1,875 +1 @@
1
- /**
2
- * FileContentReplaceTool - Replace specific content within files
3
- *
4
- * Purpose:
5
- * - Replace text content in files with precision
6
- * - Support line-limited replacements
7
- * - Handle whitespace intelligently with trim modes
8
- * - Create backups before modifications
9
- * - Generate diff reports
10
- * - Support multi-file operations
11
- */
12
-
13
- import { BaseTool } from './baseTool.js';
14
- import { promises as fs } from 'fs';
15
- import path from 'path';
16
-
17
- // Configuration constants
18
- const REPLACE_CONFIG = {
19
- // File size limits
20
- MAX_FILE_SIZE: 10 * 1024 * 1024, // 10MB max file size
21
- MAX_OLD_CONTENT_SIZE: 100 * 1024, // 100KB max old content
22
- MAX_NEW_CONTENT_SIZE: 100 * 1024, // 100KB max new content
23
-
24
- // Operation limits
25
- MAX_REPLACEMENTS_PER_FILE: 1000, // Max replacements in single file
26
- MAX_FILES_PER_OPERATION: 50, // Max files in one operation
27
- MAX_LINE_RANGE_SIZE: 10000, // Max lines in a range
28
-
29
- // Backup settings
30
- CREATE_BACKUPS: true,
31
- BACKUP_EXTENSION: '.bak',
32
-
33
- // Diff settings
34
- DIFF_CONTEXT_LINES: 3, // Lines of context in diff
35
- MAX_DIFF_LINES: 100, // Max lines to show in diff
36
-
37
- // Default settings
38
- DEFAULT_TRIM_MODE: 'trim'
39
- };
40
-
41
- class FileContentReplaceTool extends BaseTool {
42
- constructor(config = {}, logger = null) {
43
- super(config, logger);
44
-
45
- // Tool metadata
46
- this.requiresProject = true;
47
- this.isAsync = true;
48
- this.timeout = config.timeout || 120000; // 2 minutes default
49
-
50
- // Merge config with defaults
51
- this.replaceConfig = {
52
- ...REPLACE_CONFIG,
53
- ...config.replaceConfig
54
- };
55
- }
56
-
57
- /**
58
- * Get tool description for LLM consumption
59
- * @returns {string} Tool description
60
- */
61
- getDescription() {
62
- return `
63
- File Content Replace Tool: Replace specific content within files with precision.
64
-
65
- XML USAGE:
66
- <file-content-replace>
67
- <file path="src/app.js">
68
- <replace mode="trim" lines-limit="5,7-10">
69
- <old-content>
70
- const oldFunction = () => {
71
- console.log('old');
72
- }
73
- </old-content>
74
- <new-content>
75
- const newFunction = () => {
76
- console.log('new');
77
- }
78
- </new-content>
79
- </replace>
80
- </file>
81
- </file-content-replace>
82
-
83
- JSON USAGE:
84
- \`\`\`json
85
- {
86
- "toolId": "file-content-replace",
87
- "files": [
88
- {
89
- "path": "src/app.js",
90
- "replacements": [
91
- {
92
- "oldContent": "const oldFunction = () => {}",
93
- "newContent": "const newFunction = () => {}",
94
- "mode": "trim",
95
- "linesLimit": "5,7-10"
96
- }
97
- ]
98
- }
99
- ]
100
- }
101
- \`\`\`
102
-
103
- PARAMETERS:
104
-
105
- path (required):
106
- - Path to the file to modify
107
- - Can be relative or absolute
108
- - Examples: "src/app.js", "./config.json"
109
-
110
- oldContent (required):
111
- - Content to find and replace
112
- - Subject to trim mode processing
113
- - Must exist in file
114
-
115
- newContent (required):
116
- - Replacement content
117
- - Subject to trim mode processing
118
- - Can be same length, shorter, or longer
119
-
120
- mode (optional):
121
- - Whitespace handling mode
122
- - Options:
123
- * "trim" (default): Trim all whitespace from both ends
124
- * "newlines": Only trim newline characters
125
- * "none": Use content exactly as provided
126
- - Helps with matching despite indentation differences
127
-
128
- linesLimit (optional):
129
- - Restrict replacement to specific lines
130
- - Format: Comma-separated line numbers or ranges
131
- - Examples:
132
- * "5" - Only line 5
133
- * "5,10,15" - Lines 5, 10, and 15
134
- * "5-10" - Lines 5 through 10
135
- * "1-5,10,15-20" - Lines 1-5, 10, and 15-20
136
- - Line numbers are 1-based
137
-
138
- TRIM MODES EXPLAINED:
139
-
140
- Mode: "trim" (Recommended for most cases)
141
- Input:
142
- " const x = 1; \\n"
143
- After trim:
144
- "const x = 1;"
145
- Use when: Indentation may vary
146
-
147
- Mode: "newlines"
148
- Input:
149
- "\\n const x = 1; \\n"
150
- After trim:
151
- " const x = 1; "
152
- Use when: Preserving internal whitespace
153
-
154
- Mode: "none"
155
- Input:
156
- " const x = 1; \\n"
157
- After trim:
158
- " const x = 1; \\n"
159
- Use when: Exact character match needed
160
-
161
- EXAMPLES:
162
-
163
- Example 1 - Basic replacement with trim:
164
- <file-content-replace>
165
- <file path="src/components/Button.js">
166
- <replace mode="trim">
167
- <old-content>
168
- const handleClick = (event) => {
169
- console.log('clicked');
170
- }
171
- </old-content>
172
- <new-content>
173
- const handleClick = (event) => {
174
- console.log('clicked');
175
- props.onClick?.(event);
176
- }
177
- </new-content>
178
- </replace>
179
- </file>
180
- </file-content-replace>
181
-
182
- Example 2 - Line-limited replacement:
183
- <file-content-replace>
184
- <file path="src/App.js">
185
- <replace lines-limit="10-20">
186
- <old-content>const API_URL = 'http://localhost:3000'</old-content>
187
- <new-content>const API_URL = process.env.API_URL</new-content>
188
- </replace>
189
- </file>
190
- </file-content-replace>
191
-
192
- Example 3 - Multiple replacements in one file:
193
- <file-content-replace>
194
- <file path="src/config.js">
195
- <replace>
196
- <old-content>DEBUG = false</old-content>
197
- <new-content>DEBUG = true</new-content>
198
- </replace>
199
- <replace>
200
- <old-content>LOG_LEVEL = 'error'</old-content>
201
- <new-content>LOG_LEVEL = 'debug'</new-content>
202
- </replace>
203
- </file>
204
- </file-content-replace>
205
-
206
- Example 4 - Multiple files:
207
- <file-content-replace>
208
- <file path="src/app.js">
209
- <replace>
210
- <old-content>version = '1.0.0'</old-content>
211
- <new-content>version = '1.1.0'</new-content>
212
- </replace>
213
- </file>
214
- <file path="package.json">
215
- <replace mode="none">
216
- <old-content>"version": "1.0.0"</old-content>
217
- <new-content>"version": "1.1.0"</new-content>
218
- </replace>
219
- </file>
220
- </file-content-replace>
221
-
222
- Example 5 - Exact whitespace matching:
223
- <file-content-replace>
224
- <file path="Makefile">
225
- <replace mode="none">
226
- <old-content>\\tbuild:\\n\\t\\tgcc</old-content>
227
- <new-content>\\tbuild:\\n\\t\\tclang</new-content>
228
- </replace>
229
- </file>
230
- </file-content-replace>
231
-
232
- FEATURES:
233
-
234
- ✓ Automatic backup creation (.bak files)
235
- ✓ Before/after diff reports
236
- ✓ Replacement counting and statistics
237
- ✓ Multi-file operations
238
- ✓ Line-limited replacements
239
- ✓ Intelligent whitespace handling
240
- ✓ Security validation (path access)
241
- ✓ Creates parent directories if needed
242
-
243
- LIMITATIONS:
244
-
245
- - Maximum file size: ${REPLACE_CONFIG.MAX_FILE_SIZE / (1024 * 1024)}MB
246
- - Maximum old content size: ${REPLACE_CONFIG.MAX_OLD_CONTENT_SIZE / 1024}KB
247
- - Maximum new content size: ${REPLACE_CONFIG.MAX_NEW_CONTENT_SIZE / 1024}KB
248
- - Maximum replacements per file: ${REPLACE_CONFIG.MAX_REPLACEMENTS_PER_FILE}
249
- - Maximum files per operation: ${REPLACE_CONFIG.MAX_FILES_PER_OPERATION}
250
-
251
- NOTES:
252
-
253
- - Use the seek tool first to verify content exists
254
- - Backups are created automatically (.bak extension)
255
- - Replacements are case-sensitive
256
- - Old content must match exactly (after trim mode applied)
257
- - Multiple occurrences are all replaced unless linesLimit specified
258
- - Tool validates paths against agent's accessible directories
259
-
260
- MULTI-DIRECTORY SUPPORT:
261
-
262
- Works with agent's configured accessible directories.
263
- Validates paths against directoryAccess configuration.
264
- `;
265
- }
266
-
267
- /**
268
- * Parse parameters from tool command content
269
- * @param {string} content - Raw tool command content
270
- * @returns {Object} Parsed parameters
271
- */
272
- parseParameters(content) {
273
- try {
274
- // Try JSON first
275
- if (content.trim().startsWith('{')) {
276
- return this.parseJSON(content);
277
- }
278
-
279
- // Otherwise parse XML
280
- return this.parseXML(content);
281
- } catch (error) {
282
- this.logger?.error('Failed to parse file-content-replace parameters', {
283
- error: error.message
284
- });
285
- throw new Error(`Parameter parsing failed: ${error.message}`);
286
- }
287
- }
288
-
289
- /**
290
- * Parse JSON format
291
- * @param {string} content - JSON string
292
- * @returns {Object} Parsed parameters
293
- */
294
- parseJSON(content) {
295
- const parsed = JSON.parse(content);
296
-
297
- if (!parsed.files || !Array.isArray(parsed.files)) {
298
- throw new Error('JSON must have "files" array');
299
- }
300
-
301
- return {
302
- files: parsed.files.map(file => ({
303
- path: file.path,
304
- replacements: (file.replacements || []).map(r => ({
305
- oldContent: r.oldContent,
306
- newContent: r.newContent,
307
- mode: r.mode || REPLACE_CONFIG.DEFAULT_TRIM_MODE,
308
- linesLimit: r.linesLimit || null
309
- }))
310
- }))
311
- };
312
- }
313
-
314
- /**
315
- * Parse XML format
316
- * @param {string} content - XML string
317
- * @returns {Object} Parsed parameters
318
- */
319
- parseXML(content) {
320
- const files = [];
321
-
322
- // Extract <file> tags
323
- const filePattern = /<file\s+path="([^"]+)">([\s\S]*?)<\/file>/gi;
324
- let fileMatch;
325
-
326
- while ((fileMatch = filePattern.exec(content)) !== null) {
327
- const filePath = fileMatch[1];
328
- const fileContent = fileMatch[2];
329
-
330
- const replacements = [];
331
-
332
- // Extract <replace> tags within this file
333
- const replacePattern = /<replace(?:\s+([^>]*?))?>([\s\S]*?)<\/replace>/gi;
334
- let replaceMatch;
335
-
336
- while ((replaceMatch = replacePattern.exec(fileContent)) !== null) {
337
- const attributes = replaceMatch[1] || '';
338
- const replaceContent = replaceMatch[2];
339
-
340
- // Parse attributes
341
- const mode = this.extractAttribute(attributes, 'mode') || REPLACE_CONFIG.DEFAULT_TRIM_MODE;
342
- const linesLimit = this.extractAttribute(attributes, 'lines-limit');
343
-
344
- // Extract old-content
345
- const oldContentMatch = /<old-content>([\s\S]*?)<\/old-content>/i.exec(replaceContent);
346
- if (!oldContentMatch) {
347
- this.logger?.warn('Missing old-content in replace tag');
348
- continue;
349
- }
350
- const oldContentRaw = oldContentMatch[1];
351
-
352
- // Extract new-content
353
- const newContentMatch = /<new-content>([\s\S]*?)<\/new-content>/i.exec(replaceContent);
354
- if (!newContentMatch) {
355
- this.logger?.warn('Missing new-content in replace tag');
356
- continue;
357
- }
358
- const newContentRaw = newContentMatch[1];
359
-
360
- // Apply trim mode
361
- const oldContent = this.applyTrimMode(oldContentRaw, mode);
362
- const newContent = this.applyTrimMode(newContentRaw, mode);
363
-
364
- replacements.push({
365
- oldContent,
366
- newContent,
367
- mode,
368
- linesLimit
369
- });
370
- }
371
-
372
- if (replacements.length > 0) {
373
- files.push({
374
- path: filePath,
375
- replacements
376
- });
377
- }
378
- }
379
-
380
- return { files };
381
- }
382
-
383
- /**
384
- * Extract attribute value from attribute string
385
- * @param {string} attributes - Attribute string
386
- * @param {string} name - Attribute name
387
- * @returns {string|null} Attribute value
388
- */
389
- extractAttribute(attributes, name) {
390
- const pattern = new RegExp(`${name}=["']([^"']*)["']`, 'i');
391
- const match = pattern.exec(attributes);
392
- return match ? match[1] : null;
393
- }
394
-
395
- /**
396
- * Apply trim mode to content
397
- * @param {string} content - Content to process
398
- * @param {string} mode - Trim mode
399
- * @returns {string} Processed content
400
- */
401
- applyTrimMode(content, mode) {
402
- switch (mode) {
403
- case 'newlines':
404
- return content.replace(/^\n+|\n+$/g, '');
405
- case 'none':
406
- return content;
407
- case 'trim':
408
- default:
409
- return content.trim();
410
- }
411
- }
412
-
413
- /**
414
- * Get required parameters
415
- * @returns {Array<string>} Array of required parameter names
416
- */
417
- getRequiredParameters() {
418
- return ['files'];
419
- }
420
-
421
- /**
422
- * Custom parameter validation
423
- * @param {Object} params - Parameters to validate
424
- * @returns {Object} Validation result
425
- */
426
- customValidateParameters(params) {
427
- const errors = [];
428
-
429
- // Validate files array
430
- if (!params.files || !Array.isArray(params.files)) {
431
- errors.push('files must be an array');
432
- } else {
433
- if (params.files.length === 0) {
434
- errors.push('files array cannot be empty');
435
- }
436
-
437
- if (params.files.length > this.replaceConfig.MAX_FILES_PER_OPERATION) {
438
- errors.push(`Cannot process more than ${this.replaceConfig.MAX_FILES_PER_OPERATION} files in one operation`);
439
- }
440
-
441
- // Validate each file
442
- for (const file of params.files) {
443
- if (!file.path) {
444
- errors.push('Each file must have a path');
445
- }
446
-
447
- // Check for path traversal
448
- if (file.path && file.path.includes('..')) {
449
- errors.push(`Path traversal (..) not allowed for security: ${file.path}`);
450
- }
451
-
452
- if (!file.replacements || !Array.isArray(file.replacements)) {
453
- errors.push(`File ${file.path} must have replacements array`);
454
- } else if (file.replacements.length === 0) {
455
- errors.push(`File ${file.path} replacements array cannot be empty`);
456
- } else {
457
- // Validate each replacement
458
- for (const replacement of file.replacements) {
459
- if (!replacement.oldContent && replacement.oldContent !== '') {
460
- errors.push(`Replacement in ${file.path} missing oldContent`);
461
- }
462
-
463
- if (!replacement.newContent && replacement.newContent !== '') {
464
- errors.push(`Replacement in ${file.path} missing newContent`);
465
- }
466
-
467
- // Validate content sizes
468
- if (replacement.oldContent && replacement.oldContent.length > this.replaceConfig.MAX_OLD_CONTENT_SIZE) {
469
- errors.push(`oldContent too large (max ${this.replaceConfig.MAX_OLD_CONTENT_SIZE / 1024}KB)`);
470
- }
471
-
472
- if (replacement.newContent && replacement.newContent.length > this.replaceConfig.MAX_NEW_CONTENT_SIZE) {
473
- errors.push(`newContent too large (max ${this.replaceConfig.MAX_NEW_CONTENT_SIZE / 1024}KB)`);
474
- }
475
-
476
- // Validate mode
477
- if (replacement.mode && !['trim', 'newlines', 'none'].includes(replacement.mode)) {
478
- errors.push(`Invalid mode: ${replacement.mode}. Must be 'trim', 'newlines', or 'none'`);
479
- }
480
- }
481
- }
482
- }
483
- }
484
-
485
- // Throw error if validation fails
486
- if (errors.length > 0) {
487
- throw new Error(`Parameter validation failed: ${errors.join(', ')}`);
488
- }
489
-
490
- return {
491
- valid: true,
492
- errors: []
493
- };
494
- }
495
-
496
- /**
497
- * Execute tool with parsed parameters
498
- * @param {Object} params - Parsed parameters
499
- * @param {Object} context - Execution context
500
- * @returns {Promise<Object>} Execution result
501
- */
502
- async execute(params, context) {
503
- const { files } = params;
504
- const { projectDir, agentId, directoryAccess } = context;
505
-
506
- // Determine working directory (respect multi-directory access)
507
- let workingDirectory = projectDir || process.cwd();
508
-
509
- if (directoryAccess && directoryAccess.workingDirectory) {
510
- workingDirectory = directoryAccess.workingDirectory;
511
- this.logger?.info('Using agent configured working directory', {
512
- workingDirectory: directoryAccess.workingDirectory,
513
- agentId
514
- });
515
- }
516
-
517
- this.logger?.info('Executing file content replace', {
518
- fileCount: files.length,
519
- workingDirectory,
520
- agentId
521
- });
522
-
523
- const results = [];
524
- const stats = {
525
- filesProcessed: 0,
526
- filesModified: 0,
527
- totalReplacements: 0,
528
- backupsCreated: 0,
529
- errors: 0
530
- };
531
-
532
- // Process each file
533
- for (const file of files) {
534
- try {
535
- const fileResult = await this.processFile(file, workingDirectory, directoryAccess);
536
- results.push(fileResult);
537
-
538
- stats.filesProcessed++;
539
- if (fileResult.replacementsMade > 0) {
540
- stats.filesModified++;
541
- stats.totalReplacements += fileResult.replacementsMade;
542
- }
543
- if (fileResult.backupCreated) {
544
- stats.backupsCreated++;
545
- }
546
- } catch (error) {
547
- this.logger?.error(`Error processing file ${file.path}`, { error: error.message });
548
- results.push({
549
- filePath: file.path,
550
- success: false,
551
- error: error.message
552
- });
553
- stats.errors++;
554
- }
555
- }
556
-
557
- return {
558
- success: stats.errors === 0,
559
- results,
560
- statistics: stats,
561
- summary: this.generateSummary(stats),
562
- toolUsed: 'file-content-replace'
563
- };
564
- }
565
-
566
- /**
567
- * Process a single file
568
- * @param {Object} file - File object with path and replacements
569
- * @param {string} workingDirectory - Working directory
570
- * @param {Object} directoryAccess - Directory access config
571
- * @returns {Promise<Object>} File processing result
572
- */
573
- async processFile(file, workingDirectory, directoryAccess) {
574
- const { path: filePath, replacements } = file;
575
-
576
- // Resolve path
577
- const resolvedPath = path.isAbsolute(filePath)
578
- ? filePath
579
- : path.resolve(workingDirectory, filePath);
580
-
581
- // Validate path access (if directoryAccess provided)
582
- if (directoryAccess) {
583
- const accessible = this.isPathAccessible(resolvedPath, workingDirectory, directoryAccess);
584
- if (!accessible) {
585
- throw new Error(`Path not accessible: ${filePath}`);
586
- }
587
- }
588
-
589
- // Check file exists
590
- try {
591
- await fs.access(resolvedPath);
592
- } catch (error) {
593
- throw new Error(`File not found: ${filePath}`);
594
- }
595
-
596
- // Check file size
597
- const stats = await fs.stat(resolvedPath);
598
- if (stats.size > this.replaceConfig.MAX_FILE_SIZE) {
599
- throw new Error(`File too large (max ${this.replaceConfig.MAX_FILE_SIZE / (1024 * 1024)}MB): ${filePath}`);
600
- }
601
-
602
- // Read file content
603
- let content = await fs.readFile(resolvedPath, 'utf-8');
604
- const originalContent = content;
605
-
606
- // Create backup
607
- let backupCreated = false;
608
- if (this.replaceConfig.CREATE_BACKUPS) {
609
- const backupPath = resolvedPath + this.replaceConfig.BACKUP_EXTENSION;
610
- try {
611
- await fs.writeFile(backupPath, originalContent, 'utf-8');
612
- backupCreated = true;
613
- } catch (error) {
614
- this.logger?.warn(`Failed to create backup: ${error.message}`);
615
- }
616
- }
617
-
618
- // Apply replacements
619
- let replacementsMade = 0;
620
- const replacementDetails = [];
621
-
622
- for (const replacement of replacements) {
623
- const result = await this.applyReplacement(
624
- content,
625
- replacement.oldContent,
626
- replacement.newContent,
627
- replacement.linesLimit,
628
- replacement.mode
629
- );
630
-
631
- content = result.newContent;
632
- replacementsMade += result.count;
633
-
634
- replacementDetails.push({
635
- oldContent: replacement.oldContent.substring(0, 50) + (replacement.oldContent.length > 50 ? '...' : ''),
636
- newContent: replacement.newContent.substring(0, 50) + (replacement.newContent.length > 50 ? '...' : ''),
637
- count: result.count,
638
- mode: replacement.mode,
639
- linesLimit: replacement.linesLimit
640
- });
641
- }
642
-
643
- // Write back if changes were made
644
- if (replacementsMade > 0) {
645
- await fs.writeFile(resolvedPath, content, 'utf-8');
646
- }
647
-
648
- // Generate diff
649
- const diff = replacementsMade > 0
650
- ? this.generateDiff(originalContent, content)
651
- : null;
652
-
653
- return {
654
- filePath,
655
- resolvedPath,
656
- success: true,
657
- replacementsMade,
658
- backupCreated,
659
- replacementDetails,
660
- diff,
661
- message: replacementsMade > 0
662
- ? `Made ${replacementsMade} replacement(s) in ${filePath}`
663
- : `No replacements made in ${filePath} (content not found)`
664
- };
665
- }
666
-
667
- /**
668
- * Check if path is accessible
669
- * @param {string} targetPath - Path to check
670
- * @param {string} workingDirectory - Working directory
671
- * @param {Object} directoryAccess - Directory access config
672
- * @returns {boolean} True if accessible
673
- */
674
- isPathAccessible(targetPath, workingDirectory, directoryAccess) {
675
- // Always allow paths within working directory
676
- const relativeToWorking = path.relative(workingDirectory, targetPath);
677
- if (!relativeToWorking.startsWith('..') && !path.isAbsolute(relativeToWorking)) {
678
- return true;
679
- }
680
-
681
- // Check writeEnabledDirectories
682
- if (directoryAccess.writeEnabledDirectories) {
683
- for (const dir of directoryAccess.writeEnabledDirectories) {
684
- const relative = path.relative(dir, targetPath);
685
- if (!relative.startsWith('..') && !path.isAbsolute(relative)) {
686
- return true;
687
- }
688
- }
689
- }
690
-
691
- return false;
692
- }
693
-
694
- /**
695
- * Apply a single replacement
696
- * @param {string} content - File content
697
- * @param {string} oldContent - Content to replace
698
- * @param {string} newContent - Replacement content
699
- * @param {string|null} linesLimit - Line limit specification
700
- * @param {string} mode - Trim mode
701
- * @returns {Object} Result with newContent and count
702
- */
703
- async applyReplacement(content, oldContent, newContent, linesLimit, mode) {
704
- if (!linesLimit) {
705
- // Replace in entire file (simple string replace, not regex)
706
- const count = this.countOccurrences(content, oldContent);
707
-
708
- if (count === 0) {
709
- return { newContent: content, count: 0 };
710
- }
711
-
712
- // Simple replaceAll
713
- const newFileContent = content.split(oldContent).join(newContent);
714
-
715
- return { newContent: newFileContent, count };
716
- }
717
-
718
- // Line-limited replacement
719
- const lineNumbers = this.parseLineRanges(linesLimit);
720
- const lines = content.split('\n');
721
- let replacementCount = 0;
722
-
723
- // Process each line
724
- for (let i = 0; i < lines.length; i++) {
725
- const lineNumber = i + 1; // 1-based
726
-
727
- if (lineNumbers.has(lineNumber)) {
728
- // Check if this line contains the old content
729
- if (lines[i].includes(oldContent)) {
730
- const occurrencesInLine = this.countOccurrences(lines[i], oldContent);
731
- lines[i] = lines[i].split(oldContent).join(newContent);
732
- replacementCount += occurrencesInLine;
733
- }
734
- }
735
- }
736
-
737
- return {
738
- newContent: lines.join('\n'),
739
- count: replacementCount
740
- };
741
- }
742
-
743
- /**
744
- * Count occurrences of substring in string
745
- * @param {string} str - String to search
746
- * @param {string} substr - Substring to count
747
- * @returns {number} Count of occurrences
748
- */
749
- countOccurrences(str, substr) {
750
- if (!substr) return 0;
751
- return str.split(substr).length - 1;
752
- }
753
-
754
- /**
755
- * Parse line ranges from string like "3,5,7-9"
756
- * @param {string} rangesStr - Line range string
757
- * @returns {Set<number>} Set of line numbers
758
- */
759
- parseLineRanges(rangesStr) {
760
- const result = new Set();
761
-
762
- if (!rangesStr || rangesStr.trim() === '') {
763
- return result;
764
- }
765
-
766
- const ranges = rangesStr.split(',');
767
-
768
- for (const range of ranges) {
769
- const trimmed = range.trim();
770
-
771
- if (trimmed === '') continue;
772
-
773
- // Check if it's a range (e.g., "7-9")
774
- if (trimmed.includes('-')) {
775
- const [start, end] = trimmed.split('-').map(n => parseInt(n.trim(), 10));
776
-
777
- if (!isNaN(start) && !isNaN(end) && end - start < this.replaceConfig.MAX_LINE_RANGE_SIZE) {
778
- for (let i = start; i <= end; i++) {
779
- result.add(i);
780
- }
781
- }
782
- } else {
783
- // Single line number
784
- const lineNum = parseInt(trimmed, 10);
785
- if (!isNaN(lineNum)) {
786
- result.add(lineNum);
787
- }
788
- }
789
- }
790
-
791
- return result;
792
- }
793
-
794
- /**
795
- * Generate diff between original and new content
796
- * @param {string} original - Original content
797
- * @param {string} modified - Modified content
798
- * @returns {string} Diff string
799
- */
800
- generateDiff(original, modified) {
801
- const oldLines = original.split('\n');
802
- const newLines = modified.split('\n');
803
-
804
- // Find first and last lines that differ
805
- let firstDiff = -1;
806
- let lastDiff = -1;
807
-
808
- const maxLines = Math.max(oldLines.length, newLines.length);
809
-
810
- for (let i = 0; i < maxLines; i++) {
811
- const oldLine = i < oldLines.length ? oldLines[i] : '';
812
- const newLine = i < newLines.length ? newLines[i] : '';
813
-
814
- if (oldLine !== newLine) {
815
- if (firstDiff === -1) firstDiff = i;
816
- lastDiff = i;
817
- }
818
- }
819
-
820
- if (firstDiff === -1) return 'No differences';
821
-
822
- // Add context
823
- const contextLines = this.replaceConfig.DIFF_CONTEXT_LINES;
824
- const startLine = Math.max(0, firstDiff - contextLines);
825
- const endLine = Math.min(maxLines - 1, lastDiff + contextLines);
826
-
827
- // Limit total lines shown
828
- if (endLine - startLine > this.replaceConfig.MAX_DIFF_LINES) {
829
- return `Diff too large (${endLine - startLine + 1} lines), showing summary only:\n` +
830
- `Changed lines: ${firstDiff + 1} to ${lastDiff + 1}`;
831
- }
832
-
833
- let diff = `@@ -${startLine + 1},${endLine - startLine + 1} +${startLine + 1},${endLine - startLine + 1} @@\n`;
834
-
835
- for (let i = startLine; i <= endLine; i++) {
836
- const oldLine = i < oldLines.length ? oldLines[i] : '';
837
- const newLine = i < newLines.length ? newLines[i] : '';
838
-
839
- if (oldLine === newLine) {
840
- diff += ` ${oldLine}\n`;
841
- } else {
842
- diff += `- ${oldLine}\n`;
843
- diff += `+ ${newLine}\n`;
844
- }
845
- }
846
-
847
- return diff;
848
- }
849
-
850
- /**
851
- * Generate summary text
852
- * @param {Object} stats - Statistics object
853
- * @returns {string} Summary text
854
- */
855
- generateSummary(stats) {
856
- return `
857
- Processed ${stats.filesProcessed} file(s)
858
- Modified ${stats.filesModified} file(s)
859
- Total replacements: ${stats.totalReplacements}
860
- Backups created: ${stats.backupsCreated}
861
- Errors: ${stats.errors}
862
- `.trim();
863
- }
864
-
865
- /**
866
- * Resource cleanup
867
- * @param {string} operationId - Operation identifier
868
- */
869
- async cleanup(operationId) {
870
- // No persistent resources to clean up
871
- this.logger?.info('File content replace tool cleanup completed', { operationId });
872
- }
873
- }
874
-
875
- export default FileContentReplaceTool;
1
+ function a0_0x4694(){const _0x265d49=['C3rHCNrZv2L0Aa','rgLMzIb0B28GBgfYz2uGka','cKvYCM9YCZOG','C3bSAxq','CMvWBgfJzq','ChjVy2vZC0zPBgu','cIaGica','Bwf4','rxHLy3v0Aw5NigzPBguGy29UDgvUDcbYzxbSywnL','tufyx05fv19dt05uru5ux1njwKu','BgLUzxnmAw1PDa','zxjYB3jZ','z2v0rgvZy3jPChrPB24','odqWoteWEwX3swnt','tufyx0XjtKvFuKfor0vFu0LArq','Aw5JBhvKzxm','AxnbCNjHEq','zxH0CMfJDef0DhjPyNv0zq','BwfW','B2XKq29UDgvUDa','ig11C3qGAgf2zsbYzxbSywnLBwvUDhmGyxjYyxK','C2L6zq','tufyx09mrf9dt05uru5ux1njwKu','Bg9Nz2vY','tufyx0zjtevtx1bfuL9puevsqvrjt04','CgfYC2vku09o','tuiklsbnyxHPBxvTig9SzcbJB250zw50ihnPEMu6ia','icHJB250zw50ig5VDcbMB3vUzcK','AxnqyxrOqwnJzxnZAwjSzq','nJaYnJnIzLnRCei','CgfYC2vmAw5LuMfUz2vZ','tuiPoIa','mta0nteYBKTrD3P3','AgfZ','C3vIC3rYAw5N','BMv3BgLUzxm','nJeWmdH1tMHHsKu','s0iklsbnyxHPBxvTihjLCgXHy2vTzw50CYbWzxiGzMLSztOG','ugfYyw1LDgvYihzHBgLKyxrPB24GzMfPBgvKoIa','rMfPBgvKihrVihbHCNnLigzPBguTy29UDgvUDc1YzxbSywnLihbHCMfTzxrLCNm','ntKXodyZBNnHDejr','DgLTzw91Da','zxHLy3v0zq','D29YA2LUz0rPCMvJDg9YEq','nde2mdyYnePrDhzlqG','Dg90ywXszxbSywnLBwvUDhm','igzPBgvZigLUig9UzsbVCgvYyxrPB24','CMvWBgfJzunVBMzPzW','yxbWBhLszxbSywnLBwvUDa','y2XLyw51Ca','lIbnDxn0igjLicD0CMLTjYWGj25LD2XPBMvZjYWGB3iGj25VBMuN','q1jfqvrfx0jbq0Tvufm','BgvUz3rO','ihjLCgXHy2vTzw50khmPigLUia','pvSIj10Ow14Ij10QkvSIj10','CMvWBgfJzw1LBNrZ','Bw9Kzq','ChvZAa','zMLSzxnqCM9JzxnZzwq','C3rHDa','D2fYBG','nwreExvevG','y291BNq','CMvHzezPBgu','cGPot1rfuZOkcI0GvxnLihrOzsbZzwvRihrVB2WGzMLYC3qGDg8GDMvYAwz5ignVBNrLBNqGzxHPC3rZcI0GqMfJA3vWCYbHCMuGy3jLyxrLzcbHDxrVBwf0AwnHBgX5icGUyMfRigv4DgvUC2LVBIKklsbszxbSywnLBwvUDhmGyxjLignHC2uTC2vUC2L0AxzLcI0Gt2XKignVBNrLBNqGBxvZDcbTyxrJAcbLEgfJDgX5icHHzNrLCIb0CMLTig1VzguGyxbWBgLLzcKklsbnDwX0AxbSzsbVy2n1CNjLBMnLCYbHCMuGywXSihjLCgXHy2vKihvUBgvZCYbSAw5LC0XPBwL0ihnWzwnPzMLLzaOTifrVB2WGDMfSAwrHDgvZihbHDgHZigfNywLUC3qGywDLBNqNCYbHy2nLC3nPyMXLigrPCMvJDg9YAwvZcGPnvuXuss1esvjfq1rpuLKGu1vque9svdOkcLDVCMTZihDPDgGGywDLBNqNCYbJB25MAwD1CMvKigfJy2vZC2LIBguGzgLYzwn0B3jPzxmUcLzHBgLKyxrLCYbWyxrOCYbHz2fPBNn0igrPCMvJDg9YEufJy2vZCYbJB25MAwD1CMf0Aw9UlGOGicaG','yMfJA3vWq3jLyxrLza','z2vUzxjHDgvtDw1Tyxj5','y3vZDg9TvMfSAwrHDgvqyxjHBwv0zxjZ','y291BNrpy2n1CNjLBMnLCW','zMLSzxnnB2rPzMLLza','BgLUzxmTBgLTAxq','twLZC2LUzYbVBgqTy29UDgvUDcbPBIbYzxbSywnLihrHzW','B2XKq29UDgvUDcb0B28GBgfYz2uGkg1HEca','D3jPDgvgAwXL','ig1PC3nPBMCGBMv3q29UDgvUDa','zMLSzxm','CgfYC2vytuW','tufyx0zjtevFu0LArq','zxjYB3i','Cgf0Aa','mJa4nZK5nhfWwgnTtq','ugf0AcbUB3qGywnJzxnZAwjSztOG','igzPBguOCYKktw9KAwzPzwqG','z2vUzxjHDgveAwzM','ig1PC3nPBMCGB2XKq29UDgvUDa','DxrMltG','ywrK','BMv3q29UDgvUDa','s0iP','zxHLyW','tufyx0rjrKzFteLorvm','CMvWBgfJzw1LBNrZtwfKzq','rMLSzsbJB250zw50ihjLCgXHy2uGDg9VBcbJBgvHBNvWignVBxbSzxrLza','DhjPBq','ihrVia','AxnbyNnVBhv0zq','rxjYB3iGChjVy2vZC2LUzYbMAwXLia','Aw5MBW'];a0_0x4694=function(){return _0x265d49;};return a0_0x4694();}const a0_0x20dfb8=a0_0x8fd8;(function(_0x1ebaf8,_0x3ef7d0){const _0x3ae939=a0_0x8fd8,_0x54b506=_0x1ebaf8();while(!![]){try{const _0x5ae1d3=parseInt(_0x3ae939(0x14a))/0x1+-parseInt(_0x3ae939(0x12f))/0x2+parseInt(_0x3ae939(0x146))/0x3+-parseInt(_0x3ae939(0x142))/0x4+-parseInt(_0x3ae939(0xfd))/0x5*(parseInt(_0x3ae939(0x110))/0x6)+-parseInt(_0x3ae939(0x13f))/0x7+parseInt(_0x3ae939(0x14e))/0x8;if(_0x5ae1d3===_0x3ef7d0)break;else _0x54b506['push'](_0x54b506['shift']());}catch(_0x4187fe){_0x54b506['push'](_0x54b506['shift']());}}}(a0_0x4694,0x5057e));import{BaseTool}from'./baseTool.js';import{promises as a0_0x1fad82}from'fs';function a0_0x8fd8(_0x299dcd,_0x505451){_0x299dcd=_0x299dcd-0xf8;const _0x469422=a0_0x4694();let _0x8fd84d=_0x469422[_0x299dcd];if(a0_0x8fd8['pmXIhi']===undefined){var _0x11492f=function(_0xca7dbc){const _0x425602='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x1fad82='',_0x5e54f3='';for(let _0x2db1b9=0x0,_0x570e89,_0x531eb3,_0x48d6c2=0x0;_0x531eb3=_0xca7dbc['charAt'](_0x48d6c2++);~_0x531eb3&&(_0x570e89=_0x2db1b9%0x4?_0x570e89*0x40+_0x531eb3:_0x531eb3,_0x2db1b9++%0x4)?_0x1fad82+=String['fromCharCode'](0xff&_0x570e89>>(-0x2*_0x2db1b9&0x6)):0x0){_0x531eb3=_0x425602['indexOf'](_0x531eb3);}for(let _0x3f34df=0x0,_0x197c06=_0x1fad82['length'];_0x3f34df<_0x197c06;_0x3f34df++){_0x5e54f3+='%'+('00'+_0x1fad82['charCodeAt'](_0x3f34df)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x5e54f3);};a0_0x8fd8['LdmPEc']=_0x11492f,a0_0x8fd8['dtISOS']={},a0_0x8fd8['pmXIhi']=!![];}const _0x5959da=_0x469422[0x0],_0x2cb79f=_0x299dcd+_0x5959da,_0x25a280=a0_0x8fd8['dtISOS'][_0x2cb79f];return!_0x25a280?(_0x8fd84d=a0_0x8fd8['LdmPEc'](_0x8fd84d),a0_0x8fd8['dtISOS'][_0x2cb79f]=_0x8fd84d):_0x8fd84d=_0x25a280,_0x8fd84d;}import a0_0x5e54f3 from'path';const REPLACE_CONFIG={'MAX_FILE_SIZE':0xa*0x400*0x400,'MAX_OLD_CONTENT_SIZE':0x64*0x400,'MAX_NEW_CONTENT_SIZE':0x64*0x400,'MAX_REPLACEMENTS_PER_FILE':0x3e8,'MAX_FILES_PER_OPERATION':0x32,'MAX_LINE_RANGE_SIZE':0x2710,'CREATE_BACKUPS':!![],'BACKUP_EXTENSION':'.bak','DIFF_CONTEXT_LINES':0x3,'MAX_DIFF_LINES':0x64,'DEFAULT_TRIM_MODE':'trim'};class FileContentReplaceTool extends BaseTool{constructor(_0x2db1b9={},_0x570e89=null){const _0x486636=a0_0x8fd8;super(_0x2db1b9,_0x570e89),this['requiresProject']=!![],this['isAsync']=!![],this['timeout']=_0x2db1b9[_0x486636(0x14b)]||0x1d4c0,this['replaceConfig']={...REPLACE_CONFIG,..._0x2db1b9['replaceConfig']};}[a0_0x20dfb8(0x12e)](){const _0x17608a=a0_0x20dfb8;return'\x0aFile\x20Content\x20Replace\x20Tool:\x20Replace\x20specific\x20content\x20within\x20files\x20with\x20precision.\x0a\x0aXML\x20USAGE:\x0a<file-content-replace>\x0a\x20\x20<file\x20path=\x22src/app.js\x22>\x0a\x20\x20\x20\x20<replace\x20mode=\x22trim\x22\x20lines-limit=\x225,7-10\x22>\x0a\x20\x20\x20\x20\x20\x20<old-content>\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20oldFunction\x20=\x20()\x20=>\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27old\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20newFunction\x20=\x20()\x20=>\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27new\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a</file-content-replace>\x0a\x0aJSON\x20USAGE:\x0a```json\x0a{\x0a\x20\x20\x22toolId\x22:\x20\x22file-content-replace\x22,\x0a\x20\x20\x22files\x22:\x20[\x0a\x20\x20\x20\x20{\x0a\x20\x20\x20\x20\x20\x20\x22path\x22:\x20\x22src/app.js\x22,\x0a\x20\x20\x20\x20\x20\x20\x22replacements\x22:\x20[\x0a\x20\x20\x20\x20\x20\x20\x20\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22oldContent\x22:\x20\x22const\x20oldFunction\x20=\x20()\x20=>\x20{}\x22,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22newContent\x22:\x20\x22const\x20newFunction\x20=\x20()\x20=>\x20{}\x22,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22mode\x22:\x20\x22trim\x22,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22linesLimit\x22:\x20\x225,7-10\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20]\x0a\x20\x20\x20\x20}\x0a\x20\x20]\x0a}\x0a```\x0a\x0aPARAMETERS:\x0a\x0apath\x20(required):\x0a\x20\x20-\x20Path\x20to\x20the\x20file\x20to\x20modify\x0a\x20\x20-\x20Can\x20be\x20relative\x20or\x20absolute\x0a\x20\x20-\x20Examples:\x20\x22src/app.js\x22,\x20\x22./config.json\x22\x0a\x0aoldContent\x20(required):\x0a\x20\x20-\x20Content\x20to\x20find\x20and\x20replace\x0a\x20\x20-\x20Subject\x20to\x20trim\x20mode\x20processing\x0a\x20\x20-\x20Must\x20exist\x20in\x20file\x0a\x0anewContent\x20(required):\x0a\x20\x20-\x20Replacement\x20content\x0a\x20\x20-\x20Subject\x20to\x20trim\x20mode\x20processing\x0a\x20\x20-\x20Can\x20be\x20same\x20length,\x20shorter,\x20or\x20longer\x0a\x0amode\x20(optional):\x0a\x20\x20-\x20Whitespace\x20handling\x20mode\x0a\x20\x20-\x20Options:\x0a\x20\x20\x20\x20*\x20\x22trim\x22\x20(default):\x20Trim\x20all\x20whitespace\x20from\x20both\x20ends\x0a\x20\x20\x20\x20*\x20\x22newlines\x22:\x20Only\x20trim\x20newline\x20characters\x0a\x20\x20\x20\x20*\x20\x22none\x22:\x20Use\x20content\x20exactly\x20as\x20provided\x0a\x20\x20-\x20Helps\x20with\x20matching\x20despite\x20indentation\x20differences\x0a\x0alinesLimit\x20(optional):\x0a\x20\x20-\x20Restrict\x20replacement\x20to\x20specific\x20lines\x0a\x20\x20-\x20Format:\x20Comma-separated\x20line\x20numbers\x20or\x20ranges\x0a\x20\x20-\x20Examples:\x0a\x20\x20\x20\x20*\x20\x225\x22\x20-\x20Only\x20line\x205\x0a\x20\x20\x20\x20*\x20\x225,10,15\x22\x20-\x20Lines\x205,\x2010,\x20and\x2015\x0a\x20\x20\x20\x20*\x20\x225-10\x22\x20-\x20Lines\x205\x20through\x2010\x0a\x20\x20\x20\x20*\x20\x221-5,10,15-20\x22\x20-\x20Lines\x201-5,\x2010,\x20and\x2015-20\x0a\x20\x20-\x20Line\x20numbers\x20are\x201-based\x0a\x0aTRIM\x20MODES\x20EXPLAINED:\x0a\x0aMode:\x20\x22trim\x22\x20(Recommended\x20for\x20most\x20cases)\x0a\x20\x20Input:\x0a\x20\x20\x20\x20\x22\x20\x20const\x20x\x20=\x201;\x20\x20\x5cn\x22\x0a\x20\x20After\x20trim:\x0a\x20\x20\x20\x20\x22const\x20x\x20=\x201;\x22\x0a\x20\x20Use\x20when:\x20Indentation\x20may\x20vary\x0a\x0aMode:\x20\x22newlines\x22\x0a\x20\x20Input:\x0a\x20\x20\x20\x20\x22\x5cn\x20\x20const\x20x\x20=\x201;\x20\x20\x5cn\x22\x0a\x20\x20After\x20trim:\x0a\x20\x20\x20\x20\x22\x20\x20const\x20x\x20=\x201;\x20\x20\x22\x0a\x20\x20Use\x20when:\x20Preserving\x20internal\x20whitespace\x0a\x0aMode:\x20\x22none\x22\x0a\x20\x20Input:\x0a\x20\x20\x20\x20\x22\x20\x20const\x20x\x20=\x201;\x20\x20\x5cn\x22\x0a\x20\x20After\x20trim:\x0a\x20\x20\x20\x20\x22\x20\x20const\x20x\x20=\x201;\x20\x20\x5cn\x22\x0a\x20\x20Use\x20when:\x20Exact\x20character\x20match\x20needed\x0a\x0aEXAMPLES:\x0a\x0aExample\x201\x20-\x20Basic\x20replacement\x20with\x20trim:\x0a<file-content-replace>\x0a\x20\x20<file\x20path=\x22src/components/Button.js\x22>\x0a\x20\x20\x20\x20<replace\x20mode=\x22trim\x22>\x0a\x20\x20\x20\x20\x20\x20<old-content>\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20handleClick\x20=\x20(event)\x20=>\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27clicked\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>\x0a\x20\x20\x20\x20\x20\x20\x20\x20const\x20handleClick\x20=\x20(event)\x20=>\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20console.log(\x27clicked\x27);\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20props.onClick?.(event);\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a</file-content-replace>\x0a\x0aExample\x202\x20-\x20Line-limited\x20replacement:\x0a<file-content-replace>\x0a\x20\x20<file\x20path=\x22src/App.js\x22>\x0a\x20\x20\x20\x20<replace\x20lines-limit=\x2210-20\x22>\x0a\x20\x20\x20\x20\x20\x20<old-content>const\x20API_URL\x20=\x20\x27http://localhost:3000\x27</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>const\x20API_URL\x20=\x20process.env.API_URL</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a</file-content-replace>\x0a\x0aExample\x203\x20-\x20Multiple\x20replacements\x20in\x20one\x20file:\x0a<file-content-replace>\x0a\x20\x20<file\x20path=\x22src/config.js\x22>\x0a\x20\x20\x20\x20<replace>\x0a\x20\x20\x20\x20\x20\x20<old-content>DEBUG\x20=\x20false</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>DEBUG\x20=\x20true</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20\x20\x20<replace>\x0a\x20\x20\x20\x20\x20\x20<old-content>LOG_LEVEL\x20=\x20\x27error\x27</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>LOG_LEVEL\x20=\x20\x27debug\x27</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a</file-content-replace>\x0a\x0aExample\x204\x20-\x20Multiple\x20files:\x0a<file-content-replace>\x0a\x20\x20<file\x20path=\x22src/app.js\x22>\x0a\x20\x20\x20\x20<replace>\x0a\x20\x20\x20\x20\x20\x20<old-content>version\x20=\x20\x271.0.0\x27</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>version\x20=\x20\x271.1.0\x27</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a\x20\x20<file\x20path=\x22package.json\x22>\x0a\x20\x20\x20\x20<replace\x20mode=\x22none\x22>\x0a\x20\x20\x20\x20\x20\x20<old-content>\x22version\x22:\x20\x221.0.0\x22</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>\x22version\x22:\x20\x221.1.0\x22</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a</file-content-replace>\x0a\x0aExample\x205\x20-\x20Exact\x20whitespace\x20matching:\x0a<file-content-replace>\x0a\x20\x20<file\x20path=\x22Makefile\x22>\x0a\x20\x20\x20\x20<replace\x20mode=\x22none\x22>\x0a\x20\x20\x20\x20\x20\x20<old-content>\x5ctbuild:\x5cn\x5ct\x5ctgcc</old-content>\x0a\x20\x20\x20\x20\x20\x20<new-content>\x5ctbuild:\x5cn\x5ct\x5ctclang</new-content>\x0a\x20\x20\x20\x20</replace>\x0a\x20\x20</file>\x0a</file-content-replace>\x0a\x0aFEATURES:\x0a\x0a✓\x20Automatic\x20backup\x20creation\x20(.bak\x20files)\x0a✓\x20Before/after\x20diff\x20reports\x0a✓\x20Replacement\x20counting\x20and\x20statistics\x0a✓\x20Multi-file\x20operations\x0a✓\x20Line-limited\x20replacements\x0a✓\x20Intelligent\x20whitespace\x20handling\x0a✓\x20Security\x20validation\x20(path\x20access)\x0a✓\x20Creates\x20parent\x20directories\x20if\x20needed\x0a\x0aLIMITATIONS:\x0a\x0a-\x20Maximum\x20file\x20size:\x20'+REPLACE_CONFIG[_0x17608a(0x10d)]/(0x400*0x400)+_0x17608a(0x13c)+REPLACE_CONFIG[_0x17608a(0x138)]/0x400+'KB\x0a-\x20Maximum\x20new\x20content\x20size:\x20'+REPLACE_CONFIG[_0x17608a(0x12b)]/0x400+_0x17608a(0x147)+REPLACE_CONFIG['MAX_REPLACEMENTS_PER_FILE']+'\x0a-\x20Maximum\x20files\x20per\x20operation:\x20'+REPLACE_CONFIG[_0x17608a(0x13a)]+_0x17608a(0x100);}['parseParameters'](_0x531eb3){const _0x3f01e4=a0_0x20dfb8;try{if(_0x531eb3[_0x3f01e4(0x11d)]()[_0x3f01e4(0x122)]('{'))return this['parseJSON'](_0x531eb3);return this[_0x3f01e4(0x10c)](_0x531eb3);}catch(_0x48d6c2){this['logger']?.[_0x3f01e4(0x10e)](_0x3f01e4(0x149),{'error':_0x48d6c2['message']});throw new Error('Parameter\x20parsing\x20failed:\x20'+_0x48d6c2['message']);}}[a0_0x20dfb8(0x13b)](_0x3f34df){const _0xc2d175=a0_0x20dfb8,_0x197c06=JSON['parse'](_0x3f34df);if(!_0x197c06['files']||!Array[_0xc2d175(0x132)](_0x197c06[_0xc2d175(0x10b)]))throw new Error('JSON\x20must\x20have\x20\x22files\x22\x20array');return{'files':_0x197c06['files']['map'](_0x295053=>({'path':_0x295053['path'],'replacements':(_0x295053['replacements']||[])[_0xc2d175(0x134)](_0x52965a=>({'oldContent':_0x52965a[_0xc2d175(0x135)],'newContent':_0x52965a[_0xc2d175(0x117)],'mode':_0x52965a[_0xc2d175(0xf8)]||REPLACE_CONFIG['DEFAULT_TRIM_MODE'],'linesLimit':_0x52965a[_0xc2d175(0x12c)]||null}))}))};}['parseXML'](_0x306bcd){const _0x4b9ede=a0_0x20dfb8,_0x23259e=[],_0x2f8c91=/<file\s+path="([^"]+)">([\s\S]*?)<\/file>/gi;let _0x535d10;while((_0x535d10=_0x2f8c91[_0x4b9ede(0x119)](_0x306bcd))!==null){const _0x46ac89=_0x535d10[0x1],_0x5d5369=_0x535d10[0x2],_0x4f97ab=[],_0x4a5d52=/<replace(?:\s+([^>]*?))?>([\s\S]*?)<\/replace>/gi;let _0x2819b2;while((_0x2819b2=_0x4a5d52[_0x4b9ede(0x119)](_0x5d5369))!==null){const _0x421c45=_0x2819b2[0x1]||'',_0x549761=_0x2819b2[0x2],_0x38a982=this['extractAttribute'](_0x421c45,_0x4b9ede(0xf8))||REPLACE_CONFIG['DEFAULT_TRIM_MODE'],_0x310218=this['extractAttribute'](_0x421c45,_0x4b9ede(0x106)),_0x41d360=/<old-content>([\s\S]*?)<\/old-content>/i['exec'](_0x549761);if(!_0x41d360){this['logger']?.['warn'](_0x4b9ede(0x107));continue;}const _0x211cd5=_0x41d360[0x1],_0x548b3b=/<new-content>([\s\S]*?)<\/new-content>/i[_0x4b9ede(0x119)](_0x549761);if(!_0x548b3b){this[_0x4b9ede(0x139)]?.['warn']('Missing\x20new-content\x20in\x20replace\x20tag');continue;}const _0x4c7b82=_0x548b3b[0x1],_0x34e742=this['applyTrimMode'](_0x211cd5,_0x38a982),_0x30ec34=this['applyTrimMode'](_0x4c7b82,_0x38a982);_0x4f97ab[_0x4b9ede(0xf9)]({'oldContent':_0x34e742,'newContent':_0x30ec34,'mode':_0x38a982,'linesLimit':_0x310218});}_0x4f97ab[_0x4b9ede(0x156)]>0x0&&_0x23259e[_0x4b9ede(0xf9)]({'path':_0x46ac89,'replacements':_0x4f97ab});}return{'files':_0x23259e};}[a0_0x20dfb8(0x133)](_0x39d595,_0x894500){const _0x81d77c=a0_0x20dfb8,_0x185912=new RegExp(_0x894500+_0x81d77c(0x158),'i'),_0x5d8141=_0x185912['exec'](_0x39d595);return _0x5d8141?_0x5d8141[0x1]:null;}['applyTrimMode'](_0x288d1a,_0x3a3915){const _0x4907af=a0_0x20dfb8;switch(_0x3a3915){case'newlines':return _0x288d1a[_0x4907af(0x126)](/^\n+|\n+$/g,'');case'none':return _0x288d1a;case'trim':default:return _0x288d1a['trim']();}}['getRequiredParameters'](){return['files'];}[a0_0x20dfb8(0x103)](_0x8b44de){const _0x345b47=a0_0x20dfb8,_0x4941d7=[];if(!_0x8b44de[_0x345b47(0x10b)]||!Array['isArray'](_0x8b44de[_0x345b47(0x10b)]))_0x4941d7['push']('files\x20must\x20be\x20an\x20array');else{_0x8b44de[_0x345b47(0x10b)]['length']===0x0&&_0x4941d7['push']('files\x20array\x20cannot\x20be\x20empty');_0x8b44de[_0x345b47(0x10b)]['length']>this[_0x345b47(0x151)][_0x345b47(0x13a)]&&_0x4941d7['push']('Cannot\x20process\x20more\x20than\x20'+this['replaceConfig'][_0x345b47(0x13a)]+_0x345b47(0x150));for(const _0x46fe30 of _0x8b44de[_0x345b47(0x10b)]){!_0x46fe30[_0x345b47(0x10f)]&&_0x4941d7[_0x345b47(0xf9)]('Each\x20file\x20must\x20have\x20a\x20path');_0x46fe30['path']&&_0x46fe30[_0x345b47(0x10f)]['includes']('..')&&_0x4941d7['push']('Path\x20traversal\x20(..)\x20not\x20allowed\x20for\x20security:\x20'+_0x46fe30['path']);if(!_0x46fe30[_0x345b47(0x159)]||!Array[_0x345b47(0x132)](_0x46fe30[_0x345b47(0x159)]))_0x4941d7[_0x345b47(0xf9)]('File\x20'+_0x46fe30[_0x345b47(0x10f)]+_0x345b47(0x136));else{if(_0x46fe30['replacements']['length']===0x0)_0x4941d7[_0x345b47(0xf9)]('File\x20'+_0x46fe30[_0x345b47(0x10f)]+'\x20replacements\x20array\x20cannot\x20be\x20empty');else for(const _0x5a7ea5 of _0x46fe30['replacements']){!_0x5a7ea5[_0x345b47(0x135)]&&_0x5a7ea5['oldContent']!==''&&_0x4941d7['push']('Replacement\x20in\x20'+_0x46fe30[_0x345b47(0x10f)]+_0x345b47(0x114)),!_0x5a7ea5['newContent']&&_0x5a7ea5['newContent']!==''&&_0x4941d7[_0x345b47(0xf9)]('Replacement\x20in\x20'+_0x46fe30['path']+_0x345b47(0x10a)),_0x5a7ea5['oldContent']&&_0x5a7ea5[_0x345b47(0x135)]['length']>this[_0x345b47(0x151)]['MAX_OLD_CONTENT_SIZE']&&_0x4941d7[_0x345b47(0xf9)](_0x345b47(0x108)+this[_0x345b47(0x151)][_0x345b47(0x138)]/0x400+_0x345b47(0x118)),_0x5a7ea5['newContent']&&_0x5a7ea5['newContent']['length']>this[_0x345b47(0x151)]['MAX_NEW_CONTENT_SIZE']&&_0x4941d7['push']('newContent\x20too\x20large\x20(max\x20'+this['replaceConfig'][_0x345b47(0x12b)]/0x400+'KB)'),_0x5a7ea5[_0x345b47(0xf8)]&&!['trim',_0x345b47(0x145),'none'][_0x345b47(0x131)](_0x5a7ea5['mode'])&&_0x4941d7['push']('Invalid\x20mode:\x20'+_0x5a7ea5['mode']+_0x345b47(0x154));}}}}if(_0x4941d7[_0x345b47(0x156)]>0x0)throw new Error(_0x345b47(0x148)+_0x4941d7['join'](',\x20'));return{'valid':!![],'errors':[]};}async[a0_0x20dfb8(0x14c)](_0x152c5d,_0x332a45){const _0x10dbf6=a0_0x20dfb8,{files:_0x3d9abc}=_0x152c5d,{projectDir:_0x3ab6ab,agentId:_0x3d6aa8,directoryAccess:_0x3b543a}=_0x332a45;let _0x5e0ccf=_0x3ab6ab||process['cwd']();_0x3b543a&&_0x3b543a['workingDirectory']&&(_0x5e0ccf=_0x3b543a[_0x10dbf6(0x14d)],this['logger']?.['info']('Using\x20agent\x20configured\x20working\x20directory',{'workingDirectory':_0x3b543a['workingDirectory'],'agentId':_0x3d6aa8}));this['logger']?.['info'](_0x10dbf6(0x12a),{'fileCount':_0x3d9abc[_0x10dbf6(0x156)],'workingDirectory':_0x5e0ccf,'agentId':_0x3d6aa8});const _0x2dc509=[],_0x552ce7={'filesProcessed':0x0,'filesModified':0x0,'totalReplacements':0x0,'backupsCreated':0x0,'errors':0x0};for(const _0x341317 of _0x3d9abc){try{const _0x38b142=await this[_0x10dbf6(0x127)](_0x341317,_0x5e0ccf,_0x3b543a);_0x2dc509['push'](_0x38b142),_0x552ce7[_0x10dbf6(0xfa)]++,_0x38b142[_0x10dbf6(0x11b)]>0x0&&(_0x552ce7[_0x10dbf6(0x105)]++,_0x552ce7[_0x10dbf6(0x14f)]+=_0x38b142['replacementsMade']),_0x38b142[_0x10dbf6(0x101)]&&_0x552ce7['backupsCreated']++;}catch(_0x1d395a){this['logger']?.['error'](_0x10dbf6(0x120)+_0x341317[_0x10dbf6(0x10f)],{'error':_0x1d395a['message']}),_0x2dc509[_0x10dbf6(0xf9)]({'filePath':_0x341317['path'],'success':![],'error':_0x1d395a['message']}),_0x552ce7[_0x10dbf6(0x12d)]++;}}return{'success':_0x552ce7['errors']===0x0,'results':_0x2dc509,'statistics':_0x552ce7,'summary':this['generateSummary'](_0x552ce7),'toolUsed':'file-content-replace'};}async[a0_0x20dfb8(0x127)](_0x4ef838,_0x10132f,_0x3457eb){const _0x4ad491=a0_0x20dfb8,{path:_0x22c9b6,replacements:_0x4504e2}=_0x4ef838,_0x4ff55=a0_0x5e54f3['isAbsolute'](_0x22c9b6)?_0x22c9b6:a0_0x5e54f3['resolve'](_0x10132f,_0x22c9b6);if(_0x3457eb){const _0x3a9071=this[_0x4ad491(0x13e)](_0x4ff55,_0x10132f,_0x3457eb);if(!_0x3a9071)throw new Error(_0x4ad491(0x111)+_0x22c9b6);}try{await a0_0x1fad82['access'](_0x4ff55);}catch(_0x5be746){throw new Error('File\x20not\x20found:\x20'+_0x22c9b6);}const _0x5fc3fb=await a0_0x1fad82[_0x4ad491(0xfb)](_0x4ff55);if(_0x5fc3fb[_0x4ad491(0x137)]>this[_0x4ad491(0x151)]['MAX_FILE_SIZE'])throw new Error('File\x20too\x20large\x20(max\x20'+this[_0x4ad491(0x151)]['MAX_FILE_SIZE']/(0x400*0x400)+_0x4ad491(0x141)+_0x22c9b6);let _0xde9648=await a0_0x1fad82[_0x4ad491(0xff)](_0x4ff55,_0x4ad491(0x115));const _0x5abf2d=_0xde9648;let _0x2bd1b9=![];if(this[_0x4ad491(0x151)][_0x4ad491(0x155)]){const _0x2c5c0c=_0x4ff55+this['replaceConfig']['BACKUP_EXTENSION'];try{await a0_0x1fad82['writeFile'](_0x2c5c0c,_0x5abf2d,_0x4ad491(0x115)),_0x2bd1b9=!![];}catch(_0x45723a){this[_0x4ad491(0x139)]?.[_0x4ad491(0xfc)]('Failed\x20to\x20create\x20backup:\x20'+_0x45723a['message']);}}let _0x96f485=0x0;const _0x6775ad=[];for(const _0x50779a of _0x4504e2){const _0x1effe8=await this['applyReplacement'](_0xde9648,_0x50779a[_0x4ad491(0x135)],_0x50779a['newContent'],_0x50779a['linesLimit'],_0x50779a['mode']);_0xde9648=_0x1effe8[_0x4ad491(0x117)],_0x96f485+=_0x1effe8['count'],_0x6775ad['push']({'oldContent':_0x50779a['oldContent'][_0x4ad491(0x144)](0x0,0x32)+(_0x50779a['oldContent'][_0x4ad491(0x156)]>0x32?'...':''),'newContent':_0x50779a[_0x4ad491(0x117)][_0x4ad491(0x144)](0x0,0x32)+(_0x50779a['newContent'][_0x4ad491(0x156)]>0x32?'...':''),'count':_0x1effe8[_0x4ad491(0xfe)],'mode':_0x50779a['mode'],'linesLimit':_0x50779a[_0x4ad491(0x12c)]});}_0x96f485>0x0&&await a0_0x1fad82[_0x4ad491(0x109)](_0x4ff55,_0xde9648,_0x4ad491(0x115));const _0x260ecf=_0x96f485>0x0?this['generateDiff'](_0x5abf2d,_0xde9648):null;return{'filePath':_0x22c9b6,'resolvedPath':_0x4ff55,'success':!![],'replacementsMade':_0x96f485,'backupCreated':_0x2bd1b9,'replacementDetails':_0x6775ad,'diff':_0x260ecf,'message':_0x96f485>0x0?'Made\x20'+_0x96f485+_0x4ad491(0x157)+_0x22c9b6:'No\x20replacements\x20made\x20in\x20'+_0x22c9b6+_0x4ad491(0x13d)};}['isPathAccessible'](_0x32a120,_0x1f48c1,_0x21865){const _0x41859b=a0_0x20dfb8,_0x308e0f=a0_0x5e54f3['relative'](_0x1f48c1,_0x32a120);if(!_0x308e0f[_0x41859b(0x122)]('..')&&!a0_0x5e54f3['isAbsolute'](_0x308e0f))return!![];if(_0x21865['writeEnabledDirectories'])for(const _0x223924 of _0x21865['writeEnabledDirectories']){const _0x46c893=a0_0x5e54f3['relative'](_0x223924,_0x32a120);if(!_0x46c893[_0x41859b(0x122)]('..')&&!a0_0x5e54f3[_0x41859b(0x11f)](_0x46c893))return!![];}return![];}async[a0_0x20dfb8(0x152)](_0x9cfb9b,_0x19bf5f,_0x5b6670,_0x5d9e6f,_0x91c3c8){const _0x3509e1=a0_0x20dfb8;if(!_0x5d9e6f){const _0x3e8d80=this[_0x3509e1(0x104)](_0x9cfb9b,_0x19bf5f);if(_0x3e8d80===0x0)return{'newContent':_0x9cfb9b,'count':0x0};const _0x2c857c=_0x9cfb9b['split'](_0x19bf5f)['join'](_0x5b6670);return{'newContent':_0x2c857c,'count':_0x3e8d80};}const _0x292fd4=this[_0x3509e1(0x140)](_0x5d9e6f),_0x2caaee=_0x9cfb9b[_0x3509e1(0x125)]('\x0a');let _0x3dd3d8=0x0;for(let _0x3d76d9=0x0;_0x3d76d9<_0x2caaee['length'];_0x3d76d9++){const _0x53a181=_0x3d76d9+0x1;if(_0x292fd4[_0x3509e1(0x143)](_0x53a181)){if(_0x2caaee[_0x3d76d9]['includes'](_0x19bf5f)){const _0x45f225=this[_0x3509e1(0x104)](_0x2caaee[_0x3d76d9],_0x19bf5f);_0x2caaee[_0x3d76d9]=_0x2caaee[_0x3d76d9][_0x3509e1(0x125)](_0x19bf5f)['join'](_0x5b6670),_0x3dd3d8+=_0x45f225;}}}return{'newContent':_0x2caaee['join']('\x0a'),'count':_0x3dd3d8};}[a0_0x20dfb8(0x104)](_0x562902,_0x1a5ec0){const _0x55fb0c=a0_0x20dfb8;if(!_0x1a5ec0)return 0x0;return _0x562902[_0x55fb0c(0x125)](_0x1a5ec0)[_0x55fb0c(0x156)]-0x1;}['parseLineRanges'](_0x505ddf){const _0x2d47aa=a0_0x20dfb8,_0x3972ee=new Set();if(!_0x505ddf||_0x505ddf['trim']()==='')return _0x3972ee;const _0x5e0acd=_0x505ddf[_0x2d47aa(0x125)](',');for(const _0x1b381e of _0x5e0acd){const _0x4ccfd4=_0x1b381e['trim']();if(_0x4ccfd4==='')continue;if(_0x4ccfd4[_0x2d47aa(0x131)]('-')){const [_0x1f4859,_0x3c85ec]=_0x4ccfd4['split']('-')[_0x2d47aa(0x134)](_0x5e9bfa=>parseInt(_0x5e9bfa[_0x2d47aa(0x11d)](),0xa));if(!isNaN(_0x1f4859)&&!isNaN(_0x3c85ec)&&_0x3c85ec-_0x1f4859<this[_0x2d47aa(0x151)][_0x2d47aa(0x130)])for(let _0x304884=_0x1f4859;_0x304884<=_0x3c85ec;_0x304884++){_0x3972ee[_0x2d47aa(0x116)](_0x304884);}}else{const _0x2d9f15=parseInt(_0x4ccfd4,0xa);!isNaN(_0x2d9f15)&&_0x3972ee['add'](_0x2d9f15);}}return _0x3972ee;}[a0_0x20dfb8(0x113)](_0x1a6cd3,_0x6d333){const _0x585aac=a0_0x20dfb8,_0x316b52=_0x1a6cd3[_0x585aac(0x125)]('\x0a'),_0x3afd25=_0x6d333['split']('\x0a');let _0x5dabb0=-0x1,_0x6f602d=-0x1;const _0x4f67d5=Math[_0x585aac(0x129)](_0x316b52['length'],_0x3afd25['length']);for(let _0x341876=0x0;_0x341876<_0x4f67d5;_0x341876++){const _0x2cd8b3=_0x341876<_0x316b52[_0x585aac(0x156)]?_0x316b52[_0x341876]:'',_0x303fac=_0x341876<_0x3afd25[_0x585aac(0x156)]?_0x3afd25[_0x341876]:'';if(_0x2cd8b3!==_0x303fac){if(_0x5dabb0===-0x1)_0x5dabb0=_0x341876;_0x6f602d=_0x341876;}}if(_0x5dabb0===-0x1)return'No\x20differences';const _0x8df45=this[_0x585aac(0x151)]['DIFF_CONTEXT_LINES'],_0x52e015=Math['max'](0x0,_0x5dabb0-_0x8df45),_0x4e2378=Math['min'](_0x4f67d5-0x1,_0x6f602d+_0x8df45);if(_0x4e2378-_0x52e015>this[_0x585aac(0x151)][_0x585aac(0x11a)])return _0x585aac(0x123)+(_0x4e2378-_0x52e015+0x1)+'\x20lines),\x20showing\x20summary\x20only:\x0a'+('Changed\x20lines:\x20'+(_0x5dabb0+0x1)+_0x585aac(0x11e)+(_0x6f602d+0x1));let _0x2aa4af='@@\x20-'+(_0x52e015+0x1)+','+(_0x4e2378-_0x52e015+0x1)+'\x20+'+(_0x52e015+0x1)+','+(_0x4e2378-_0x52e015+0x1)+'\x20@@\x0a';for(let _0x2c2a2a=_0x52e015;_0x2c2a2a<=_0x4e2378;_0x2c2a2a++){const _0x4288e1=_0x2c2a2a<_0x316b52[_0x585aac(0x156)]?_0x316b52[_0x2c2a2a]:'',_0x2d6eb3=_0x2c2a2a<_0x3afd25['length']?_0x3afd25[_0x2c2a2a]:'';_0x4288e1===_0x2d6eb3?_0x2aa4af+='\x20\x20'+_0x4288e1+'\x0a':(_0x2aa4af+='-\x20'+_0x4288e1+'\x0a',_0x2aa4af+='+\x20'+_0x2d6eb3+'\x0a');}return _0x2aa4af;}[a0_0x20dfb8(0x102)](_0x432af5){const _0x2db49c=a0_0x20dfb8;return('\x0aProcessed\x20'+_0x432af5[_0x2db49c(0xfa)]+_0x2db49c(0x112)+_0x432af5['filesModified']+'\x20file(s)\x0aTotal\x20replacements:\x20'+_0x432af5[_0x2db49c(0x14f)]+'\x0aBackups\x20created:\x20'+_0x432af5['backupsCreated']+_0x2db49c(0x124)+_0x432af5['errors']+_0x2db49c(0x128))['trim']();}async[a0_0x20dfb8(0x153)](_0x56e971){const _0xaa3df8=a0_0x20dfb8;this['logger']?.[_0xaa3df8(0x121)](_0xaa3df8(0x11c),{'operationId':_0x56e971});}}export default FileContentReplaceTool;