@machina.ai/cell-cli-core 1.49.0-rc6 → 1.51.0-rc1

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 (124) hide show
  1. package/dist/docs/CHANGES.md +23 -0
  2. package/dist/docs/adr/001-openai-xai-compatible-adapters.md +75 -0
  3. package/dist/docs/changelogs/preview.md +11 -3
  4. package/dist/docs/cli/settings.md +21 -1
  5. package/dist/docs/reference/configuration.md +150 -39
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/package.json +2 -2
  10. package/dist/src/agents/agentLoader.d.ts +4 -4
  11. package/dist/src/agents/browser/browserAgentDefinition.js +2 -2
  12. package/dist/src/agents/browser/browserAgentDefinition.js.map +1 -1
  13. package/dist/src/agents/codebase-investigator.js +2 -2
  14. package/dist/src/agents/codebase-investigator.js.map +1 -1
  15. package/dist/src/agents/skill-extraction-agent.js +2 -2
  16. package/dist/src/agents/skill-extraction-agent.js.map +1 -1
  17. package/dist/src/billing/billing.js +3 -1
  18. package/dist/src/billing/billing.js.map +1 -1
  19. package/dist/src/code_assist/types.d.ts +20 -20
  20. package/dist/src/config/config.d.ts +9 -0
  21. package/dist/src/config/config.js +33 -0
  22. package/dist/src/config/config.js.map +1 -1
  23. package/dist/src/config/config.test.js +11 -1
  24. package/dist/src/config/config.test.js.map +1 -1
  25. package/dist/src/config/defaultModelConfigs.js +91 -25
  26. package/dist/src/config/defaultModelConfigs.js.map +1 -1
  27. package/dist/src/config/extensions/integrityTypes.d.ts +2 -2
  28. package/dist/src/config/localModel.test.d.ts +6 -0
  29. package/dist/src/config/localModel.test.js +114 -0
  30. package/dist/src/config/localModel.test.js.map +1 -0
  31. package/dist/src/config/models.d.ts +18 -1
  32. package/dist/src/config/models.js +90 -7
  33. package/dist/src/config/models.js.map +1 -1
  34. package/dist/src/config/models.test.js +63 -16
  35. package/dist/src/config/models.test.js.map +1 -1
  36. package/dist/src/core/baseLlmClient.js +26 -1
  37. package/dist/src/core/baseLlmClient.js.map +1 -1
  38. package/dist/src/core/contentGenerator.js +91 -1
  39. package/dist/src/core/contentGenerator.js.map +1 -1
  40. package/dist/src/core/contentGenerator.test.js +101 -0
  41. package/dist/src/core/contentGenerator.test.js.map +1 -1
  42. package/dist/src/core/geminiChat.test.js +25 -0
  43. package/dist/src/core/geminiChat.test.js.map +1 -1
  44. package/dist/src/core/openAiCompatibleContentGenerator.d.ts +156 -0
  45. package/dist/src/core/openAiCompatibleContentGenerator.js +1161 -0
  46. package/dist/src/core/openAiCompatibleContentGenerator.js.map +1 -0
  47. package/dist/src/core/openAiCompatibleContentGenerator.test.d.ts +6 -0
  48. package/dist/src/core/openAiCompatibleContentGenerator.test.js +850 -0
  49. package/dist/src/core/openAiCompatibleContentGenerator.test.js.map +1 -0
  50. package/dist/src/generated/git-commit.d.ts +2 -2
  51. package/dist/src/generated/git-commit.js +2 -2
  52. package/dist/src/index.d.ts +1 -0
  53. package/dist/src/index.js +1 -0
  54. package/dist/src/index.js.map +1 -1
  55. package/dist/src/safety/built-in.js +60 -11
  56. package/dist/src/safety/built-in.js.map +1 -1
  57. package/dist/src/safety/built-in.test.js +60 -0
  58. package/dist/src/safety/built-in.test.js.map +1 -1
  59. package/dist/src/test-utils/mockWorkspaceContext.js +12 -1
  60. package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -1
  61. package/dist/src/tools/at-reference-resolution.test.d.ts +6 -0
  62. package/dist/src/tools/at-reference-resolution.test.js +402 -0
  63. package/dist/src/tools/at-reference-resolution.test.js.map +1 -0
  64. package/dist/src/tools/edit.js +91 -12
  65. package/dist/src/tools/edit.js.map +1 -1
  66. package/dist/src/tools/edit.test.js +22 -1
  67. package/dist/src/tools/edit.test.js.map +1 -1
  68. package/dist/src/tools/glob.js +40 -4
  69. package/dist/src/tools/glob.js.map +1 -1
  70. package/dist/src/tools/glob.test.js +2 -1
  71. package/dist/src/tools/glob.test.js.map +1 -1
  72. package/dist/src/tools/grep.js +22 -3
  73. package/dist/src/tools/grep.js.map +1 -1
  74. package/dist/src/tools/grep.test.js +2 -2
  75. package/dist/src/tools/grep.test.js.map +1 -1
  76. package/dist/src/tools/read-file.js +16 -3
  77. package/dist/src/tools/read-file.js.map +1 -1
  78. package/dist/src/tools/read-many-files.test.js +2 -2
  79. package/dist/src/tools/read-many-files.test.js.map +1 -1
  80. package/dist/src/tools/ripGrep.js +30 -3
  81. package/dist/src/tools/ripGrep.js.map +1 -1
  82. package/dist/src/tools/ripGrep.test.js +3 -3
  83. package/dist/src/tools/ripGrep.test.js.map +1 -1
  84. package/dist/src/tools/trackerTools.test.js +1 -1
  85. package/dist/src/tools/trackerTools.test.js.map +1 -1
  86. package/dist/src/tools/write-file.js +76 -9
  87. package/dist/src/tools/write-file.js.map +1 -1
  88. package/dist/src/tools/write-file.test.js +17 -16
  89. package/dist/src/tools/write-file.test.js.map +1 -1
  90. package/dist/src/utils/editCorrector.test.js +6 -0
  91. package/dist/src/utils/editCorrector.test.js.map +1 -1
  92. package/dist/src/utils/fetch.test.js +1 -0
  93. package/dist/src/utils/fetch.test.js.map +1 -1
  94. package/dist/src/utils/historyHardening.d.ts +1 -0
  95. package/dist/src/utils/historyHardening.js +92 -14
  96. package/dist/src/utils/historyHardening.js.map +1 -1
  97. package/dist/src/utils/historyHardening.test.js +189 -1
  98. package/dist/src/utils/historyHardening.test.js.map +1 -1
  99. package/dist/src/utils/memoryImportProcessor.js +24 -3
  100. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  101. package/dist/src/utils/memoryImportProcessor.test.js +36 -0
  102. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  103. package/dist/src/utils/modelUtils.d.ts +8 -0
  104. package/dist/src/utils/modelUtils.js +59 -0
  105. package/dist/src/utils/modelUtils.js.map +1 -1
  106. package/dist/src/utils/modelUtils.test.js +46 -2
  107. package/dist/src/utils/modelUtils.test.js.map +1 -1
  108. package/dist/src/utils/pathCorrector.js +5 -3
  109. package/dist/src/utils/pathCorrector.js.map +1 -1
  110. package/dist/src/utils/pathCorrector.test.js +2 -1
  111. package/dist/src/utils/pathCorrector.test.js.map +1 -1
  112. package/dist/src/utils/paths.d.ts +5 -0
  113. package/dist/src/utils/paths.js +41 -0
  114. package/dist/src/utils/paths.js.map +1 -1
  115. package/dist/src/utils/paths.test.js +15 -1
  116. package/dist/src/utils/paths.test.js.map +1 -1
  117. package/dist/src/utils/workspaceContext.js +21 -0
  118. package/dist/src/utils/workspaceContext.js.map +1 -1
  119. package/dist/src/utils/workspaceContext.test.js +40 -0
  120. package/dist/src/utils/workspaceContext.test.js.map +1 -1
  121. package/dist/src/voice/whisperModelManager.js +2 -0
  122. package/dist/src/voice/whisperModelManager.js.map +1 -1
  123. package/dist/tsconfig.tsbuildinfo +1 -1
  124. package/package.json +2 -2
@@ -0,0 +1,402 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { ReadFileTool } from './read-file.js';
8
+ import { WriteFileTool, getCorrectedFileContent } from './write-file.js';
9
+ import { EditTool } from './edit.js';
10
+ import { correctPath } from '../utils/pathCorrector.js';
11
+ import path from 'node:path';
12
+ import os from 'node:os';
13
+ import fs from 'node:fs';
14
+ import fsp from 'node:fs/promises';
15
+ import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
16
+ import { StandardFileSystemService } from '../services/fileSystemService.js';
17
+ import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js';
18
+ import { createMockMessageBus } from '../test-utils/mock-message-bus.js';
19
+ import { isSubpath } from '../utils/paths.js';
20
+ vi.mock('../telemetry/loggers.js', () => ({
21
+ logFileOperation: vi.fn(),
22
+ logEditStrategy: vi.fn(),
23
+ logEditCorrectionEvent: vi.fn(),
24
+ }));
25
+ vi.mock('./jit-context.js', () => ({
26
+ discoverJitContext: vi.fn().mockResolvedValue(''),
27
+ appendJitContext: vi.fn().mockImplementation((content) => content),
28
+ appendJitContextToParts: vi.fn().mockImplementation((content) => content),
29
+ }));
30
+ describe('Consolidated At-Reference Path Resolution Tests (b-495551283)', () => {
31
+ let tempRootDir;
32
+ let mockConfigInstance;
33
+ const abortSignal = new AbortController().signal;
34
+ beforeEach(async () => {
35
+ // Create a unique temporary root directory for each test run
36
+ const realTmp = await fsp.realpath(os.tmpdir());
37
+ tempRootDir = await fsp.mkdtemp(path.join(realTmp, 'at-ref-resolution-root-'));
38
+ mockConfigInstance = {
39
+ getFileService: () => new FileDiscoveryService(tempRootDir),
40
+ getFileSystemService: () => new StandardFileSystemService(),
41
+ getTargetDir: () => tempRootDir,
42
+ getWorkspaceContext: () => createMockWorkspaceContext(tempRootDir),
43
+ getFileFilteringOptions: () => ({
44
+ respectGitIgnore: true,
45
+ respectGeminiIgnore: true,
46
+ }),
47
+ storage: {
48
+ getProjectTempDir: () => path.join(tempRootDir, '.temp'),
49
+ },
50
+ isInteractive: () => false,
51
+ isPlanMode: () => false,
52
+ getActiveModel: () => undefined,
53
+ getBaseLlmClient: () => undefined,
54
+ getDisableLLMCorrection: () => true,
55
+ isPathAllowed(absolutePath) {
56
+ const workspaceContext = this.getWorkspaceContext();
57
+ if (workspaceContext.isPathWithinWorkspace(absolutePath)) {
58
+ return true;
59
+ }
60
+ const projectTempDir = this.storage.getProjectTempDir();
61
+ return isSubpath(path.resolve(projectTempDir), absolutePath);
62
+ },
63
+ validatePathAccess(absolutePath) {
64
+ if (this.isPathAllowed(absolutePath)) {
65
+ return null;
66
+ }
67
+ const workspaceDirs = this.getWorkspaceContext().getDirectories();
68
+ const projectTempDir = this.storage.getProjectTempDir();
69
+ return `Path not in workspace: Attempted path "${absolutePath}" resolves outside the allowed workspace directories: ${workspaceDirs.join(', ')} or the project temp directory: ${projectTempDir}`;
70
+ },
71
+ };
72
+ // Create the policies directory and new-policies.txt file
73
+ await fsp.mkdir(path.join(tempRootDir, 'policies'), { recursive: true });
74
+ await fsp.writeFile(path.join(tempRootDir, 'policies', 'new-policies.txt'), '[[rule]]\ntoolName = "run_shell_command"\ndecision = "allow"\n', 'utf8');
75
+ });
76
+ afterEach(async () => {
77
+ // Clean up the temporary root directory
78
+ if (fs.existsSync(tempRootDir)) {
79
+ await fsp.rm(tempRootDir, { recursive: true, force: true });
80
+ }
81
+ });
82
+ it('ReadFileTool successfully reads a file when the path is prefixed with @', async () => {
83
+ const readFileTool = new ReadFileTool(mockConfigInstance, createMockMessageBus());
84
+ const invocation = readFileTool.build({
85
+ file_path: '@policies/new-policies.txt',
86
+ });
87
+ const result = await invocation.execute({ abortSignal });
88
+ // The tool should succeed because it defensively strips the leading '@'
89
+ expect(result.error).toBeUndefined();
90
+ expect(result.llmContent).toContain('toolName = "run_shell_command"');
91
+ });
92
+ it('ReadFileTool successfully reads a file when the path is prefixed with @/', async () => {
93
+ const readFileTool = new ReadFileTool(mockConfigInstance, createMockMessageBus());
94
+ const invocation = readFileTool.build({
95
+ file_path: '@/policies/new-policies.txt',
96
+ });
97
+ const result = await invocation.execute({ abortSignal });
98
+ // The tool should succeed because it defensively strips the leading '@/'
99
+ expect(result.error).toBeUndefined();
100
+ expect(result.llmContent).toContain('toolName = "run_shell_command"');
101
+ });
102
+ it('WriteFileTool successfully writes to/updates a file when the path is prefixed with @', async () => {
103
+ const writeFileTool = new WriteFileTool(mockConfigInstance, createMockMessageBus());
104
+ const invocation = writeFileTool.build({
105
+ file_path: '@policies/new-policies.txt',
106
+ content: '[[rule]]\nupdated_content = true\n',
107
+ });
108
+ const result = await invocation.execute({ abortSignal });
109
+ // The tool should succeed and update the correct file
110
+ expect(result.error).toBeUndefined();
111
+ const incorrectFilePath = path.join(tempRootDir, '@policies', 'new-policies.txt');
112
+ const correctFilePath = path.join(tempRootDir, 'policies', 'new-policies.txt');
113
+ // It should NOT have created a literal "@policies" directory
114
+ expect(fs.existsSync(incorrectFilePath)).toBe(false);
115
+ // It should have updated the correct file under "policies"
116
+ const updatedContent = await fsp.readFile(correctFilePath, 'utf8');
117
+ expect(updatedContent).toContain('updated_content = true');
118
+ });
119
+ it('WriteFileTool successfully creates a new file when the path is prefixed with @ and the parent directory exists', async () => {
120
+ const writeFileTool = new WriteFileTool(mockConfigInstance, createMockMessageBus());
121
+ const invocation = writeFileTool.build({
122
+ file_path: '@policies/brand-new-file.txt',
123
+ content: '[[rule]]\nbrand_new_file = true\n',
124
+ });
125
+ const result = await invocation.execute({ abortSignal });
126
+ // The tool should succeed and create the correct file
127
+ expect(result.error).toBeUndefined();
128
+ const incorrectFilePath = path.join(tempRootDir, '@policies', 'brand-new-file.txt');
129
+ const correctFilePath = path.join(tempRootDir, 'policies', 'brand-new-file.txt');
130
+ // It should NOT have created a literal "@policies" directory
131
+ expect(fs.existsSync(incorrectFilePath)).toBe(false);
132
+ // It should have created the correct file under "policies"
133
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
134
+ expect(createdContent).toContain('brand_new_file = true');
135
+ });
136
+ it('WriteFileTool successfully creates a new file in a nested subdirectory when the path is prefixed with @ and the first segment exists', async () => {
137
+ const writeFileTool = new WriteFileTool(mockConfigInstance, createMockMessageBus());
138
+ const invocation = writeFileTool.build({
139
+ file_path: '@policies/sub/brand-new-file.txt',
140
+ content: '[[rule]]\nnested_brand_new_file = true\n',
141
+ });
142
+ const result = await invocation.execute({ abortSignal });
143
+ // The tool should succeed and create the correct file
144
+ expect(result.error).toBeUndefined();
145
+ const incorrectFilePath = path.join(tempRootDir, '@policies', 'sub', 'brand-new-file.txt');
146
+ const correctFilePath = path.join(tempRootDir, 'policies', 'sub', 'brand-new-file.txt');
147
+ // It should NOT have created a literal "@policies" directory
148
+ expect(fs.existsSync(incorrectFilePath)).toBe(false);
149
+ // It should have created the correct file under "policies/sub"
150
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
151
+ expect(createdContent).toContain('nested_brand_new_file = true');
152
+ });
153
+ it('WriteFileTool successfully creates a new file in a nested subdirectory when the path is prefixed with @ and the first segment does NOT exist', async () => {
154
+ const writeFileTool = new WriteFileTool(mockConfigInstance, createMockMessageBus());
155
+ const invocation = writeFileTool.build({
156
+ file_path: '@new-policies/sub/brand-new-file.txt',
157
+ content: '[[rule]]\nnested_brand_new_file = true\n',
158
+ });
159
+ const result = await invocation.execute({ abortSignal });
160
+ // The tool should succeed and create the correct file
161
+ expect(result.error).toBeUndefined();
162
+ const incorrectFilePath = path.join(tempRootDir, '@new-policies', 'sub', 'brand-new-file.txt');
163
+ const correctFilePath = path.join(tempRootDir, 'new-policies', 'sub', 'brand-new-file.txt');
164
+ // It should NOT have created a literal "@new-policies" directory
165
+ expect(fs.existsSync(incorrectFilePath)).toBe(false);
166
+ // It SHOULD have created the file under "new-policies/sub"
167
+ expect(fs.existsSync(correctFilePath)).toBe(true);
168
+ // Verify the content of the created file
169
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
170
+ expect(createdContent).toContain('nested_brand_new_file = true');
171
+ });
172
+ it('WriteFileTool successfully creates a new file in a nested subdirectory when the path is prefixed with @/ and the first segment does NOT exist', async () => {
173
+ const writeFileTool = new WriteFileTool(mockConfigInstance, createMockMessageBus());
174
+ const invocation = writeFileTool.build({
175
+ file_path: '@/new-policies-alias/sub/brand-new-file.txt',
176
+ content: '[[rule]]\nnested_brand_new_file_alias = true\n',
177
+ });
178
+ const result = await invocation.execute({ abortSignal });
179
+ // The tool should succeed and create the correct file
180
+ expect(result.error).toBeUndefined();
181
+ const literalAtFilePath = path.join(tempRootDir, '@', 'new-policies-alias', 'sub', 'brand-new-file.txt');
182
+ const correctFilePath = path.join(tempRootDir, 'new-policies-alias', 'sub', 'brand-new-file.txt');
183
+ // It should NOT have created a literal "@" directory
184
+ expect(fs.existsSync(literalAtFilePath)).toBe(false);
185
+ expect(fs.existsSync(path.join(tempRootDir, '@'))).toBe(false);
186
+ // It should have created the file under "new-policies-alias/sub"
187
+ expect(fs.existsSync(correctFilePath)).toBe(true);
188
+ // Verify the content of the created file
189
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
190
+ expect(createdContent).toContain('nested_brand_new_file_alias = true');
191
+ });
192
+ it('WriteFileTool successfully creates a new file in a nested subdirectory when the path is prefixed with @\\ and the first segment does NOT exist', async () => {
193
+ const writeFileTool = new WriteFileTool(mockConfigInstance, createMockMessageBus());
194
+ const invocation = writeFileTool.build({
195
+ file_path: '@\\new-policies-alias-win\\sub\\brand-new-file.txt',
196
+ content: '[[rule]]\nnested_brand_new_file_alias_win = true\n',
197
+ });
198
+ const result = await invocation.execute({ abortSignal });
199
+ // The tool should succeed and create the correct file
200
+ expect(result.error).toBeUndefined();
201
+ const isWindows = process.platform === 'win32';
202
+ const literalAtFilePath = isWindows
203
+ ? path.join(tempRootDir, '@', 'new-policies-alias-win', 'sub', 'brand-new-file.txt')
204
+ : path.join(tempRootDir, '@\\new-policies-alias-win\\sub\\brand-new-file.txt');
205
+ const correctFilePath = isWindows
206
+ ? path.join(tempRootDir, 'new-policies-alias-win', 'sub', 'brand-new-file.txt')
207
+ : path.join(tempRootDir, 'new-policies-alias-win\\sub\\brand-new-file.txt');
208
+ // It should NOT have created a literal "@" directory
209
+ expect(fs.existsSync(literalAtFilePath)).toBe(false);
210
+ expect(fs.existsSync(path.join(tempRootDir, '@'))).toBe(false);
211
+ // It should have created the file under "new-policies-alias-win/sub"
212
+ expect(fs.existsSync(correctFilePath)).toBe(true);
213
+ // Verify the content of the created file
214
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
215
+ expect(createdContent).toContain('nested_brand_new_file_alias_win = true');
216
+ });
217
+ it('getCorrectedFileContent blocks path traversal outside the workspace', async () => {
218
+ const result = await getCorrectedFileContent(mockConfigInstance, '../../etc/passwd', 'malicious content', abortSignal);
219
+ // The utility should fail with a path validation error
220
+ expect(result.error).toBeDefined();
221
+ expect(result.error?.message).toContain('Path not in workspace');
222
+ });
223
+ it('EditTool.getModifyContext blocks path traversal outside the workspace', async () => {
224
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
225
+ const modifyContext = editTool.getModifyContext(abortSignal);
226
+ // The getCurrentContent method should throw a path validation error
227
+ await expect(modifyContext.getCurrentContent({
228
+ file_path: '../../etc/passwd',
229
+ instruction: 'read file',
230
+ old_string: '',
231
+ new_string: '',
232
+ })).rejects.toThrow('Path not in workspace');
233
+ // The getProposedContent method should throw a path validation error
234
+ await expect(modifyContext.getProposedContent({
235
+ file_path: '../../etc/passwd',
236
+ instruction: 'read file',
237
+ old_string: '',
238
+ new_string: '',
239
+ })).rejects.toThrow('Path not in workspace');
240
+ });
241
+ it('getCorrectedFileContent handles symlink loops gracefully', async () => {
242
+ const symlinkPath1 = path.join(tempRootDir, 'symlink1');
243
+ const symlinkPath2 = path.join(tempRootDir, 'symlink2');
244
+ await fsp.symlink(symlinkPath2, symlinkPath1);
245
+ await fsp.symlink(symlinkPath1, symlinkPath2);
246
+ const result = await getCorrectedFileContent(mockConfigInstance, 'symlink1', 'content', abortSignal);
247
+ // The utility should fail gracefully with a resolution error
248
+ expect(result.error).toBeDefined();
249
+ expect(result.error?.message).toContain('Failed to resolve path');
250
+ });
251
+ it('EditTool.getModifyContext handles symlink loops gracefully by throwing a descriptive error', async () => {
252
+ const symlinkPath1 = path.join(tempRootDir, 'symlink1');
253
+ const symlinkPath2 = path.join(tempRootDir, 'symlink2');
254
+ await fsp.symlink(symlinkPath2, symlinkPath1);
255
+ await fsp.symlink(symlinkPath1, symlinkPath2);
256
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
257
+ const modifyContext = editTool.getModifyContext(abortSignal);
258
+ // The getCurrentContent method should throw a path resolution error
259
+ await expect(modifyContext.getCurrentContent({
260
+ file_path: 'symlink1',
261
+ instruction: 'read file',
262
+ old_string: '',
263
+ new_string: '',
264
+ })).rejects.toThrow('Failed to resolve path');
265
+ // The getProposedContent method should throw a path resolution error
266
+ await expect(modifyContext.getProposedContent({
267
+ file_path: 'symlink1',
268
+ instruction: 'read file',
269
+ old_string: '',
270
+ new_string: '',
271
+ })).rejects.toThrow('Failed to resolve path');
272
+ });
273
+ it('getCorrectedFileContent successfully resolves paths in Plan Mode', async () => {
274
+ const plansDir = path.join(tempRootDir, '.plans');
275
+ await fsp.mkdir(plansDir, { recursive: true });
276
+ await fsp.writeFile(path.join(plansDir, 'plan-file.txt'), 'plan content', 'utf8');
277
+ const planConfigInstance = Object.assign({}, mockConfigInstance, {
278
+ isPlanMode: () => true,
279
+ getProjectRoot: () => tempRootDir,
280
+ storage: {
281
+ getProjectTempDir: () => path.join(tempRootDir, '.temp'),
282
+ getPlansDir: () => plansDir,
283
+ },
284
+ });
285
+ const result = await getCorrectedFileContent(planConfigInstance, 'plan-file.txt', 'new plan content', abortSignal);
286
+ expect(result.error).toBeUndefined();
287
+ expect(result.originalContent).toBe('plan content');
288
+ });
289
+ it('EditTool successfully edits an existing file when the path is prefixed with @', async () => {
290
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
291
+ const invocation = editTool.build({
292
+ file_path: '@policies/new-policies.txt',
293
+ instruction: 'update decision rule',
294
+ old_string: 'decision = "allow"',
295
+ new_string: 'decision = "deny"',
296
+ });
297
+ const result = await invocation.execute({ abortSignal });
298
+ // The tool should succeed and update the correct file
299
+ expect(result.error).toBeUndefined();
300
+ const correctFilePath = path.join(tempRootDir, 'policies', 'new-policies.txt');
301
+ const updatedContent = await fsp.readFile(correctFilePath, 'utf8');
302
+ expect(updatedContent).toContain('decision = "deny"');
303
+ });
304
+ it('EditTool successfully creates a new file when the path is prefixed with @ and the parent directory exists', async () => {
305
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
306
+ const invocation = editTool.build({
307
+ file_path: '@policies/brand-new-edit-file.txt',
308
+ instruction: 'create new file',
309
+ old_string: '',
310
+ new_string: '[[rule]]\nbrand_new_edit_file = true\n',
311
+ });
312
+ const result = await invocation.execute({ abortSignal });
313
+ // The tool should succeed and create the correct file
314
+ expect(result.error).toBeUndefined();
315
+ const incorrectFilePath = path.join(tempRootDir, '@policies', 'brand-new-edit-file.txt');
316
+ const correctFilePath = path.join(tempRootDir, 'policies', 'brand-new-edit-file.txt');
317
+ // It should NOT have created a literal "@policies" directory
318
+ expect(fs.existsSync(incorrectFilePath)).toBe(false);
319
+ // It should have created the correct file under "policies"
320
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
321
+ expect(createdContent).toContain('brand_new_edit_file = true');
322
+ });
323
+ it('EditTool successfully creates a new file in a nested subdirectory when the path is prefixed with @ and the first segment does NOT exist', async () => {
324
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
325
+ const invocation = editTool.build({
326
+ file_path: '@new-policies-edit/sub/brand-new-file.txt',
327
+ instruction: 'create new file in nested subdirectory',
328
+ old_string: '',
329
+ new_string: '[[rule]]\nnested_brand_new_edit_file = true\n',
330
+ });
331
+ const result = await invocation.execute({ abortSignal });
332
+ // The tool should succeed and create the correct file
333
+ expect(result.error).toBeUndefined();
334
+ const incorrectFilePath = path.join(tempRootDir, '@new-policies-edit', 'sub', 'brand-new-file.txt');
335
+ const correctFilePath = path.join(tempRootDir, 'new-policies-edit', 'sub', 'brand-new-file.txt');
336
+ // It should NOT have created a literal "@new-policies-edit" directory
337
+ expect(fs.existsSync(incorrectFilePath)).toBe(false);
338
+ // It SHOULD have created the file under "new-policies-edit/sub"
339
+ expect(fs.existsSync(correctFilePath)).toBe(true);
340
+ // Verify the content of the created file
341
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
342
+ expect(createdContent).toContain('nested_brand_new_edit_file = true');
343
+ });
344
+ it('EditTool successfully creates a new file in a nested subdirectory when the path is prefixed with @/ and the first segment does NOT exist', async () => {
345
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
346
+ const invocation = editTool.build({
347
+ file_path: '@/new-policies-edit-alias/sub/brand-new-file.txt',
348
+ instruction: 'create new file in nested subdirectory',
349
+ old_string: '',
350
+ new_string: '[[rule]]\nnested_brand_new_edit_file_alias = true\n',
351
+ });
352
+ const result = await invocation.execute({ abortSignal });
353
+ // The tool should succeed and create the correct file
354
+ expect(result.error).toBeUndefined();
355
+ const literalAtFilePath = path.join(tempRootDir, '@', 'new-policies-edit-alias', 'sub', 'brand-new-file.txt');
356
+ const correctFilePath = path.join(tempRootDir, 'new-policies-edit-alias', 'sub', 'brand-new-file.txt');
357
+ // It should NOT have created a literal "@" directory
358
+ expect(fs.existsSync(literalAtFilePath)).toBe(false);
359
+ expect(fs.existsSync(path.join(tempRootDir, '@'))).toBe(false);
360
+ // It should have created the file under "new-policies-edit-alias/sub"
361
+ expect(fs.existsSync(correctFilePath)).toBe(true);
362
+ // Verify the content of the created file
363
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
364
+ expect(createdContent).toContain('nested_brand_new_edit_file_alias = true');
365
+ });
366
+ it('EditTool successfully creates a new file in a nested subdirectory when the path is prefixed with @\\ and the first segment does NOT exist', async () => {
367
+ const editTool = new EditTool(mockConfigInstance, createMockMessageBus());
368
+ const invocation = editTool.build({
369
+ file_path: '@\\new-policies-edit-alias-win\\sub\\brand-new-file.txt',
370
+ instruction: 'create new file in nested subdirectory',
371
+ old_string: '',
372
+ new_string: '[[rule]]\nnested_brand_new_edit_file_alias_win = true\n',
373
+ });
374
+ const result = await invocation.execute({ abortSignal });
375
+ // The tool should succeed and create the correct file
376
+ expect(result.error).toBeUndefined();
377
+ const isWindows = process.platform === 'win32';
378
+ const literalAtFilePath = isWindows
379
+ ? path.join(tempRootDir, '@', 'new-policies-edit-alias-win', 'sub', 'brand-new-file.txt')
380
+ : path.join(tempRootDir, '@\\new-policies-edit-alias-win\\sub\\brand-new-file.txt');
381
+ const correctFilePath = isWindows
382
+ ? path.join(tempRootDir, 'new-policies-edit-alias-win', 'sub', 'brand-new-file.txt')
383
+ : path.join(tempRootDir, 'new-policies-edit-alias-win\\sub\\brand-new-file.txt');
384
+ // It should NOT have created a literal "@" directory
385
+ expect(fs.existsSync(literalAtFilePath)).toBe(false);
386
+ expect(fs.existsSync(path.join(tempRootDir, '@'))).toBe(false);
387
+ // It should have created the file under "new-policies-edit-alias-win/sub"
388
+ expect(fs.existsSync(correctFilePath)).toBe(true);
389
+ // Verify the content of the created file
390
+ const createdContent = await fsp.readFile(correctFilePath, 'utf8');
391
+ expect(createdContent).toContain('nested_brand_new_edit_file_alias_win = true');
392
+ });
393
+ it('correctPath successfully resolves a path prefixed with @ to its clean counterpart', () => {
394
+ const result = correctPath('@policies/new-policies.txt', mockConfigInstance);
395
+ expect(result.success).toBe(true);
396
+ if (result.success) {
397
+ const expectedPath = path.join(tempRootDir, 'policies', 'new-policies.txt');
398
+ expect(result.correctedPath).toBe(expectedPath);
399
+ }
400
+ });
401
+ });
402
+ //# sourceMappingURL=at-reference-resolution.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"at-reference-resolution.test.js","sourceRoot":"","sources":["../../../src/tools/at-reference-resolution.test.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ import * as Diff from 'diff';
11
11
  import { BaseDeclarativeTool, BaseToolInvocation, Kind, } from './tools.js';
12
12
  import { buildFilePathArgsPattern } from '../policy/utils.js';
13
13
  import { ToolErrorType } from './tool-error.js';
14
- import { makeRelative, shortenPath } from '../utils/paths.js';
14
+ import { makeRelative, shortenPath, resolveDefensiveToolPath, resolveToRealPath, } from '../utils/paths.js';
15
15
  import { isNodeError } from '../utils/errors.js';
16
16
  import { correctPath } from '../utils/pathCorrector.js';
17
17
  import { CoreToolCallStatus } from '../scheduler/types.js';
@@ -281,26 +281,45 @@ class EditToolInvocation extends BaseToolInvocation {
281
281
  this.config = config;
282
282
  if (this.config.isPlanMode()) {
283
283
  try {
284
- this.resolvedPath = resolveAndValidatePlanPath(this.params.file_path, this.config.storage.getPlansDir(), this.config.getProjectRoot());
284
+ const cleanFilePath = this.params.file_path.replace(/\0/g, '');
285
+ const planPath = resolveAndValidatePlanPath(cleanFilePath, this.config.storage.getPlansDir(), this.config.getProjectRoot());
286
+ this.resolvedPath = resolveToRealPath(planPath);
285
287
  }
286
288
  catch (e) {
287
289
  debugLogger.error('Failed to resolve plan path during EditTool invocation setup', e);
288
290
  // Validation fails, set resolvedPath to something that will fail validation downstream or just the raw path.
289
291
  // It's safer to store it so validation in execute() or getConfirmationDetails() catches it.
290
- this.resolvedPath = this.params.file_path;
292
+ this.resolvedPath = this.params.file_path.replace(/\0/g, '');
291
293
  }
292
294
  }
293
295
  else if (!path.isAbsolute(this.params.file_path)) {
294
296
  const result = correctPath(this.params.file_path, this.config);
295
297
  if (result.success) {
296
- this.resolvedPath = result.correctedPath;
298
+ try {
299
+ this.resolvedPath = resolveToRealPath(result.correctedPath);
300
+ }
301
+ catch {
302
+ this.resolvedPath = result.correctedPath;
303
+ }
297
304
  }
298
305
  else {
299
- this.resolvedPath = path.resolve(this.config.getTargetDir(), this.params.file_path);
306
+ const sanitizedPath = resolveDefensiveToolPath(this.params.file_path, this.config.getTargetDir());
307
+ try {
308
+ this.resolvedPath = resolveToRealPath(path.resolve(this.config.getTargetDir(), sanitizedPath));
309
+ }
310
+ catch {
311
+ this.resolvedPath = path.resolve(this.config.getTargetDir(), sanitizedPath);
312
+ }
300
313
  }
301
314
  }
302
315
  else {
303
- this.resolvedPath = this.params.file_path;
316
+ const cleanPath = this.params.file_path.replace(/\0/g, '');
317
+ try {
318
+ this.resolvedPath = resolveToRealPath(cleanPath);
319
+ }
320
+ catch {
321
+ this.resolvedPath = cleanPath;
322
+ }
304
323
  }
305
324
  }
306
325
  toolLocations() {
@@ -754,7 +773,9 @@ export class EditTool extends BaseDeclarativeTool {
754
773
  let resolvedPath;
755
774
  if (this.config.isPlanMode()) {
756
775
  try {
757
- resolvedPath = resolveAndValidatePlanPath(params.file_path, this.config.storage.getPlansDir(), this.config.getProjectRoot());
776
+ const cleanFilePath = params.file_path.replace(/\0/g, '');
777
+ const planPath = resolveAndValidatePlanPath(cleanFilePath, this.config.storage.getPlansDir(), this.config.getProjectRoot());
778
+ resolvedPath = resolveToRealPath(planPath);
758
779
  }
759
780
  catch (err) {
760
781
  return err instanceof Error ? err.message : String(err);
@@ -763,14 +784,31 @@ export class EditTool extends BaseDeclarativeTool {
763
784
  else if (!path.isAbsolute(params.file_path)) {
764
785
  const result = correctPath(params.file_path, this.config);
765
786
  if (result.success) {
766
- resolvedPath = result.correctedPath;
787
+ try {
788
+ resolvedPath = resolveToRealPath(result.correctedPath);
789
+ }
790
+ catch (err) {
791
+ return err instanceof Error ? err.message : String(err);
792
+ }
767
793
  }
768
794
  else {
769
- resolvedPath = path.resolve(this.config.getTargetDir(), params.file_path);
795
+ const sanitizedPath = resolveDefensiveToolPath(params.file_path, this.config.getTargetDir());
796
+ try {
797
+ resolvedPath = resolveToRealPath(path.resolve(this.config.getTargetDir(), sanitizedPath));
798
+ }
799
+ catch (err) {
800
+ return err instanceof Error ? err.message : String(err);
801
+ }
770
802
  }
771
803
  }
772
804
  else {
773
- resolvedPath = params.file_path;
805
+ const cleanPath = params.file_path.replace(/\0/g, '');
806
+ try {
807
+ resolvedPath = resolveToRealPath(cleanPath);
808
+ }
809
+ catch (err) {
810
+ return err instanceof Error ? err.message : String(err);
811
+ }
774
812
  }
775
813
  const newPlaceholders = detectOmissionPlaceholders(params.new_string);
776
814
  if (newPlaceholders.length > 0) {
@@ -790,13 +828,53 @@ export class EditTool extends BaseDeclarativeTool {
790
828
  return resolveToolDeclaration(EDIT_DEFINITION, modelId);
791
829
  }
792
830
  getModifyContext(_) {
831
+ const resolvePath = (params) => {
832
+ let pathBeforeRealResolve;
833
+ try {
834
+ if (this.config.isPlanMode()) {
835
+ const cleanFilePath = params.file_path.replace(/\0/g, '');
836
+ pathBeforeRealResolve = resolveAndValidatePlanPath(cleanFilePath, this.config.storage.getPlansDir(), this.config.getProjectRoot());
837
+ }
838
+ else if (!path.isAbsolute(params.file_path)) {
839
+ const result = correctPath(params.file_path, this.config);
840
+ if (result.success) {
841
+ pathBeforeRealResolve = result.correctedPath;
842
+ }
843
+ else {
844
+ const sanitizedPath = resolveDefensiveToolPath(params.file_path, this.config.getTargetDir());
845
+ pathBeforeRealResolve = path.resolve(this.config.getTargetDir(), sanitizedPath);
846
+ }
847
+ }
848
+ else {
849
+ pathBeforeRealResolve = params.file_path.replace(/\0/g, '');
850
+ }
851
+ }
852
+ catch (err) {
853
+ throw new Error('Failed to resolve path: ' +
854
+ (err instanceof Error ? err.message : String(err)));
855
+ }
856
+ let resolved;
857
+ try {
858
+ resolved = resolveToRealPath(pathBeforeRealResolve);
859
+ }
860
+ catch (err) {
861
+ throw new Error('Failed to resolve path: ' +
862
+ (err instanceof Error ? err.message : String(err)));
863
+ }
864
+ const validationError = this.config.validatePathAccess(resolved);
865
+ if (validationError) {
866
+ throw new Error(validationError);
867
+ }
868
+ return resolved;
869
+ };
793
870
  return {
794
871
  getFilePath: (params) => params.file_path,
795
872
  getCurrentContent: async (params) => {
796
873
  try {
874
+ const resolvedPath = resolvePath(params);
797
875
  return await this.config
798
876
  .getFileSystemService()
799
- .readTextFile(params.file_path);
877
+ .readTextFile(resolvedPath);
800
878
  }
801
879
  catch (err) {
802
880
  if (!isNodeError(err) || err.code !== 'ENOENT')
@@ -806,9 +884,10 @@ export class EditTool extends BaseDeclarativeTool {
806
884
  },
807
885
  getProposedContent: async (params) => {
808
886
  try {
887
+ const resolvedPath = resolvePath(params);
809
888
  const currentContent = await this.config
810
889
  .getFileSystemService()
811
- .readTextFile(params.file_path);
890
+ .readTextFile(resolvedPath);
812
891
  return applyReplacement(currentContent, params.old_string, params.new_string, params.old_string === '' && currentContent === '');
813
892
  }
814
893
  catch (err) {