@google/gemini-cli-core 0.5.0-preview.1 → 0.7.0-nightly.20250912.68035591
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/LICENSE +2 -2
- package/README.md +12 -2
- package/dist/google-gemini-cli-core-0.6.0-nightly.tgz +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/config/config.d.ts +24 -1
- package/dist/src/config/config.js +58 -15
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +11 -15
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/models.d.ts +14 -0
- package/dist/src/config/models.js +26 -0
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/models.test.d.ts +6 -0
- package/dist/src/config/models.test.js +55 -0
- package/dist/src/config/models.test.js.map +1 -0
- package/dist/src/confirmation-bus/index.d.ts +7 -0
- package/dist/src/confirmation-bus/index.js +8 -0
- package/dist/src/confirmation-bus/index.js.map +1 -0
- package/dist/src/confirmation-bus/message-bus.d.ts +17 -0
- package/dist/src/confirmation-bus/message-bus.js +81 -0
- package/dist/src/confirmation-bus/message-bus.js.map +1 -0
- package/dist/src/confirmation-bus/message-bus.test.d.ts +6 -0
- package/dist/src/confirmation-bus/message-bus.test.js +164 -0
- package/dist/src/confirmation-bus/message-bus.test.js.map +1 -0
- package/dist/src/confirmation-bus/types.d.ts +38 -0
- package/dist/src/confirmation-bus/types.js +15 -0
- package/dist/src/confirmation-bus/types.js.map +1 -0
- package/dist/src/core/client.d.ts +4 -1
- package/dist/src/core/client.js +46 -18
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +156 -46
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +0 -1
- package/dist/src/core/contentGenerator.js +0 -4
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +0 -3
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +4 -3
- package/dist/src/core/coreToolScheduler.js +42 -5
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +34 -0
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +1 -22
- package/dist/src/core/geminiChat.js +15 -135
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +59 -312
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +48 -0
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/subagent.js +1 -1
- package/dist/src/core/subagent.js.map +1 -1
- package/dist/src/core/subagent.test.js +9 -8
- package/dist/src/core/subagent.test.js.map +1 -1
- package/dist/src/core/turn.d.ts +2 -1
- package/dist/src/core/turn.js +2 -2
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/core/turn.test.js +18 -18
- package/dist/src/core/turn.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/ide/ide-client.d.ts +27 -0
- package/dist/src/ide/ide-client.js +85 -5
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/ide/ide-client.test.js +53 -0
- package/dist/src/ide/ide-client.test.js.map +1 -1
- package/dist/src/ide/ideContext.d.ts +34 -20
- package/dist/src/ide/ideContext.js +20 -33
- package/dist/src/ide/ideContext.js.map +1 -1
- package/dist/src/ide/ideContext.test.js +37 -39
- package/dist/src/ide/ideContext.test.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/output/json-formatter.d.ts +11 -0
- package/dist/src/output/json-formatter.js +30 -0
- package/dist/src/output/json-formatter.js.map +1 -0
- package/dist/src/output/json-formatter.test.d.ts +6 -0
- package/dist/src/output/json-formatter.test.js +266 -0
- package/dist/src/output/json-formatter.test.js.map +1 -0
- package/dist/src/output/types.d.ts +20 -0
- package/dist/src/output/types.js +11 -0
- package/dist/src/output/types.js.map +1 -0
- package/dist/src/policy/index.d.ts +7 -0
- package/dist/src/policy/index.js +8 -0
- package/dist/src/policy/index.js.map +1 -0
- package/dist/src/policy/policy-engine.d.ts +30 -0
- package/dist/src/policy/policy-engine.js +83 -0
- package/dist/src/policy/policy-engine.js.map +1 -0
- package/dist/src/policy/policy-engine.test.d.ts +6 -0
- package/dist/src/policy/policy-engine.test.js +470 -0
- package/dist/src/policy/policy-engine.test.js.map +1 -0
- package/dist/src/policy/stable-stringify.d.ts +58 -0
- package/dist/src/policy/stable-stringify.js +122 -0
- package/dist/src/policy/stable-stringify.js.map +1 -0
- package/dist/src/policy/types.d.ts +47 -0
- package/dist/src/policy/types.js +12 -0
- package/dist/src/policy/types.js.map +1 -0
- package/dist/src/routing/modelRouterService.d.ts +23 -0
- package/dist/src/routing/modelRouterService.js +36 -0
- package/dist/src/routing/modelRouterService.js.map +1 -0
- package/dist/src/routing/modelRouterService.test.d.ts +6 -0
- package/dist/src/routing/modelRouterService.test.js +72 -0
- package/dist/src/routing/modelRouterService.test.js.map +1 -0
- package/dist/src/routing/routingStrategy.d.ts +62 -0
- package/dist/src/routing/routingStrategy.js +7 -0
- package/dist/src/routing/routingStrategy.js.map +1 -0
- package/dist/src/routing/strategies/compositeStrategy.d.ts +26 -0
- package/dist/src/routing/strategies/compositeStrategy.js +67 -0
- package/dist/src/routing/strategies/compositeStrategy.js.map +1 -0
- package/dist/src/routing/strategies/compositeStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/compositeStrategy.test.js +123 -0
- package/dist/src/routing/strategies/compositeStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/defaultStrategy.d.ts +12 -0
- package/dist/src/routing/strategies/defaultStrategy.js +20 -0
- package/dist/src/routing/strategies/defaultStrategy.js.map +1 -0
- package/dist/src/routing/strategies/defaultStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/defaultStrategy.test.js +26 -0
- package/dist/src/routing/strategies/defaultStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/fallbackStrategy.d.ts +12 -0
- package/dist/src/routing/strategies/fallbackStrategy.js +25 -0
- package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.js +55 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/overrideStrategy.d.ts +15 -0
- package/dist/src/routing/strategies/overrideStrategy.js +27 -0
- package/dist/src/routing/strategies/overrideStrategy.js.map +1 -0
- package/dist/src/routing/strategies/overrideStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/overrideStrategy.test.js +41 -0
- package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.d.ts +10 -0
- package/dist/src/services/fileDiscoveryService.js +31 -17
- package/dist/src/services/fileDiscoveryService.js.map +1 -1
- package/dist/src/services/loopDetectionService.d.ts +5 -0
- package/dist/src/services/loopDetectionService.js +13 -2
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +15 -0
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.d.ts +34 -2
- package/dist/src/services/shellExecutionService.js +177 -43
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +153 -56
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +4 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +31 -4
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +6 -2
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +14 -2
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +2 -2
- package/dist/src/telemetry/index.js +2 -2
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +2 -1
- package/dist/src/telemetry/loggers.js +20 -5
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +50 -35
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +1 -1
- package/dist/src/telemetry/metrics.js +2 -2
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +23 -3
- package/dist/src/telemetry/types.js +25 -3
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/tools/edit.js +2 -3
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +2 -8
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.d.ts +5 -1
- package/dist/src/tools/glob.js +24 -17
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +51 -0
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/ls.js +19 -32
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.js +140 -280
- package/dist/src/tools/ls.test.js.map +1 -1
- package/dist/src/tools/read-many-files.d.ts +1 -1
- package/dist/src/tools/read-many-files.js +17 -49
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/ripGrep.d.ts +4 -0
- package/dist/src/tools/ripGrep.js +11 -1
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/ripGrep.test.js +51 -1
- package/dist/src/tools/ripGrep.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +12 -2
- package/dist/src/tools/shell.js +12 -16
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +2 -33
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/smart-edit.js +2 -3
- package/dist/src/tools/smart-edit.js.map +1 -1
- package/dist/src/tools/smart-edit.test.js +2 -8
- package/dist/src/tools/smart-edit.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +6 -4
- package/dist/src/tools/tools.js +2 -2
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/write-file.js +2 -3
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +78 -0
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.js +11 -5
- package/dist/src/utils/bfsFileSearch.js.map +1 -1
- package/dist/src/utils/errors.d.ts +6 -0
- package/dist/src/utils/errors.js +10 -0
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/geminiIgnoreParser.d.ts +18 -0
- package/dist/src/utils/geminiIgnoreParser.js +61 -0
- package/dist/src/utils/geminiIgnoreParser.js.map +1 -0
- package/dist/src/utils/geminiIgnoreParser.test.d.ts +6 -0
- package/dist/src/utils/geminiIgnoreParser.test.js +50 -0
- package/dist/src/utils/geminiIgnoreParser.test.js.map +1 -0
- package/dist/src/utils/gitIgnoreParser.d.ts +3 -9
- package/dist/src/utils/gitIgnoreParser.js +60 -69
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.test.js +18 -53
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
- package/dist/src/utils/terminalSerializer.d.ts +28 -0
- package/dist/src/utils/terminalSerializer.js +432 -0
- package/dist/src/utils/terminalSerializer.js.map +1 -0
- package/dist/src/utils/terminalSerializer.test.d.ts +6 -0
- package/dist/src/utils/terminalSerializer.test.js +176 -0
- package/dist/src/utils/terminalSerializer.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/google-gemini-cli-core-0.5.0-preview.tgz +0 -0
- package/dist/src/utils/ide-trust.d.ts +0 -10
- package/dist/src/utils/ide-trust.js +0 -14
- package/dist/src/utils/ide-trust.js.map +0 -1
package/dist/src/tools/ls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/tools/ls.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/tools/ls.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,361 +3,234 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import fs from 'node:fs';
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
9
8
|
import path from 'node:path';
|
|
10
|
-
|
|
11
|
-
default: {
|
|
12
|
-
statSync: vi.fn(),
|
|
13
|
-
readdirSync: vi.fn(),
|
|
14
|
-
},
|
|
15
|
-
statSync: vi.fn(),
|
|
16
|
-
readdirSync: vi.fn(),
|
|
17
|
-
mkdirSync: vi.fn(),
|
|
18
|
-
}));
|
|
9
|
+
import os from 'node:os';
|
|
19
10
|
import { LSTool } from './ls.js';
|
|
11
|
+
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
|
20
12
|
import { ToolErrorType } from './tool-error.js';
|
|
13
|
+
import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js';
|
|
21
14
|
describe('LSTool', () => {
|
|
22
15
|
let lsTool;
|
|
16
|
+
let tempRootDir;
|
|
17
|
+
let tempSecondaryDir;
|
|
23
18
|
let mockConfig;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
mockWorkspaceContext = {
|
|
32
|
-
getDirectories: vi
|
|
33
|
-
.fn()
|
|
34
|
-
.mockReturnValue([mockPrimaryDir, mockSecondaryDir]),
|
|
35
|
-
isPathWithinWorkspace: vi
|
|
36
|
-
.fn()
|
|
37
|
-
.mockImplementation((path) => path.startsWith(mockPrimaryDir) ||
|
|
38
|
-
path.startsWith(mockSecondaryDir)),
|
|
39
|
-
addDirectory: vi.fn(),
|
|
40
|
-
};
|
|
41
|
-
// Mock FileService
|
|
42
|
-
mockFileService = {
|
|
43
|
-
shouldGitIgnoreFile: vi.fn().mockReturnValue(false),
|
|
44
|
-
shouldGeminiIgnoreFile: vi.fn().mockReturnValue(false),
|
|
45
|
-
};
|
|
46
|
-
// Mock Config
|
|
19
|
+
const abortSignal = new AbortController().signal;
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
tempRootDir = await fs.mkdtemp(path.join(os.tmpdir(), 'ls-tool-root-'));
|
|
22
|
+
tempSecondaryDir = await fs.mkdtemp(path.join(os.tmpdir(), 'ls-tool-secondary-'));
|
|
23
|
+
const mockWorkspaceContext = createMockWorkspaceContext(tempRootDir, [
|
|
24
|
+
tempSecondaryDir,
|
|
25
|
+
]);
|
|
47
26
|
mockConfig = {
|
|
48
|
-
getTargetDir:
|
|
49
|
-
getWorkspaceContext:
|
|
50
|
-
getFileService:
|
|
51
|
-
getFileFilteringOptions:
|
|
27
|
+
getTargetDir: () => tempRootDir,
|
|
28
|
+
getWorkspaceContext: () => mockWorkspaceContext,
|
|
29
|
+
getFileService: () => new FileDiscoveryService(tempRootDir),
|
|
30
|
+
getFileFilteringOptions: () => ({
|
|
52
31
|
respectGitIgnore: true,
|
|
53
32
|
respectGeminiIgnore: true,
|
|
54
33
|
}),
|
|
55
34
|
};
|
|
56
35
|
lsTool = new LSTool(mockConfig);
|
|
57
36
|
});
|
|
37
|
+
afterEach(async () => {
|
|
38
|
+
await fs.rm(tempRootDir, { recursive: true, force: true });
|
|
39
|
+
await fs.rm(tempSecondaryDir, { recursive: true, force: true });
|
|
40
|
+
});
|
|
58
41
|
describe('parameter validation', () => {
|
|
59
|
-
it('should accept valid absolute paths within workspace', () => {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
};
|
|
63
|
-
vi.mocked(fs.statSync).mockReturnValue({
|
|
64
|
-
isDirectory: () => true,
|
|
65
|
-
});
|
|
66
|
-
const invocation = lsTool.build(params);
|
|
42
|
+
it('should accept valid absolute paths within workspace', async () => {
|
|
43
|
+
const testPath = path.join(tempRootDir, 'src');
|
|
44
|
+
await fs.mkdir(testPath);
|
|
45
|
+
const invocation = lsTool.build({ path: testPath });
|
|
67
46
|
expect(invocation).toBeDefined();
|
|
68
47
|
});
|
|
69
48
|
it('should reject relative paths', () => {
|
|
70
|
-
|
|
71
|
-
path: './src',
|
|
72
|
-
};
|
|
73
|
-
expect(() => lsTool.build(params)).toThrow('Path must be absolute: ./src');
|
|
49
|
+
expect(() => lsTool.build({ path: './src' })).toThrow('Path must be absolute: ./src');
|
|
74
50
|
});
|
|
75
51
|
it('should reject paths outside workspace with clear error message', () => {
|
|
76
|
-
|
|
77
|
-
path: '/etc/passwd',
|
|
78
|
-
};
|
|
79
|
-
expect(() => lsTool.build(params)).toThrow('Path must be within one of the workspace directories: /home/user/project, /home/user/other-project');
|
|
52
|
+
expect(() => lsTool.build({ path: '/etc/passwd' })).toThrow(`Path must be within one of the workspace directories: ${tempRootDir}, ${tempSecondaryDir}`);
|
|
80
53
|
});
|
|
81
|
-
it('should accept paths in secondary workspace directory', () => {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
vi.mocked(fs.statSync).mockReturnValue({
|
|
86
|
-
isDirectory: () => true,
|
|
87
|
-
});
|
|
88
|
-
const invocation = lsTool.build(params);
|
|
54
|
+
it('should accept paths in secondary workspace directory', async () => {
|
|
55
|
+
const testPath = path.join(tempSecondaryDir, 'lib');
|
|
56
|
+
await fs.mkdir(testPath);
|
|
57
|
+
const invocation = lsTool.build({ path: testPath });
|
|
89
58
|
expect(invocation).toBeDefined();
|
|
90
59
|
});
|
|
91
60
|
});
|
|
92
61
|
describe('execute', () => {
|
|
93
62
|
it('should list files in a directory', async () => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
size: 1024,
|
|
100
|
-
};
|
|
101
|
-
vi.mocked(fs.statSync).mockImplementation((path) => {
|
|
102
|
-
const pathStr = path.toString();
|
|
103
|
-
if (pathStr === testPath) {
|
|
104
|
-
return { isDirectory: () => true };
|
|
105
|
-
}
|
|
106
|
-
// For individual files
|
|
107
|
-
if (pathStr.toString().endsWith('subdir')) {
|
|
108
|
-
return { ...mockStats, isDirectory: () => true, size: 0 };
|
|
109
|
-
}
|
|
110
|
-
return { ...mockStats, isDirectory: () => false };
|
|
111
|
-
});
|
|
112
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
113
|
-
const invocation = lsTool.build({ path: testPath });
|
|
114
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
63
|
+
await fs.writeFile(path.join(tempRootDir, 'file1.txt'), 'content1');
|
|
64
|
+
await fs.mkdir(path.join(tempRootDir, 'subdir'));
|
|
65
|
+
await fs.writeFile(path.join(tempSecondaryDir, 'secondary-file.txt'), 'secondary');
|
|
66
|
+
const invocation = lsTool.build({ path: tempRootDir });
|
|
67
|
+
const result = await invocation.execute(abortSignal);
|
|
115
68
|
expect(result.llmContent).toContain('[DIR] subdir');
|
|
116
|
-
expect(result.llmContent).toContain('file1.
|
|
117
|
-
expect(result.
|
|
118
|
-
expect(result.returnDisplay).toBe('Listed 3 item(s).');
|
|
69
|
+
expect(result.llmContent).toContain('file1.txt');
|
|
70
|
+
expect(result.returnDisplay).toBe('Listed 2 item(s).');
|
|
119
71
|
});
|
|
120
72
|
it('should list files from secondary workspace directory', async () => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
isDirectory: () => false,
|
|
129
|
-
mtime: new Date(),
|
|
130
|
-
size: 2048,
|
|
131
|
-
};
|
|
132
|
-
});
|
|
133
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
134
|
-
const invocation = lsTool.build({ path: testPath });
|
|
135
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
136
|
-
expect(result.llmContent).toContain('module1.js');
|
|
137
|
-
expect(result.llmContent).toContain('module2.js');
|
|
138
|
-
expect(result.returnDisplay).toBe('Listed 2 item(s).');
|
|
73
|
+
await fs.writeFile(path.join(tempRootDir, 'file1.txt'), 'content1');
|
|
74
|
+
await fs.mkdir(path.join(tempRootDir, 'subdir'));
|
|
75
|
+
await fs.writeFile(path.join(tempSecondaryDir, 'secondary-file.txt'), 'secondary');
|
|
76
|
+
const invocation = lsTool.build({ path: tempSecondaryDir });
|
|
77
|
+
const result = await invocation.execute(abortSignal);
|
|
78
|
+
expect(result.llmContent).toContain('secondary-file.txt');
|
|
79
|
+
expect(result.returnDisplay).toBe('Listed 1 item(s).');
|
|
139
80
|
});
|
|
140
81
|
it('should handle empty directories', async () => {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const invocation = lsTool.build({ path: testPath });
|
|
147
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
148
|
-
expect(result.llmContent).toBe('Directory /home/user/project/empty is empty.');
|
|
82
|
+
const emptyDir = path.join(tempRootDir, 'empty');
|
|
83
|
+
await fs.mkdir(emptyDir);
|
|
84
|
+
const invocation = lsTool.build({ path: emptyDir });
|
|
85
|
+
const result = await invocation.execute(abortSignal);
|
|
86
|
+
expect(result.llmContent).toBe(`Directory ${emptyDir} is empty.`);
|
|
149
87
|
expect(result.returnDisplay).toBe('Directory is empty.');
|
|
150
88
|
});
|
|
151
89
|
it('should respect ignore patterns', async () => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
vi.mocked(fs.statSync).mockImplementation((path) => {
|
|
155
|
-
const pathStr = path.toString();
|
|
156
|
-
if (pathStr === testPath) {
|
|
157
|
-
return { isDirectory: () => true };
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
isDirectory: () => false,
|
|
161
|
-
mtime: new Date(),
|
|
162
|
-
size: 1024,
|
|
163
|
-
};
|
|
164
|
-
});
|
|
165
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
90
|
+
await fs.writeFile(path.join(tempRootDir, 'file1.txt'), 'content1');
|
|
91
|
+
await fs.writeFile(path.join(tempRootDir, 'file2.log'), 'content1');
|
|
166
92
|
const invocation = lsTool.build({
|
|
167
|
-
path:
|
|
168
|
-
ignore: ['*.
|
|
93
|
+
path: tempRootDir,
|
|
94
|
+
ignore: ['*.log'],
|
|
169
95
|
});
|
|
170
|
-
const result = await invocation.execute(
|
|
171
|
-
expect(result.llmContent).toContain('
|
|
172
|
-
expect(result.llmContent).toContain('
|
|
173
|
-
expect(result.
|
|
174
|
-
expect(result.returnDisplay).toBe('Listed 2 item(s).');
|
|
96
|
+
const result = await invocation.execute(abortSignal);
|
|
97
|
+
expect(result.llmContent).toContain('file1.txt');
|
|
98
|
+
expect(result.llmContent).not.toContain('file2.log');
|
|
99
|
+
expect(result.returnDisplay).toBe('Listed 1 item(s).');
|
|
175
100
|
});
|
|
176
101
|
it('should respect gitignore patterns', async () => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
size: 1024,
|
|
188
|
-
};
|
|
189
|
-
});
|
|
190
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
191
|
-
mockFileService.shouldGitIgnoreFile.mockImplementation((path) => path.includes('ignored.js'));
|
|
192
|
-
const invocation = lsTool.build({ path: testPath });
|
|
193
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
194
|
-
expect(result.llmContent).toContain('file1.js');
|
|
195
|
-
expect(result.llmContent).toContain('file2.js');
|
|
196
|
-
expect(result.llmContent).not.toContain('ignored.js');
|
|
197
|
-
expect(result.returnDisplay).toBe('Listed 2 item(s). (1 git-ignored)');
|
|
102
|
+
await fs.writeFile(path.join(tempRootDir, 'file1.txt'), 'content1');
|
|
103
|
+
await fs.writeFile(path.join(tempRootDir, 'file2.log'), 'content1');
|
|
104
|
+
await fs.writeFile(path.join(tempRootDir, '.git'), '');
|
|
105
|
+
await fs.writeFile(path.join(tempRootDir, '.gitignore'), '*.log');
|
|
106
|
+
const invocation = lsTool.build({ path: tempRootDir });
|
|
107
|
+
const result = await invocation.execute(abortSignal);
|
|
108
|
+
expect(result.llmContent).toContain('file1.txt');
|
|
109
|
+
expect(result.llmContent).not.toContain('file2.log');
|
|
110
|
+
// .git is always ignored by default.
|
|
111
|
+
expect(result.returnDisplay).toBe('Listed 2 item(s). (2 git-ignored)');
|
|
198
112
|
});
|
|
199
113
|
it('should respect geminiignore patterns', async () => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return {
|
|
208
|
-
isDirectory: () => false,
|
|
209
|
-
mtime: new Date(),
|
|
210
|
-
size: 1024,
|
|
211
|
-
};
|
|
212
|
-
});
|
|
213
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
214
|
-
mockFileService.shouldGeminiIgnoreFile.mockImplementation((path) => path.includes('private.js'));
|
|
215
|
-
const invocation = lsTool.build({ path: testPath });
|
|
216
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
217
|
-
expect(result.llmContent).toContain('file1.js');
|
|
218
|
-
expect(result.llmContent).toContain('file2.js');
|
|
219
|
-
expect(result.llmContent).not.toContain('private.js');
|
|
114
|
+
await fs.writeFile(path.join(tempRootDir, 'file1.txt'), 'content1');
|
|
115
|
+
await fs.writeFile(path.join(tempRootDir, 'file2.log'), 'content1');
|
|
116
|
+
await fs.writeFile(path.join(tempRootDir, '.geminiignore'), '*.log');
|
|
117
|
+
const invocation = lsTool.build({ path: tempRootDir });
|
|
118
|
+
const result = await invocation.execute(abortSignal);
|
|
119
|
+
expect(result.llmContent).toContain('file1.txt');
|
|
120
|
+
expect(result.llmContent).not.toContain('file2.log');
|
|
220
121
|
expect(result.returnDisplay).toBe('Listed 2 item(s). (1 gemini-ignored)');
|
|
221
122
|
});
|
|
222
123
|
it('should handle non-directory paths', async () => {
|
|
223
|
-
const testPath = '
|
|
224
|
-
|
|
225
|
-
isDirectory: () => false,
|
|
226
|
-
});
|
|
124
|
+
const testPath = path.join(tempRootDir, 'file1.txt');
|
|
125
|
+
await fs.writeFile(testPath, 'content1');
|
|
227
126
|
const invocation = lsTool.build({ path: testPath });
|
|
228
|
-
const result = await invocation.execute(
|
|
127
|
+
const result = await invocation.execute(abortSignal);
|
|
229
128
|
expect(result.llmContent).toContain('Path is not a directory');
|
|
230
129
|
expect(result.returnDisplay).toBe('Error: Path is not a directory.');
|
|
231
130
|
expect(result.error?.type).toBe(ToolErrorType.PATH_IS_NOT_A_DIRECTORY);
|
|
232
131
|
});
|
|
233
132
|
it('should handle non-existent paths', async () => {
|
|
234
|
-
const testPath = '
|
|
235
|
-
vi.mocked(fs.statSync).mockImplementation(() => {
|
|
236
|
-
throw new Error('ENOENT: no such file or directory');
|
|
237
|
-
});
|
|
133
|
+
const testPath = path.join(tempRootDir, 'does-not-exist');
|
|
238
134
|
const invocation = lsTool.build({ path: testPath });
|
|
239
|
-
const result = await invocation.execute(
|
|
135
|
+
const result = await invocation.execute(abortSignal);
|
|
240
136
|
expect(result.llmContent).toContain('Error listing directory');
|
|
241
137
|
expect(result.returnDisplay).toBe('Error: Failed to list directory.');
|
|
242
138
|
expect(result.error?.type).toBe(ToolErrorType.LS_EXECUTION_ERROR);
|
|
243
139
|
});
|
|
244
140
|
it('should sort directories first, then files alphabetically', async () => {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
isDirectory: () => false,
|
|
260
|
-
mtime: new Date(),
|
|
261
|
-
size: 1024,
|
|
262
|
-
};
|
|
263
|
-
});
|
|
264
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
265
|
-
const invocation = lsTool.build({ path: testPath });
|
|
266
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
267
|
-
const lines = (typeof result.llmContent === 'string' ? result.llmContent : '').split('\n');
|
|
268
|
-
const entries = lines.slice(1).filter((line) => line.trim()); // Skip header
|
|
269
|
-
expect(entries[0]).toBe('[DIR] a-dir');
|
|
270
|
-
expect(entries[1]).toBe('[DIR] c-dir');
|
|
271
|
-
expect(entries[2]).toBe('b-file.ts');
|
|
272
|
-
expect(entries[3]).toBe('z-file.ts');
|
|
141
|
+
await fs.writeFile(path.join(tempRootDir, 'a-file.txt'), 'content1');
|
|
142
|
+
await fs.writeFile(path.join(tempRootDir, 'b-file.txt'), 'content1');
|
|
143
|
+
await fs.mkdir(path.join(tempRootDir, 'x-dir'));
|
|
144
|
+
await fs.mkdir(path.join(tempRootDir, 'y-dir'));
|
|
145
|
+
const invocation = lsTool.build({ path: tempRootDir });
|
|
146
|
+
const result = await invocation.execute(abortSignal);
|
|
147
|
+
const lines = (typeof result.llmContent === 'string' ? result.llmContent : '')
|
|
148
|
+
.split('\n')
|
|
149
|
+
.filter(Boolean);
|
|
150
|
+
const entries = lines.slice(1); // Skip header
|
|
151
|
+
expect(entries[0]).toBe('[DIR] x-dir');
|
|
152
|
+
expect(entries[1]).toBe('[DIR] y-dir');
|
|
153
|
+
expect(entries[2]).toBe('a-file.txt');
|
|
154
|
+
expect(entries[3]).toBe('b-file.txt');
|
|
273
155
|
});
|
|
274
156
|
it('should handle permission errors gracefully', async () => {
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
});
|
|
282
|
-
const
|
|
283
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
157
|
+
const restrictedDir = path.join(tempRootDir, 'restricted');
|
|
158
|
+
await fs.mkdir(restrictedDir);
|
|
159
|
+
// To simulate a permission error in a cross-platform way,
|
|
160
|
+
// we mock fs.readdir to throw an error.
|
|
161
|
+
const error = new Error('EACCES: permission denied');
|
|
162
|
+
vi.spyOn(fs, 'readdir').mockRejectedValueOnce(error);
|
|
163
|
+
const invocation = lsTool.build({ path: restrictedDir });
|
|
164
|
+
const result = await invocation.execute(abortSignal);
|
|
284
165
|
expect(result.llmContent).toContain('Error listing directory');
|
|
285
166
|
expect(result.llmContent).toContain('permission denied');
|
|
286
167
|
expect(result.returnDisplay).toBe('Error: Failed to list directory.');
|
|
287
168
|
expect(result.error?.type).toBe(ToolErrorType.LS_EXECUTION_ERROR);
|
|
288
169
|
});
|
|
289
|
-
it('should throw for invalid params at build time',
|
|
170
|
+
it('should throw for invalid params at build time', () => {
|
|
290
171
|
expect(() => lsTool.build({ path: '../outside' })).toThrow('Path must be absolute: ../outside');
|
|
291
172
|
});
|
|
292
173
|
it('should handle errors accessing individual files during listing', async () => {
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
174
|
+
await fs.writeFile(path.join(tempRootDir, 'file1.txt'), 'content1');
|
|
175
|
+
const problematicFile = path.join(tempRootDir, 'problematic.txt');
|
|
176
|
+
await fs.writeFile(problematicFile, 'content2');
|
|
177
|
+
// To simulate an error on a single file in a cross-platform way,
|
|
178
|
+
// we mock fs.stat to throw for a specific file. This avoids
|
|
179
|
+
// platform-specific behavior with things like dangling symlinks.
|
|
180
|
+
const originalStat = fs.stat;
|
|
181
|
+
const statSpy = vi.spyOn(fs, 'stat').mockImplementation(async (p) => {
|
|
182
|
+
if (p.toString() === problematicFile) {
|
|
183
|
+
throw new Error('Simulated stat error');
|
|
298
184
|
}
|
|
299
|
-
|
|
300
|
-
throw new Error('EACCES: permission denied');
|
|
301
|
-
}
|
|
302
|
-
return {
|
|
303
|
-
isDirectory: () => false,
|
|
304
|
-
mtime: new Date(),
|
|
305
|
-
size: 1024,
|
|
306
|
-
};
|
|
185
|
+
return originalStat(p);
|
|
307
186
|
});
|
|
308
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
309
187
|
// Spy on console.error to verify it's called
|
|
310
188
|
const consoleErrorSpy = vi
|
|
311
189
|
.spyOn(console, 'error')
|
|
312
190
|
.mockImplementation(() => { });
|
|
313
|
-
const invocation = lsTool.build({ path:
|
|
314
|
-
const result = await invocation.execute(
|
|
315
|
-
// Should still list the
|
|
316
|
-
expect(result.llmContent).toContain('
|
|
317
|
-
expect(result.llmContent).not.toContain('
|
|
191
|
+
const invocation = lsTool.build({ path: tempRootDir });
|
|
192
|
+
const result = await invocation.execute(abortSignal);
|
|
193
|
+
// Should still list the other files
|
|
194
|
+
expect(result.llmContent).toContain('file1.txt');
|
|
195
|
+
expect(result.llmContent).not.toContain('problematic.txt');
|
|
318
196
|
expect(result.returnDisplay).toBe('Listed 1 item(s).');
|
|
319
197
|
// Verify error was logged
|
|
320
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.
|
|
198
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringMatching(/Error accessing.*problematic\.txt/s));
|
|
199
|
+
statSpy.mockRestore();
|
|
321
200
|
consoleErrorSpy.mockRestore();
|
|
322
201
|
});
|
|
323
202
|
});
|
|
324
203
|
describe('getDescription', () => {
|
|
325
204
|
it('should return shortened relative path', () => {
|
|
205
|
+
const deeplyNestedDir = path.join(tempRootDir, 'deeply', 'nested');
|
|
326
206
|
const params = {
|
|
327
|
-
path:
|
|
207
|
+
path: path.join(deeplyNestedDir, 'directory'),
|
|
328
208
|
};
|
|
329
|
-
vi.mocked(fs.statSync).mockReturnValue({
|
|
330
|
-
isDirectory: () => true,
|
|
331
|
-
});
|
|
332
209
|
const invocation = lsTool.build(params);
|
|
333
210
|
const description = invocation.getDescription();
|
|
334
211
|
expect(description).toBe(path.join('deeply', 'nested', 'directory'));
|
|
335
212
|
});
|
|
336
213
|
it('should handle paths in secondary workspace', () => {
|
|
337
214
|
const params = {
|
|
338
|
-
path:
|
|
215
|
+
path: path.join(tempSecondaryDir, 'lib'),
|
|
339
216
|
};
|
|
340
|
-
vi.mocked(fs.statSync).mockReturnValue({
|
|
341
|
-
isDirectory: () => true,
|
|
342
|
-
});
|
|
343
217
|
const invocation = lsTool.build(params);
|
|
344
218
|
const description = invocation.getDescription();
|
|
345
|
-
|
|
219
|
+
const expected = path.relative(tempRootDir, params.path);
|
|
220
|
+
expect(description).toBe(expected);
|
|
346
221
|
});
|
|
347
222
|
});
|
|
348
223
|
describe('workspace boundary validation', () => {
|
|
349
|
-
it('should accept paths in primary workspace directory', () => {
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
});
|
|
224
|
+
it('should accept paths in primary workspace directory', async () => {
|
|
225
|
+
const testPath = path.join(tempRootDir, 'src');
|
|
226
|
+
await fs.mkdir(testPath);
|
|
227
|
+
const params = { path: testPath };
|
|
354
228
|
expect(lsTool.build(params)).toBeDefined();
|
|
355
229
|
});
|
|
356
|
-
it('should accept paths in secondary workspace directory', () => {
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
});
|
|
230
|
+
it('should accept paths in secondary workspace directory', async () => {
|
|
231
|
+
const testPath = path.join(tempSecondaryDir, 'lib');
|
|
232
|
+
await fs.mkdir(testPath);
|
|
233
|
+
const params = { path: testPath };
|
|
361
234
|
expect(lsTool.build(params)).toBeDefined();
|
|
362
235
|
});
|
|
363
236
|
it('should reject paths outside all workspace directories', () => {
|
|
@@ -365,24 +238,11 @@ describe('LSTool', () => {
|
|
|
365
238
|
expect(() => lsTool.build(params)).toThrow('Path must be within one of the workspace directories');
|
|
366
239
|
});
|
|
367
240
|
it('should list files from secondary workspace directory', async () => {
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
return {
|
|
375
|
-
isDirectory: () => false,
|
|
376
|
-
mtime: new Date(),
|
|
377
|
-
size: 512,
|
|
378
|
-
};
|
|
379
|
-
});
|
|
380
|
-
vi.mocked(fs.readdirSync).mockReturnValue(mockFiles);
|
|
381
|
-
const invocation = lsTool.build({ path: testPath });
|
|
382
|
-
const result = await invocation.execute(new AbortController().signal);
|
|
383
|
-
expect(result.llmContent).toContain('test1.spec.ts');
|
|
384
|
-
expect(result.llmContent).toContain('test2.spec.ts');
|
|
385
|
-
expect(result.returnDisplay).toBe('Listed 2 item(s).');
|
|
241
|
+
await fs.writeFile(path.join(tempSecondaryDir, 'secondary-file.txt'), 'secondary');
|
|
242
|
+
const invocation = lsTool.build({ path: tempSecondaryDir });
|
|
243
|
+
const result = await invocation.execute(abortSignal);
|
|
244
|
+
expect(result.llmContent).toContain('secondary-file.txt');
|
|
245
|
+
expect(result.returnDisplay).toBe('Listed 1 item(s).');
|
|
386
246
|
});
|
|
387
247
|
});
|
|
388
248
|
});
|