onbuzz 3.6.1 → 3.6.2

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 (83) hide show
  1. package/package.json +1 -1
  2. package/src/__test-utils__/fixtures/malformedJson.js +31 -0
  3. package/src/__test-utils__/globalSetup.js +9 -0
  4. package/src/__test-utils__/globalTeardown.js +12 -0
  5. package/src/__test-utils__/mockFactories.js +101 -0
  6. package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -0
  7. package/src/analyzers/__tests__/ConfigValidator.test.js +362 -0
  8. package/src/analyzers/__tests__/ESLintAnalyzer.test.js +271 -0
  9. package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -0
  10. package/src/analyzers/__tests__/PrettierFormatter.test.js +197 -0
  11. package/src/analyzers/__tests__/PythonAnalyzer.test.js +208 -0
  12. package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -0
  13. package/src/analyzers/__tests__/SparrowAnalyzer.test.js +270 -0
  14. package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -0
  15. package/src/core/__tests__/agentPool.test.js +601 -0
  16. package/src/core/__tests__/agentScheduler.test.js +576 -0
  17. package/src/core/__tests__/contextManager.test.js +252 -0
  18. package/src/core/__tests__/flowExecutor.test.js +262 -0
  19. package/src/core/__tests__/messageProcessor.test.js +627 -0
  20. package/src/core/__tests__/orchestrator.test.js +257 -0
  21. package/src/core/__tests__/stateManager.test.js +375 -0
  22. package/src/core/agentPool.js +11 -1
  23. package/src/index.js +25 -9
  24. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +3 -5
  25. package/src/services/__tests__/agentActivityService.test.js +319 -0
  26. package/src/services/__tests__/apiKeyManager.test.js +206 -0
  27. package/src/services/__tests__/benchmarkService.test.js +184 -0
  28. package/src/services/__tests__/budgetService.test.js +211 -0
  29. package/src/services/__tests__/contextInjectionService.test.js +205 -0
  30. package/src/services/__tests__/conversationCompactionService.test.js +280 -0
  31. package/src/services/__tests__/credentialVault.test.js +469 -0
  32. package/src/services/__tests__/errorHandler.test.js +314 -0
  33. package/src/services/__tests__/fileAttachmentService.test.js +278 -0
  34. package/src/services/__tests__/flowContextService.test.js +199 -0
  35. package/src/services/__tests__/memoryService.test.js +450 -0
  36. package/src/services/__tests__/modelRouterService.test.js +388 -0
  37. package/src/services/__tests__/modelsService.test.js +261 -0
  38. package/src/services/__tests__/portRegistry.test.js +123 -0
  39. package/src/services/__tests__/projectDetector.test.js +34 -0
  40. package/src/services/__tests__/promptService.test.js +242 -0
  41. package/src/services/__tests__/qualityInspector.test.js +97 -0
  42. package/src/services/__tests__/scheduleService.test.js +308 -0
  43. package/src/services/__tests__/serviceRegistry.test.js +74 -0
  44. package/src/services/__tests__/skillsService.test.js +402 -0
  45. package/src/services/__tests__/tokenCountingService.test.js +48 -0
  46. package/src/tools/__tests__/agentCommunicationTool.test.js +500 -0
  47. package/src/tools/__tests__/agentDelayTool.test.js +342 -0
  48. package/src/tools/__tests__/asyncToolManager.test.js +344 -0
  49. package/src/tools/__tests__/baseTool.test.js +420 -0
  50. package/src/tools/__tests__/codeMapTool.test.js +348 -0
  51. package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -0
  52. package/src/tools/__tests__/fileTreeTool.test.js +274 -0
  53. package/src/tools/__tests__/filesystemTool.test.js +717 -0
  54. package/src/tools/__tests__/helpTool.test.js +204 -0
  55. package/src/tools/__tests__/jobDoneTool.test.js +296 -0
  56. package/src/tools/__tests__/memoryTool.test.js +297 -0
  57. package/src/tools/__tests__/seekTool.test.js +282 -0
  58. package/src/tools/__tests__/skillsTool.test.js +226 -0
  59. package/src/tools/__tests__/staticAnalysisTool.test.js +509 -0
  60. package/src/tools/__tests__/taskManagerTool.test.js +725 -0
  61. package/src/tools/__tests__/terminalTool.test.js +384 -0
  62. package/src/tools/__tests__/userPromptTool.test.js +297 -0
  63. package/src/tools/__tests__/webTool.e2e.test.js +25 -11
  64. package/src/tools/webTool.js +6 -12
  65. package/src/types/__tests__/agent.test.js +499 -0
  66. package/src/types/__tests__/contextReference.test.js +606 -0
  67. package/src/types/__tests__/conversation.test.js +555 -0
  68. package/src/types/__tests__/toolCommand.test.js +584 -0
  69. package/src/types/contextReference.js +1 -1
  70. package/src/utilities/__tests__/attachmentValidator.test.js +80 -0
  71. package/src/utilities/__tests__/configManager.test.js +397 -0
  72. package/src/utilities/__tests__/constants.test.js +49 -0
  73. package/src/utilities/__tests__/directoryAccessManager.test.js +388 -0
  74. package/src/utilities/__tests__/fileProcessor.test.js +104 -0
  75. package/src/utilities/__tests__/jsonRepair.test.js +104 -0
  76. package/src/utilities/__tests__/logger.test.js +129 -0
  77. package/src/utilities/__tests__/platformUtils.test.js +87 -0
  78. package/src/utilities/__tests__/structuredFileValidator.test.js +263 -0
  79. package/src/utilities/__tests__/tagParser.test.js +887 -0
  80. package/src/utilities/__tests__/toolConstants.test.js +94 -0
  81. package/src/utilities/tagParser.js +2 -2
  82. package/src/tools/browserTool.js +0 -897
  83. package/src/utilities/platformUtils.test.js +0 -98
@@ -0,0 +1,274 @@
1
+ import { jest, describe, test, expect, beforeEach } from '@jest/globals';
2
+ import { createMockLogger, createMockConfig } from '../../__test-utils__/mockFactories.js';
3
+
4
+ // Mock fs/promises before import
5
+ const mockFs = {
6
+ stat: jest.fn(),
7
+ readdir: jest.fn()
8
+ };
9
+
10
+ jest.unstable_mockModule('fs', () => ({
11
+ promises: mockFs,
12
+ default: { promises: mockFs }
13
+ }));
14
+
15
+ // Mock constants
16
+ jest.unstable_mockModule('../../utilities/constants.js', () => ({
17
+ TOOL_STATUS: { PENDING: 'pending', EXECUTING: 'executing', COMPLETED: 'completed', FAILED: 'failed' },
18
+ OPERATION_STATUS: { NOT_FOUND: 'not_found' },
19
+ ERROR_TYPES: {},
20
+ SYSTEM_DEFAULTS: { MAX_TOOL_EXECUTION_TIME: 300000 }
21
+ }));
22
+
23
+ const { default: FileTreeTool } = await import('../fileTreeTool.js');
24
+
25
+ // Helper to create mock dirent
26
+ function mockDirent(name, isDir = false) {
27
+ return {
28
+ name,
29
+ isDirectory: () => isDir,
30
+ isFile: () => !isDir,
31
+ isSymbolicLink: () => false
32
+ };
33
+ }
34
+
35
+ describe('FileTreeTool', () => {
36
+ let tool;
37
+ let logger;
38
+ const context = { projectDir: '/project', agentId: 'agent-1' };
39
+
40
+ beforeEach(() => {
41
+ jest.clearAllMocks();
42
+ logger = createMockLogger();
43
+ tool = new FileTreeTool({}, logger);
44
+ });
45
+
46
+ test('constructor sets metadata correctly', () => {
47
+ expect(tool.id).toBe('file-tree');
48
+ expect(tool.requiresProject).toBe(true);
49
+ expect(tool.isAsync).toBe(true);
50
+ });
51
+
52
+ test('getDescription mentions file tree', () => {
53
+ const desc = tool.getDescription();
54
+ expect(desc).toContain('File Tree Tool');
55
+ expect(desc).toContain('maxDepth');
56
+ });
57
+
58
+ test('getRequiredParameters returns empty array', () => {
59
+ expect(tool.getRequiredParameters()).toEqual([]);
60
+ });
61
+
62
+ test('parseParameters parses JSON content', () => {
63
+ const content = JSON.stringify({
64
+ directory: 'src',
65
+ maxDepth: 5,
66
+ includeExtensions: ['.js'],
67
+ showFiles: true
68
+ });
69
+ const result = tool.parseParameters(content);
70
+ expect(result.directory).toBe('src');
71
+ expect(result.maxDepth).toBe(5);
72
+ expect(result.includeExtensions).toEqual(['.js']);
73
+ expect(result.showFiles).toBe(true);
74
+ });
75
+
76
+ test('parseParameters defaults for missing JSON fields', () => {
77
+ const result = tool.parseParameters('{}');
78
+ expect(result.directory).toBe('.');
79
+ expect(result.maxDepth).toBe(3);
80
+ expect(result.showFiles).toBe(true);
81
+ expect(result.showHidden).toBe(false);
82
+ });
83
+
84
+ test('parseParameters handles XML content', () => {
85
+ const content = '<directory>src</directory><max-depth>4</max-depth><show-files>true</show-files>';
86
+ const result = tool.parseParameters(content);
87
+ expect(result.directory).toBe('src');
88
+ expect(result.maxDepth).toBe(4);
89
+ });
90
+
91
+ test('parseParameters returns defaults on parse error', () => {
92
+ const result = tool.parseParameters('{ broken');
93
+ expect(result.directory).toBe('.');
94
+ expect(result).toHaveProperty('parseError');
95
+ });
96
+
97
+ test('customValidateParameters rejects maxDepth exceeding limit', () => {
98
+ expect(() => tool.customValidateParameters({ maxDepth: 100 })).toThrow();
99
+ });
100
+
101
+ test('customValidateParameters rejects maxDepth < 1', () => {
102
+ expect(() => tool.customValidateParameters({ maxDepth: 0 })).toThrow();
103
+ });
104
+
105
+ test('customValidateParameters rejects path traversal', () => {
106
+ expect(() => tool.customValidateParameters({ directory: '../etc' })).toThrow('traversal');
107
+ });
108
+
109
+ test('customValidateParameters rejects non-array includeExtensions', () => {
110
+ expect(() => tool.customValidateParameters({ includeExtensions: '.js' })).toThrow();
111
+ });
112
+
113
+ test('customValidateParameters rejects extension without dot', () => {
114
+ expect(() => tool.customValidateParameters({ includeExtensions: ['js'] })).toThrow('dot');
115
+ });
116
+
117
+ test('customValidateParameters accepts valid params', () => {
118
+ const result = tool.customValidateParameters({
119
+ maxDepth: 3,
120
+ directory: 'src',
121
+ includeExtensions: ['.js'],
122
+ excludeExtensions: ['.test.js'],
123
+ excludeDirectories: ['tests']
124
+ });
125
+ expect(result.valid).toBe(true);
126
+ });
127
+
128
+ test('execute generates directory tree structure', async () => {
129
+ // Root directory stat
130
+ mockFs.stat.mockResolvedValue({ isDirectory: () => true });
131
+
132
+ // Root readdir
133
+ mockFs.readdir.mockResolvedValueOnce([
134
+ mockDirent('src', true),
135
+ mockDirent('package.json')
136
+ ]);
137
+
138
+ // src readdir
139
+ mockFs.readdir.mockResolvedValueOnce([
140
+ mockDirent('index.js'),
141
+ mockDirent('app.js')
142
+ ]);
143
+
144
+ const result = await tool.execute(
145
+ { directory: '.', maxDepth: 3, showFiles: true, showHidden: false },
146
+ context
147
+ );
148
+
149
+ expect(result.success).toBe(true);
150
+ expect(result.tree).toContain('src');
151
+ expect(result.tree).toContain('package.json');
152
+ expect(result.totalFiles).toBeGreaterThanOrEqual(1);
153
+ expect(result.totalDirectories).toBeGreaterThanOrEqual(1);
154
+ expect(result).toHaveProperty('summary');
155
+ });
156
+
157
+ test('execute respects depth limit', async () => {
158
+ mockFs.stat.mockResolvedValue({ isDirectory: () => true });
159
+
160
+ // Root readdir with deep nesting
161
+ mockFs.readdir.mockResolvedValueOnce([
162
+ mockDirent('level1', true)
163
+ ]);
164
+
165
+ // level1 readdir - at depth 1 with maxDepth 1, files at depth 2 should be excluded
166
+ mockFs.readdir.mockResolvedValueOnce([
167
+ mockDirent('deep.js')
168
+ ]);
169
+
170
+ const result = await tool.execute(
171
+ { directory: '.', maxDepth: 1, showFiles: true, showHidden: false },
172
+ context
173
+ );
174
+
175
+ expect(result.success).toBe(true);
176
+ // Files at depth 2 should not appear when maxDepth is 1
177
+ });
178
+
179
+ test('execute ignores node_modules and .git by default', async () => {
180
+ mockFs.stat.mockResolvedValue({ isDirectory: () => true });
181
+
182
+ mockFs.readdir.mockResolvedValueOnce([
183
+ mockDirent('src', true),
184
+ mockDirent('node_modules', true),
185
+ mockDirent('.git', true)
186
+ ]);
187
+
188
+ mockFs.readdir.mockResolvedValueOnce([]); // src is empty
189
+
190
+ const result = await tool.execute(
191
+ { directory: '.', maxDepth: 3, showFiles: true, showHidden: false },
192
+ context
193
+ );
194
+
195
+ expect(result.success).toBe(true);
196
+ expect(result.skippedCount).toBeGreaterThanOrEqual(2); // node_modules, .git skipped
197
+ });
198
+
199
+ test('execute handles empty directory', async () => {
200
+ mockFs.stat.mockResolvedValue({ isDirectory: () => true });
201
+ mockFs.readdir.mockResolvedValueOnce([]);
202
+
203
+ const result = await tool.execute(
204
+ { directory: '.', maxDepth: 3, showFiles: true, showHidden: false },
205
+ context
206
+ );
207
+
208
+ expect(result.success).toBe(true);
209
+ expect(result.totalFiles).toBe(0);
210
+ });
211
+
212
+ test('execute throws for non-existent directory', async () => {
213
+ mockFs.stat.mockRejectedValue(new Error('ENOENT'));
214
+
215
+ await expect(tool.execute(
216
+ { directory: 'nonexistent', maxDepth: 3, showFiles: true, showHidden: false },
217
+ context
218
+ )).rejects.toThrow('does not exist');
219
+ });
220
+
221
+ test('execute with includeExtensions filters files', async () => {
222
+ mockFs.stat.mockResolvedValue({ isDirectory: () => true });
223
+
224
+ mockFs.readdir.mockResolvedValueOnce([
225
+ mockDirent('app.js'),
226
+ mockDirent('style.css'),
227
+ mockDirent('readme.md')
228
+ ]);
229
+
230
+ const result = await tool.execute(
231
+ { directory: '.', maxDepth: 3, showFiles: true, showHidden: false, includeExtensions: ['.js'] },
232
+ context
233
+ );
234
+
235
+ expect(result.success).toBe(true);
236
+ expect(result.tree).toContain('app.js');
237
+ expect(result.tree).not.toContain('style.css');
238
+ expect(result.tree).not.toContain('readme.md');
239
+ });
240
+
241
+ test('formatFileSize formats bytes correctly', () => {
242
+ expect(tool.formatFileSize(500)).toBe('500 B');
243
+ expect(tool.formatFileSize(2048)).toContain('KB');
244
+ expect(tool.formatFileSize(2 * 1024 * 1024)).toContain('MB');
245
+ expect(tool.formatFileSize(2 * 1024 * 1024 * 1024)).toContain('GB');
246
+ });
247
+
248
+ test('generateSummary produces summary text', () => {
249
+ const summary = tool.generateSummary('src', { filesCount: 10, directoriesCount: 3, skippedCount: 2 }, 4);
250
+ expect(summary).toContain('src');
251
+ expect(summary).toContain('10');
252
+ expect(summary).toContain('3');
253
+ });
254
+
255
+ test('formatTree handles null node', () => {
256
+ expect(tool.formatTree(null)).toBe('');
257
+ });
258
+
259
+ test('execute uses directoryAccess working directory', async () => {
260
+ mockFs.stat.mockResolvedValue({ isDirectory: () => true });
261
+ mockFs.readdir.mockResolvedValueOnce([]);
262
+
263
+ const result = await tool.execute(
264
+ { directory: '.', maxDepth: 2, showFiles: true, showHidden: false },
265
+ {
266
+ projectDir: '/project',
267
+ agentId: 'agent-1',
268
+ directoryAccess: { workingDirectory: '/custom/dir' }
269
+ }
270
+ );
271
+
272
+ expect(result.success).toBe(true);
273
+ });
274
+ });