@google/gemini-cli 0.12.0-preview.4 → 0.13.0-nightly.20251031.c89bc30d

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 (254) hide show
  1. package/dist/google-gemini-cli-0.13.0-nightly.20251029.cca41edc.tgz +0 -0
  2. package/dist/package.json +2 -2
  3. package/dist/src/commands/extensions/install.js +2 -2
  4. package/dist/src/commands/extensions/install.js.map +1 -1
  5. package/dist/src/commands/extensions/install.test.js +27 -16
  6. package/dist/src/commands/extensions/install.test.js.map +1 -1
  7. package/dist/src/commands/extensions/link.js +2 -2
  8. package/dist/src/commands/extensions/link.js.map +1 -1
  9. package/dist/src/commands/extensions/update.js +3 -2
  10. package/dist/src/commands/extensions/update.js.map +1 -1
  11. package/dist/src/commands/extensions/validate.d.ts +12 -0
  12. package/dist/src/commands/extensions/validate.js +83 -0
  13. package/dist/src/commands/extensions/validate.js.map +1 -0
  14. package/dist/src/commands/extensions/validate.test.d.ts +6 -0
  15. package/dist/src/commands/extensions/validate.test.js +93 -0
  16. package/dist/src/commands/extensions/validate.test.js.map +1 -0
  17. package/dist/src/commands/extensions.js +2 -0
  18. package/dist/src/commands/extensions.js.map +1 -1
  19. package/dist/src/config/auth.js +0 -5
  20. package/dist/src/config/auth.js.map +1 -1
  21. package/dist/src/config/auth.test.js +1 -3
  22. package/dist/src/config/auth.test.js.map +1 -1
  23. package/dist/src/config/config.js +2 -1
  24. package/dist/src/config/config.js.map +1 -1
  25. package/dist/src/config/config.test.js +6 -10
  26. package/dist/src/config/config.test.js.map +1 -1
  27. package/dist/src/config/extensions/update.d.ts +2 -2
  28. package/dist/src/config/extensions/update.js +28 -22
  29. package/dist/src/config/extensions/update.js.map +1 -1
  30. package/dist/src/config/sandboxConfig.d.ts +1 -1
  31. package/dist/src/config/sandboxConfig.js +6 -3
  32. package/dist/src/config/sandboxConfig.js.map +1 -1
  33. package/dist/src/config/settings.js +2 -2
  34. package/dist/src/config/settings.js.map +1 -1
  35. package/dist/src/config/settings.test.js +13 -53
  36. package/dist/src/config/settings.test.js.map +1 -1
  37. package/dist/src/config/settingsSchema.d.ts +25 -7
  38. package/dist/src/config/settingsSchema.js +24 -6
  39. package/dist/src/config/settingsSchema.js.map +1 -1
  40. package/dist/src/config/settingsSchema.test.js +2 -0
  41. package/dist/src/config/settingsSchema.test.js.map +1 -1
  42. package/dist/src/gemini.js +8 -1
  43. package/dist/src/gemini.js.map +1 -1
  44. package/dist/src/gemini.test.js +1 -0
  45. package/dist/src/gemini.test.js.map +1 -1
  46. package/dist/src/generated/git-commit.d.ts +2 -2
  47. package/dist/src/generated/git-commit.js +2 -2
  48. package/dist/src/generated/git-commit.js.map +1 -1
  49. package/dist/src/nonInteractiveCli.d.ts +9 -1
  50. package/dist/src/nonInteractiveCli.js +16 -1
  51. package/dist/src/nonInteractiveCli.js.map +1 -1
  52. package/dist/src/nonInteractiveCli.test.js +209 -103
  53. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  54. package/dist/src/test-utils/async.d.ts +9 -0
  55. package/dist/src/test-utils/async.js +29 -0
  56. package/dist/src/test-utils/async.js.map +1 -0
  57. package/dist/src/test-utils/render.d.ts +2 -1
  58. package/dist/src/test-utils/render.js +23 -1
  59. package/dist/src/test-utils/render.js.map +1 -1
  60. package/dist/src/test-utils/render.test.js +29 -4
  61. package/dist/src/test-utils/render.test.js.map +1 -1
  62. package/dist/src/ui/App.test.js +1 -1
  63. package/dist/src/ui/App.test.js.map +1 -1
  64. package/dist/src/ui/AppContainer.js +33 -4
  65. package/dist/src/ui/AppContainer.js.map +1 -1
  66. package/dist/src/ui/AppContainer.test.js +205 -99
  67. package/dist/src/ui/AppContainer.test.js.map +1 -1
  68. package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
  69. package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
  70. package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
  71. package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
  72. package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
  73. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
  74. package/dist/src/ui/auth/AuthDialog.js +7 -3
  75. package/dist/src/ui/auth/AuthDialog.js.map +1 -1
  76. package/dist/src/ui/auth/AuthDialog.test.js +1 -1
  77. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  78. package/dist/src/ui/auth/useAuth.d.ts +2 -0
  79. package/dist/src/ui/auth/useAuth.js +31 -2
  80. package/dist/src/ui/auth/useAuth.js.map +1 -1
  81. package/dist/src/ui/components/AnsiOutput.test.js +1 -1
  82. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  83. package/dist/src/ui/components/Composer.test.js +1 -1
  84. package/dist/src/ui/components/Composer.test.js.map +1 -1
  85. package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
  86. package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
  87. package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
  88. package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
  89. package/dist/src/ui/components/DialogManager.js +4 -0
  90. package/dist/src/ui/components/DialogManager.js.map +1 -1
  91. package/dist/src/ui/components/FolderTrustDialog.test.js +4 -3
  92. package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
  93. package/dist/src/ui/components/Footer.js +3 -2
  94. package/dist/src/ui/components/Footer.js.map +1 -1
  95. package/dist/src/ui/components/Footer.test.js +59 -0
  96. package/dist/src/ui/components/Footer.test.js.map +1 -1
  97. package/dist/src/ui/components/Header.test.js +9 -5
  98. package/dist/src/ui/components/Header.test.js.map +1 -1
  99. package/dist/src/ui/components/Help.test.js +5 -3
  100. package/dist/src/ui/components/Help.test.js.map +1 -1
  101. package/dist/src/ui/components/InputPrompt.test.js +139 -111
  102. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  103. package/dist/src/ui/components/LoadingIndicator.test.js +27 -14
  104. package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
  105. package/dist/src/ui/components/ModelDialog.test.js +20 -10
  106. package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
  107. package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
  108. package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
  109. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +11 -10
  110. package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
  111. package/dist/src/ui/components/PrepareLabel.test.js +13 -7
  112. package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
  113. package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
  114. package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
  115. package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
  116. package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
  117. package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
  118. package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
  119. package/dist/src/ui/components/SettingsDialog.test.js +438 -512
  120. package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
  121. package/dist/src/ui/components/StatsDisplay.test.js +1 -1
  122. package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
  123. package/dist/src/ui/components/ThemeDialog.test.js +3 -2
  124. package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
  125. package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
  126. package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
  127. package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
  128. package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
  129. package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
  130. package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
  131. package/dist/src/ui/components/messages/Todo.js +27 -5
  132. package/dist/src/ui/components/messages/Todo.js.map +1 -1
  133. package/dist/src/ui/components/messages/Todo.test.js +20 -8
  134. package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
  135. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
  136. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  137. package/dist/src/ui/components/shared/BaseSelectionList.test.js +12 -11
  138. package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
  139. package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
  140. package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
  141. package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
  142. package/dist/src/ui/components/shared/TextInput.js +38 -0
  143. package/dist/src/ui/components/shared/TextInput.js.map +1 -0
  144. package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
  145. package/dist/src/ui/components/shared/TextInput.test.js +242 -0
  146. package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
  147. package/dist/src/ui/components/shared/text-buffer.d.ts +8 -2
  148. package/dist/src/ui/components/shared/text-buffer.js +28 -13
  149. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  150. package/dist/src/ui/components/shared/text-buffer.test.js +137 -0
  151. package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
  152. package/dist/src/ui/components/views/ChatList.test.js +7 -4
  153. package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
  154. package/dist/src/ui/components/views/ExtensionsList.js +1 -0
  155. package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
  156. package/dist/src/ui/components/views/ExtensionsList.test.js +13 -5
  157. package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
  158. package/dist/src/ui/components/views/McpStatus.test.js +23 -12
  159. package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
  160. package/dist/src/ui/contexts/KeypressContext.test.js +132 -252
  161. package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
  162. package/dist/src/ui/contexts/SessionContext.test.js +9 -5
  163. package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
  164. package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
  165. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  166. package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
  167. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  168. package/dist/src/ui/hooks/atCommandProcessor.js +29 -7
  169. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  170. package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
  171. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  172. package/dist/src/ui/hooks/shellCommandProcessor.test.js +47 -34
  173. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  174. package/dist/src/ui/hooks/slashCommandProcessor.test.js +141 -104
  175. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  176. package/dist/src/ui/hooks/useAtCompletion.test.js +23 -21
  177. package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
  178. package/dist/src/ui/hooks/useCommandCompletion.test.js +16 -15
  179. package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
  180. package/dist/src/ui/hooks/useConsoleMessages.test.js +1 -1
  181. package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
  182. package/dist/src/ui/hooks/useEditorSettings.test.js +1 -1
  183. package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
  184. package/dist/src/ui/hooks/useExtensionUpdates.d.ts +1 -1
  185. package/dist/src/ui/hooks/useExtensionUpdates.js +9 -3
  186. package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
  187. package/dist/src/ui/hooks/useExtensionUpdates.test.js +10 -9
  188. package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
  189. package/dist/src/ui/hooks/useFocus.test.js +1 -1
  190. package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
  191. package/dist/src/ui/hooks/useFolderTrust.test.js +7 -6
  192. package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
  193. package/dist/src/ui/hooks/useGeminiStream.test.js +39 -38
  194. package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
  195. package/dist/src/ui/hooks/useGitBranchName.test.js +5 -4
  196. package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
  197. package/dist/src/ui/hooks/useIdeTrustListener.test.js +25 -11
  198. package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
  199. package/dist/src/ui/hooks/useKeypress.test.js +1 -1
  200. package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
  201. package/dist/src/ui/hooks/useLoadingIndicator.test.js +1 -1
  202. package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
  203. package/dist/src/ui/hooks/useMemoryMonitor.test.js +1 -1
  204. package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
  205. package/dist/src/ui/hooks/useMessageQueue.test.js +5 -4
  206. package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
  207. package/dist/src/ui/hooks/useModelCommand.test.js +7 -4
  208. package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
  209. package/dist/src/ui/hooks/usePhraseCycler.test.js +46 -16
  210. package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
  211. package/dist/src/ui/hooks/usePrivacySettings.test.js +11 -7
  212. package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
  213. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +28 -14
  214. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  215. package/dist/src/ui/hooks/useSelectionList.test.js +116 -109
  216. package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
  217. package/dist/src/ui/hooks/useShellHistory.test.js +25 -17
  218. package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
  219. package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
  220. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  221. package/dist/src/ui/hooks/useSlashCompletion.test.js +244 -111
  222. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  223. package/dist/src/ui/hooks/useTimer.test.js +1 -1
  224. package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
  225. package/dist/src/ui/hooks/useToolScheduler.test.js +6 -2
  226. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  227. package/dist/src/ui/hooks/vim.test.js +6 -21
  228. package/dist/src/ui/hooks/vim.test.js.map +1 -1
  229. package/dist/src/ui/state/extensions.d.ts +1 -0
  230. package/dist/src/ui/state/extensions.js +1 -0
  231. package/dist/src/ui/state/extensions.js.map +1 -1
  232. package/dist/src/ui/types.d.ts +1 -0
  233. package/dist/src/ui/types.js +2 -0
  234. package/dist/src/ui/types.js.map +1 -1
  235. package/dist/src/ui/utils/clipboardUtils.js +2 -2
  236. package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
  237. package/dist/src/ui/utils/updateCheck.js +6 -3
  238. package/dist/src/ui/utils/updateCheck.js.map +1 -1
  239. package/dist/src/ui/utils/updateCheck.test.js +5 -1
  240. package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
  241. package/dist/src/utils/commentJson.js +2 -2
  242. package/dist/src/utils/commentJson.js.map +1 -1
  243. package/dist/src/utils/commentJson.test.js +7 -6
  244. package/dist/src/utils/commentJson.test.js.map +1 -1
  245. package/dist/src/utils/version.js +6 -2
  246. package/dist/src/utils/version.js.map +1 -1
  247. package/dist/src/zed-integration/acp.js +2 -1
  248. package/dist/src/zed-integration/acp.js.map +1 -1
  249. package/dist/tsconfig.tsbuildinfo +1 -1
  250. package/package.json +3 -3
  251. package/dist/google-gemini-cli-0.12.0-preview.3.tgz +0 -0
  252. package/dist/src/utils/package.d.ts +0 -12
  253. package/dist/src/utils/package.js +0 -24
  254. package/dist/src/utils/package.js.map +0 -1
@@ -23,6 +23,9 @@ describe('handleAtCommand', () => {
23
23
  await fsPromises.writeFile(fullPath, fileContents);
24
24
  return path.resolve(testRootDir, fullPath);
25
25
  }
26
+ function getRelativePath(absolutePath) {
27
+ return path.relative(testRootDir, absolutePath);
28
+ }
26
29
  beforeEach(async () => {
27
30
  vi.resetAllMocks();
28
31
  testRootDir = await fsPromises.mkdtemp(path.join(os.tmpdir(), 'folder-structure-test-'));
@@ -59,6 +62,7 @@ describe('handleAtCommand', () => {
59
62
  getReadManyFilesExcludes: () => [],
60
63
  }),
61
64
  getUsageStatisticsEnabled: () => false,
65
+ getEnableExtensionReloading: () => false,
62
66
  };
63
67
  const registry = new ToolRegistry(mockConfig);
64
68
  registry.registerTool(new ReadManyFilesTool(mockConfig));
@@ -103,6 +107,7 @@ describe('handleAtCommand', () => {
103
107
  it('should process a valid text file path', async () => {
104
108
  const fileContent = 'This is the file content.';
105
109
  const filePath = await createTestFile(path.join(testRootDir, 'path', 'to', 'file.txt'), fileContent);
110
+ const relativePath = getRelativePath(filePath);
106
111
  const query = `@${filePath}`;
107
112
  const result = await handleAtCommand({
108
113
  query,
@@ -114,9 +119,9 @@ describe('handleAtCommand', () => {
114
119
  });
115
120
  expect(result).toEqual({
116
121
  processedQuery: [
117
- { text: `@${filePath}` },
122
+ { text: `@${relativePath}` },
118
123
  { text: '\n--- Content from referenced files ---' },
119
- { text: `\nContent from @${filePath}:\n` },
124
+ { text: `\nContent from @${relativePath}:\n` },
120
125
  { text: fileContent },
121
126
  { text: '\n--- End of content ---' },
122
127
  ],
@@ -131,8 +136,10 @@ describe('handleAtCommand', () => {
131
136
  const fileContent = 'This is the file content.';
132
137
  const filePath = await createTestFile(path.join(testRootDir, 'path', 'to', 'file.txt'), fileContent);
133
138
  const dirPath = path.dirname(filePath);
139
+ const relativeDirPath = getRelativePath(dirPath);
140
+ const relativeFilePath = getRelativePath(filePath);
134
141
  const query = `@${dirPath}`;
135
- const resolvedGlob = `${dirPath}/**`;
142
+ const resolvedGlob = path.join(relativeDirPath, '**');
136
143
  const result = await handleAtCommand({
137
144
  query,
138
145
  config: mockConfig,
@@ -145,7 +152,7 @@ describe('handleAtCommand', () => {
145
152
  processedQuery: [
146
153
  { text: `@${resolvedGlob}` },
147
154
  { text: '\n--- Content from referenced files ---' },
148
- { text: `\nContent from @${filePath}:\n` },
155
+ { text: `\nContent from @${relativeFilePath}:\n` },
149
156
  { text: fileContent },
150
157
  { text: '\n--- End of content ---' },
151
158
  ],
@@ -156,6 +163,7 @@ describe('handleAtCommand', () => {
156
163
  it('should handle query with text before and after @command', async () => {
157
164
  const fileContent = 'Markdown content.';
158
165
  const filePath = await createTestFile(path.join(testRootDir, 'doc.md'), fileContent);
166
+ const relativePath = getRelativePath(filePath);
159
167
  const textBefore = 'Explain this: ';
160
168
  const textAfter = ' in detail.';
161
169
  const query = `${textBefore}@${filePath}${textAfter}`;
@@ -169,9 +177,9 @@ describe('handleAtCommand', () => {
169
177
  });
170
178
  expect(result).toEqual({
171
179
  processedQuery: [
172
- { text: `${textBefore}@${filePath}${textAfter}` },
180
+ { text: `${textBefore}@${relativePath}${textAfter}` },
173
181
  { text: '\n--- Content from referenced files ---' },
174
- { text: `\nContent from @${filePath}:\n` },
182
+ { text: `\nContent from @${relativePath}:\n` },
175
183
  { text: fileContent },
176
184
  { text: '\n--- End of content ---' },
177
185
  ],
@@ -193,9 +201,9 @@ describe('handleAtCommand', () => {
193
201
  });
194
202
  expect(result).toEqual({
195
203
  processedQuery: [
196
- { text: `@${filePath}` },
204
+ { text: `@${getRelativePath(filePath)}` },
197
205
  { text: '\n--- Content from referenced files ---' },
198
- { text: `\nContent from @${filePath}:\n` },
206
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
199
207
  { text: fileContent },
200
208
  { text: '\n--- End of content ---' },
201
209
  ],
@@ -222,11 +230,13 @@ describe('handleAtCommand', () => {
222
230
  });
223
231
  expect(result).toEqual({
224
232
  processedQuery: [
225
- { text: query },
233
+ {
234
+ text: `@${getRelativePath(file1Path)} @${getRelativePath(file2Path)}`,
235
+ },
226
236
  { text: '\n--- Content from referenced files ---' },
227
- { text: `\nContent from @${file1Path}:\n` },
237
+ { text: `\nContent from @${getRelativePath(file1Path)}:\n` },
228
238
  { text: content1 },
229
- { text: `\nContent from @${file2Path}:\n` },
239
+ { text: `\nContent from @${getRelativePath(file2Path)}:\n` },
230
240
  { text: content2 },
231
241
  { text: '\n--- End of content ---' },
232
242
  ],
@@ -252,11 +262,13 @@ describe('handleAtCommand', () => {
252
262
  });
253
263
  expect(result).toEqual({
254
264
  processedQuery: [
255
- { text: query },
265
+ {
266
+ text: `${text1}@${getRelativePath(file1Path)}${text2}@${getRelativePath(file2Path)}${text3}`,
267
+ },
256
268
  { text: '\n--- Content from referenced files ---' },
257
- { text: `\nContent from @${file1Path}:\n` },
269
+ { text: `\nContent from @${getRelativePath(file1Path)}:\n` },
258
270
  { text: content1 },
259
- { text: `\nContent from @${file2Path}:\n` },
271
+ { text: `\nContent from @${getRelativePath(file2Path)}:\n` },
260
272
  { text: content2 },
261
273
  { text: '\n--- End of content ---' },
262
274
  ],
@@ -281,12 +293,12 @@ describe('handleAtCommand', () => {
281
293
  expect(result).toEqual({
282
294
  processedQuery: [
283
295
  {
284
- text: `Look at @${file1Path} then @${invalidFile} and also just @ symbol, then @${file2Path}`,
296
+ text: `Look at @${getRelativePath(file1Path)} then @${invalidFile} and also just @ symbol, then @${getRelativePath(file2Path)}`,
285
297
  },
286
298
  { text: '\n--- Content from referenced files ---' },
287
- { text: `\nContent from @${file2Path}:\n` },
299
+ { text: `\nContent from @${getRelativePath(file2Path)}:\n` },
288
300
  { text: content2 },
289
- { text: `\nContent from @${file1Path}:\n` },
301
+ { text: `\nContent from @${getRelativePath(file1Path)}:\n` },
290
302
  { text: content1 },
291
303
  { text: '\n--- End of content ---' },
292
304
  ],
@@ -350,9 +362,9 @@ describe('handleAtCommand', () => {
350
362
  });
351
363
  expect(result).toEqual({
352
364
  processedQuery: [
353
- { text: `@${validFile}` },
365
+ { text: `@${getRelativePath(validFile)}` },
354
366
  { text: '\n--- Content from referenced files ---' },
355
- { text: `\nContent from @${validFile}:\n` },
367
+ { text: `\nContent from @${getRelativePath(validFile)}:\n` },
356
368
  { text: 'console.log("Hello world");' },
357
369
  { text: '\n--- End of content ---' },
358
370
  ],
@@ -374,9 +386,9 @@ describe('handleAtCommand', () => {
374
386
  });
375
387
  expect(result).toEqual({
376
388
  processedQuery: [
377
- { text: `@${validFile} @${gitIgnoredFile}` },
389
+ { text: `@${getRelativePath(validFile)} @${gitIgnoredFile}` },
378
390
  { text: '\n--- Content from referenced files ---' },
379
- { text: `\nContent from @${validFile}:\n` },
391
+ { text: `\nContent from @${getRelativePath(validFile)}:\n` },
380
392
  { text: '# Project README' },
381
393
  { text: '\n--- End of content ---' },
382
394
  ],
@@ -459,9 +471,9 @@ describe('handleAtCommand', () => {
459
471
  });
460
472
  expect(result).toEqual({
461
473
  processedQuery: [
462
- { text: `@${validFile}` },
474
+ { text: `@${getRelativePath(validFile)}` },
463
475
  { text: '\n--- Content from referenced files ---' },
464
- { text: `\nContent from @${validFile}:\n` },
476
+ { text: `\nContent from @${getRelativePath(validFile)}:\n` },
465
477
  { text: 'console.log("Hello world");' },
466
478
  { text: '\n--- End of content ---' },
467
479
  ],
@@ -483,9 +495,9 @@ describe('handleAtCommand', () => {
483
495
  });
484
496
  expect(result).toEqual({
485
497
  processedQuery: [
486
- { text: `@${validFile} @${geminiIgnoredFile}` },
498
+ { text: `@${getRelativePath(validFile)} @${geminiIgnoredFile}` },
487
499
  { text: '\n--- Content from referenced files ---' },
488
- { text: `\nContent from @${validFile}:\n` },
500
+ { text: `\nContent from @${getRelativePath(validFile)}:\n` },
489
501
  { text: '// Main application entry' },
490
502
  { text: '\n--- End of content ---' },
491
503
  ],
@@ -500,77 +512,77 @@ describe('handleAtCommand', () => {
500
512
  name: 'comma',
501
513
  fileName: 'test.txt',
502
514
  fileContent: 'File content here',
503
- queryTemplate: (filePath) => `Look at @${filePath}, then explain it.`,
515
+ queryTemplate: (filePath) => `Look at @${getRelativePath(filePath)}, then explain it.`,
504
516
  messageId: 400,
505
517
  },
506
518
  {
507
519
  name: 'period',
508
520
  fileName: 'readme.md',
509
521
  fileContent: 'File content here',
510
- queryTemplate: (filePath) => `Check @${filePath}. What does it say?`,
522
+ queryTemplate: (filePath) => `Check @${getRelativePath(filePath)}. What does it say?`,
511
523
  messageId: 401,
512
524
  },
513
525
  {
514
526
  name: 'semicolon',
515
527
  fileName: 'example.js',
516
528
  fileContent: 'Code example',
517
- queryTemplate: (filePath) => `Review @${filePath}; check for bugs.`,
529
+ queryTemplate: (filePath) => `Review @${getRelativePath(filePath)}; check for bugs.`,
518
530
  messageId: 402,
519
531
  },
520
532
  {
521
533
  name: 'exclamation mark',
522
534
  fileName: 'important.txt',
523
535
  fileContent: 'Important content',
524
- queryTemplate: (filePath) => `Look at @${filePath}! This is critical.`,
536
+ queryTemplate: (filePath) => `Look at @${getRelativePath(filePath)}! This is critical.`,
525
537
  messageId: 403,
526
538
  },
527
539
  {
528
540
  name: 'question mark',
529
541
  fileName: 'config.json',
530
542
  fileContent: 'Config settings',
531
- queryTemplate: (filePath) => `What is in @${filePath}? Please explain.`,
543
+ queryTemplate: (filePath) => `What is in @${getRelativePath(filePath)}? Please explain.`,
532
544
  messageId: 404,
533
545
  },
534
546
  {
535
547
  name: 'opening parenthesis',
536
548
  fileName: 'func.ts',
537
549
  fileContent: 'Function definition',
538
- queryTemplate: (filePath) => `Analyze @${filePath}(the main function).`,
550
+ queryTemplate: (filePath) => `Analyze @${getRelativePath(filePath)}(the main function).`,
539
551
  messageId: 405,
540
552
  },
541
553
  {
542
554
  name: 'closing parenthesis',
543
555
  fileName: 'data.json',
544
556
  fileContent: 'Test data',
545
- queryTemplate: (filePath) => `Use data from @${filePath}) for testing.`,
557
+ queryTemplate: (filePath) => `Use data from @${getRelativePath(filePath)}) for testing.`,
546
558
  messageId: 406,
547
559
  },
548
560
  {
549
561
  name: 'opening square bracket',
550
562
  fileName: 'array.js',
551
563
  fileContent: 'Array data',
552
- queryTemplate: (filePath) => `Check @${filePath}[0] for the first element.`,
564
+ queryTemplate: (filePath) => `Check @${getRelativePath(filePath)}[0] for the first element.`,
553
565
  messageId: 407,
554
566
  },
555
567
  {
556
568
  name: 'closing square bracket',
557
569
  fileName: 'list.md',
558
570
  fileContent: 'List content',
559
- queryTemplate: (filePath) => `Review item @${filePath}] from the list.`,
571
+ queryTemplate: (filePath) => `Review item @${getRelativePath(filePath)}] from the list.`,
560
572
  messageId: 408,
561
573
  },
562
574
  {
563
575
  name: 'opening curly brace',
564
576
  fileName: 'object.ts',
565
577
  fileContent: 'Object definition',
566
- queryTemplate: (filePath) => `Parse @${filePath}{prop1: value1}.`,
578
+ queryTemplate: (filePath) => `Parse @${getRelativePath(filePath)}{prop1: value1}.`,
567
579
  messageId: 409,
568
580
  },
569
581
  {
570
582
  name: 'closing curly brace',
571
583
  fileName: 'config.yaml',
572
584
  fileContent: 'Configuration',
573
- queryTemplate: (filePath) => `Use settings from @${filePath}} for deployment.`,
585
+ queryTemplate: (filePath) => `Use settings from @${getRelativePath(filePath)}} for deployment.`,
574
586
  messageId: 410,
575
587
  },
576
588
  ];
@@ -589,7 +601,7 @@ describe('handleAtCommand', () => {
589
601
  processedQuery: [
590
602
  { text: query },
591
603
  { text: '\n--- Content from referenced files ---' },
592
- { text: `\nContent from @${filePath}:\n` },
604
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
593
605
  { text: fileContent },
594
606
  { text: '\n--- End of content ---' },
595
607
  ],
@@ -612,11 +624,13 @@ describe('handleAtCommand', () => {
612
624
  });
613
625
  expect(result).toEqual({
614
626
  processedQuery: [
615
- { text: `Compare @${file1Path}, @${file2Path}; what's different?` },
627
+ {
628
+ text: `Compare @${getRelativePath(file1Path)}, @${getRelativePath(file2Path)}; what's different?`,
629
+ },
616
630
  { text: '\n--- Content from referenced files ---' },
617
- { text: `\nContent from @${file1Path}:\n` },
631
+ { text: `\nContent from @${getRelativePath(file1Path)}:\n` },
618
632
  { text: content1 },
619
- { text: `\nContent from @${file2Path}:\n` },
633
+ { text: `\nContent from @${getRelativePath(file2Path)}:\n` },
620
634
  { text: content2 },
621
635
  { text: '\n--- End of content ---' },
622
636
  ],
@@ -638,9 +652,9 @@ describe('handleAtCommand', () => {
638
652
  });
639
653
  expect(result).toEqual({
640
654
  processedQuery: [
641
- { text: `Check @${filePath}, it has spaces.` },
655
+ { text: `Check @${getRelativePath(filePath)}, it has spaces.` },
642
656
  { text: '\n--- Content from referenced files ---' },
643
- { text: `\nContent from @${filePath}:\n` },
657
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
644
658
  { text: fileContent },
645
659
  { text: '\n--- End of content ---' },
646
660
  ],
@@ -650,7 +664,7 @@ describe('handleAtCommand', () => {
650
664
  it('should not break file paths with periods in extensions', async () => {
651
665
  const fileContent = 'TypeScript content';
652
666
  const filePath = await createTestFile(path.join(testRootDir, 'example.d.ts'), fileContent);
653
- const query = `Analyze @${filePath} for type definitions.`;
667
+ const query = `Analyze @${getRelativePath(filePath)} for type definitions.`;
654
668
  const result = await handleAtCommand({
655
669
  query,
656
670
  config: mockConfig,
@@ -661,9 +675,11 @@ describe('handleAtCommand', () => {
661
675
  });
662
676
  expect(result).toEqual({
663
677
  processedQuery: [
664
- { text: `Analyze @${filePath} for type definitions.` },
678
+ {
679
+ text: `Analyze @${getRelativePath(filePath)} for type definitions.`,
680
+ },
665
681
  { text: '\n--- Content from referenced files ---' },
666
- { text: `\nContent from @${filePath}:\n` },
682
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
667
683
  { text: fileContent },
668
684
  { text: '\n--- End of content ---' },
669
685
  ],
@@ -673,7 +689,7 @@ describe('handleAtCommand', () => {
673
689
  it('should handle file paths ending with period followed by space', async () => {
674
690
  const fileContent = 'Config content';
675
691
  const filePath = await createTestFile(path.join(testRootDir, 'config.json'), fileContent);
676
- const query = `Check @${filePath}. This file contains settings.`;
692
+ const query = `Check @${getRelativePath(filePath)}. This file contains settings.`;
677
693
  const result = await handleAtCommand({
678
694
  query,
679
695
  config: mockConfig,
@@ -684,9 +700,11 @@ describe('handleAtCommand', () => {
684
700
  });
685
701
  expect(result).toEqual({
686
702
  processedQuery: [
687
- { text: `Check @${filePath}. This file contains settings.` },
703
+ {
704
+ text: `Check @${getRelativePath(filePath)}. This file contains settings.`,
705
+ },
688
706
  { text: '\n--- Content from referenced files ---' },
689
- { text: `\nContent from @${filePath}:\n` },
707
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
690
708
  { text: fileContent },
691
709
  { text: '\n--- End of content ---' },
692
710
  ],
@@ -696,7 +714,7 @@ describe('handleAtCommand', () => {
696
714
  it('should handle comma termination with complex file paths', async () => {
697
715
  const fileContent = 'Package info';
698
716
  const filePath = await createTestFile(path.join(testRootDir, 'package.json'), fileContent);
699
- const query = `Review @${filePath}, then check dependencies.`;
717
+ const query = `Review @${getRelativePath(filePath)}, then check dependencies.`;
700
718
  const result = await handleAtCommand({
701
719
  query,
702
720
  config: mockConfig,
@@ -707,9 +725,11 @@ describe('handleAtCommand', () => {
707
725
  });
708
726
  expect(result).toEqual({
709
727
  processedQuery: [
710
- { text: `Review @${filePath}, then check dependencies.` },
728
+ {
729
+ text: `Review @${getRelativePath(filePath)}, then check dependencies.`,
730
+ },
711
731
  { text: '\n--- Content from referenced files ---' },
712
- { text: `\nContent from @${filePath}:\n` },
732
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
713
733
  { text: fileContent },
714
734
  { text: '\n--- End of content ---' },
715
735
  ],
@@ -719,7 +739,7 @@ describe('handleAtCommand', () => {
719
739
  it('should not terminate at period within file name', async () => {
720
740
  const fileContent = 'Version info';
721
741
  const filePath = await createTestFile(path.join(testRootDir, 'version.1.2.3.txt'), fileContent);
722
- const query = `Check @${filePath} contains version information.`;
742
+ const query = `Check @${getRelativePath(filePath)} contains version information.`;
723
743
  const result = await handleAtCommand({
724
744
  query,
725
745
  config: mockConfig,
@@ -730,9 +750,11 @@ describe('handleAtCommand', () => {
730
750
  });
731
751
  expect(result).toEqual({
732
752
  processedQuery: [
733
- { text: `Check @${filePath} contains version information.` },
753
+ {
754
+ text: `Check @${getRelativePath(filePath)} contains version information.`,
755
+ },
734
756
  { text: '\n--- Content from referenced files ---' },
735
- { text: `\nContent from @${filePath}:\n` },
757
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
736
758
  { text: fileContent },
737
759
  { text: '\n--- End of content ---' },
738
760
  ],
@@ -742,7 +764,7 @@ describe('handleAtCommand', () => {
742
764
  it('should handle end of string termination for period and comma', async () => {
743
765
  const fileContent = 'End file content';
744
766
  const filePath = await createTestFile(path.join(testRootDir, 'end.txt'), fileContent);
745
- const query = `Show me @${filePath}.`;
767
+ const query = `Show me @${getRelativePath(filePath)}.`;
746
768
  const result = await handleAtCommand({
747
769
  query,
748
770
  config: mockConfig,
@@ -753,9 +775,9 @@ describe('handleAtCommand', () => {
753
775
  });
754
776
  expect(result).toEqual({
755
777
  processedQuery: [
756
- { text: `Show me @${filePath}.` },
778
+ { text: `Show me @${getRelativePath(filePath)}.` },
757
779
  { text: '\n--- Content from referenced files ---' },
758
- { text: `\nContent from @${filePath}:\n` },
780
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
759
781
  { text: fileContent },
760
782
  { text: '\n--- End of content ---' },
761
783
  ],
@@ -765,7 +787,7 @@ describe('handleAtCommand', () => {
765
787
  it('should handle files with special characters in names', async () => {
766
788
  const fileContent = 'File with special chars content';
767
789
  const filePath = await createTestFile(path.join(testRootDir, 'file$with&special#chars.txt'), fileContent);
768
- const query = `Check @${filePath} for content.`;
790
+ const query = `Check @${getRelativePath(filePath)} for content.`;
769
791
  const result = await handleAtCommand({
770
792
  query,
771
793
  config: mockConfig,
@@ -776,9 +798,9 @@ describe('handleAtCommand', () => {
776
798
  });
777
799
  expect(result).toEqual({
778
800
  processedQuery: [
779
- { text: `Check @${filePath} for content.` },
801
+ { text: `Check @${getRelativePath(filePath)} for content.` },
780
802
  { text: '\n--- Content from referenced files ---' },
781
- { text: `\nContent from @${filePath}:\n` },
803
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
782
804
  { text: fileContent },
783
805
  { text: '\n--- End of content ---' },
784
806
  ],
@@ -788,7 +810,7 @@ describe('handleAtCommand', () => {
788
810
  it('should handle basic file names without special characters', async () => {
789
811
  const fileContent = 'Basic file content';
790
812
  const filePath = await createTestFile(path.join(testRootDir, 'basicfile.txt'), fileContent);
791
- const query = `Check @${filePath} please.`;
813
+ const query = `Check @${getRelativePath(filePath)} please.`;
792
814
  const result = await handleAtCommand({
793
815
  query,
794
816
  config: mockConfig,
@@ -799,21 +821,98 @@ describe('handleAtCommand', () => {
799
821
  });
800
822
  expect(result).toEqual({
801
823
  processedQuery: [
802
- { text: `Check @${filePath} please.` },
824
+ { text: `Check @${getRelativePath(filePath)} please.` },
825
+ { text: '\n--- Content from referenced files ---' },
826
+ { text: `\nContent from @${getRelativePath(filePath)}:\n` },
827
+ { text: fileContent },
828
+ { text: '\n--- End of content ---' },
829
+ ],
830
+ shouldProceed: true,
831
+ });
832
+ });
833
+ });
834
+ describe('absolute path handling', () => {
835
+ it('should handle absolute file paths correctly', async () => {
836
+ const fileContent = 'console.log("This is an absolute path test");';
837
+ const relativePath = path.join('src', 'absolute-test.ts');
838
+ const absolutePath = await createTestFile(path.join(testRootDir, relativePath), fileContent);
839
+ const query = `Check @${absolutePath} please.`;
840
+ const result = await handleAtCommand({
841
+ query,
842
+ config: mockConfig,
843
+ addItem: mockAddItem,
844
+ onDebugMessage: mockOnDebugMessage,
845
+ messageId: 500,
846
+ signal: abortController.signal,
847
+ });
848
+ expect(result).toEqual({
849
+ processedQuery: [
850
+ { text: `Check @${relativePath} please.` },
803
851
  { text: '\n--- Content from referenced files ---' },
804
- { text: `\nContent from @${filePath}:\n` },
852
+ { text: `\nContent from @${relativePath}:\n` },
805
853
  { text: fileContent },
806
854
  { text: '\n--- End of content ---' },
807
855
  ],
808
856
  shouldProceed: true,
809
857
  });
858
+ expect(mockOnDebugMessage).toHaveBeenCalledWith(expect.stringContaining(`using relative path: ${relativePath}`));
859
+ });
860
+ it('should handle absolute directory paths correctly', async () => {
861
+ const fileContent = 'export default function test() { return "absolute dir test"; }';
862
+ const subDirPath = path.join('src', 'utils');
863
+ const fileName = 'helper.ts';
864
+ await createTestFile(path.join(testRootDir, subDirPath, fileName), fileContent);
865
+ const absoluteDirPath = path.join(testRootDir, subDirPath);
866
+ const query = `Check @${absoluteDirPath} please.`;
867
+ const result = await handleAtCommand({
868
+ query,
869
+ config: mockConfig,
870
+ addItem: mockAddItem,
871
+ onDebugMessage: mockOnDebugMessage,
872
+ messageId: 501,
873
+ signal: abortController.signal,
874
+ });
875
+ expect(result.shouldProceed).toBe(true);
876
+ expect(result.processedQuery).toEqual(expect.arrayContaining([
877
+ { text: `Check @${path.join(subDirPath, '**')} please.` },
878
+ expect.objectContaining({
879
+ text: '\n--- Content from referenced files ---',
880
+ }),
881
+ ]));
882
+ expect(mockOnDebugMessage).toHaveBeenCalledWith(expect.stringContaining(`using glob: ${path.join(subDirPath, '**')}`));
883
+ });
884
+ it('should skip absolute paths outside workspace', async () => {
885
+ const outsidePath = '/tmp/outside-workspace.txt';
886
+ const query = `Check @${outsidePath} please.`;
887
+ const mockWorkspaceContext = {
888
+ isPathWithinWorkspace: vi.fn((path) => path.startsWith(testRootDir)),
889
+ getDirectories: () => [testRootDir],
890
+ addDirectory: vi.fn(),
891
+ getInitialDirectories: () => [testRootDir],
892
+ setDirectories: vi.fn(),
893
+ onDirectoriesChanged: vi.fn(() => () => { }),
894
+ };
895
+ mockConfig.getWorkspaceContext = () => mockWorkspaceContext;
896
+ const result = await handleAtCommand({
897
+ query,
898
+ config: mockConfig,
899
+ addItem: mockAddItem,
900
+ onDebugMessage: mockOnDebugMessage,
901
+ messageId: 502,
902
+ signal: abortController.signal,
903
+ });
904
+ expect(result).toEqual({
905
+ processedQuery: [{ text: `Check @${outsidePath} please.` }],
906
+ shouldProceed: true,
907
+ });
908
+ expect(mockOnDebugMessage).toHaveBeenCalledWith(`Path ${outsidePath} is not in the workspace and will be skipped.`);
810
909
  });
811
910
  });
812
911
  it("should not add the user's turn to history, as that is the caller's responsibility", async () => {
813
912
  // Arrange
814
913
  const fileContent = 'This is the file content.';
815
914
  const filePath = await createTestFile(path.join(testRootDir, 'path', 'to', 'another-file.txt'), fileContent);
816
- const query = `A query with @${filePath}`;
915
+ const query = `A query with @${getRelativePath(filePath)}`;
817
916
  // Act
818
917
  await handleAtCommand({
819
918
  query,