@theia/ai-ide 1.67.0-next.3 → 1.67.0-next.56
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/README.md +1 -0
- package/package.json +21 -21
- package/src/browser/ai-configuration/agent-configuration-widget.tsx +3 -3
- package/src/browser/context-file-validation-service-impl.spec.ts +405 -0
- package/src/browser/context-file-validation-service-impl.ts +120 -0
- package/src/browser/context-functions.spec.ts +155 -1
- package/src/browser/context-functions.ts +40 -6
- package/src/browser/file-changeset-functions.spec.ts +13 -13
- package/src/browser/file-changeset-functions.ts +9 -9
- package/src/browser/frontend-module.ts +12 -4
- package/src/browser/ide-chat-welcome-message-provider.tsx +64 -70
- package/src/browser/remember-command-contribution.ts +105 -0
- package/src/browser/workspace-functions.ts +68 -1
- package/src/common/ai-ide-preferences.ts +1 -1
- package/src/common/coder-replace-prompt-template.ts +8 -9
- package/src/common/command-prompt-template.ts +5 -5
- package/src/common/file-changeset-function-ids.ts +15 -1
- package/src/common/orchestrator-chat-agent.ts +2 -2
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts +0 -41
- package/lib/browser/ai-configuration/agent-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/agent-configuration-widget.js +0 -333
- package/lib/browser/ai-configuration/agent-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/ai-configuration-service.d.ts +0 -18
- package/lib/browser/ai-configuration/ai-configuration-service.d.ts.map +0 -1
- package/lib/browser/ai-configuration/ai-configuration-service.js +0 -53
- package/lib/browser/ai-configuration/ai-configuration-service.js.map +0 -1
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.d.ts +0 -14
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.d.ts.map +0 -1
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.js +0 -67
- package/lib/browser/ai-configuration/ai-configuration-view-contribution.js.map +0 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts +0 -29
- package/lib/browser/ai-configuration/ai-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/ai-configuration-widget.js +0 -118
- package/lib/browser/ai-configuration/ai-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/language-model-renderer.d.ts +0 -13
- package/lib/browser/ai-configuration/language-model-renderer.d.ts.map +0 -1
- package/lib/browser/ai-configuration/language-model-renderer.js +0 -104
- package/lib/browser/ai-configuration/language-model-renderer.js.map +0 -1
- package/lib/browser/ai-configuration/mcp-configuration-widget.d.ts +0 -43
- package/lib/browser/ai-configuration/mcp-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/mcp-configuration-widget.js +0 -302
- package/lib/browser/ai-configuration/mcp-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts +0 -41
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.js +0 -226
- package/lib/browser/ai-configuration/model-aliases-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts +0 -141
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js +0 -508
- package/lib/browser/ai-configuration/prompt-fragments-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts +0 -10
- package/lib/browser/ai-configuration/template-settings-renderer.d.ts.map +0 -1
- package/lib/browser/ai-configuration/template-settings-renderer.js +0 -48
- package/lib/browser/ai-configuration/template-settings-renderer.js.map +0 -1
- package/lib/browser/ai-configuration/token-usage-configuration-widget.d.ts +0 -22
- package/lib/browser/ai-configuration/token-usage-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/token-usage-configuration-widget.js +0 -156
- package/lib/browser/ai-configuration/token-usage-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/tools-configuration-widget.d.ts +0 -30
- package/lib/browser/ai-configuration/tools-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/tools-configuration-widget.js +0 -150
- package/lib/browser/ai-configuration/tools-configuration-widget.js.map +0 -1
- package/lib/browser/ai-configuration/variable-configuration-widget.d.ts +0 -19
- package/lib/browser/ai-configuration/variable-configuration-widget.d.ts.map +0 -1
- package/lib/browser/ai-configuration/variable-configuration-widget.js +0 -99
- package/lib/browser/ai-configuration/variable-configuration-widget.js.map +0 -1
- package/lib/browser/ai-ide-activation-service.d.ts +0 -18
- package/lib/browser/ai-ide-activation-service.d.ts.map +0 -1
- package/lib/browser/ai-ide-activation-service.js +0 -71
- package/lib/browser/ai-ide-activation-service.js.map +0 -1
- package/lib/browser/ai-terminal-functions.d.ts +0 -13
- package/lib/browser/ai-terminal-functions.d.ts.map +0 -1
- package/lib/browser/ai-terminal-functions.js +0 -114
- package/lib/browser/ai-terminal-functions.js.map +0 -1
- package/lib/browser/app-tester-chat-agent.d.ts +0 -35
- package/lib/browser/app-tester-chat-agent.d.ts.map +0 -1
- package/lib/browser/app-tester-chat-agent.js +0 -142
- package/lib/browser/app-tester-chat-agent.js.map +0 -1
- package/lib/browser/app-tester-chat-functions.d.ts +0 -25
- package/lib/browser/app-tester-chat-functions.d.ts.map +0 -1
- package/lib/browser/app-tester-chat-functions.js +0 -170
- package/lib/browser/app-tester-chat-functions.js.map +0 -1
- package/lib/browser/app-tester-prompt-template.d.ts +0 -6
- package/lib/browser/app-tester-prompt-template.d.ts.map +0 -1
- package/lib/browser/app-tester-prompt-template.js +0 -83
- package/lib/browser/app-tester-prompt-template.js.map +0 -1
- package/lib/browser/architect-agent.d.ts +0 -15
- package/lib/browser/architect-agent.d.ts.map +0 -1
- package/lib/browser/architect-agent.js +0 -68
- package/lib/browser/architect-agent.js.map +0 -1
- package/lib/browser/coder-agent.d.ts +0 -15
- package/lib/browser/coder-agent.d.ts.map +0 -1
- package/lib/browser/coder-agent.js +0 -81
- package/lib/browser/coder-agent.js.map +0 -1
- package/lib/browser/context-functions.d.ts +0 -14
- package/lib/browser/context-functions.d.ts.map +0 -1
- package/lib/browser/context-functions.js +0 -130
- package/lib/browser/context-functions.js.map +0 -1
- package/lib/browser/context-functions.spec.d.ts +0 -2
- package/lib/browser/context-functions.spec.d.ts.map +0 -1
- package/lib/browser/context-functions.spec.js +0 -93
- package/lib/browser/context-functions.spec.js.map +0 -1
- package/lib/browser/file-changeset-function.spec.d.ts +0 -2
- package/lib/browser/file-changeset-function.spec.d.ts.map +0 -1
- package/lib/browser/file-changeset-function.spec.js +0 -45
- package/lib/browser/file-changeset-function.spec.js.map +0 -1
- package/lib/browser/file-changeset-functions.d.ts +0 -87
- package/lib/browser/file-changeset-functions.d.ts.map +0 -1
- package/lib/browser/file-changeset-functions.js +0 -645
- package/lib/browser/file-changeset-functions.js.map +0 -1
- package/lib/browser/file-changeset-functions.spec.d.ts +0 -2
- package/lib/browser/file-changeset-functions.spec.d.ts.map +0 -1
- package/lib/browser/file-changeset-functions.spec.js +0 -179
- package/lib/browser/file-changeset-functions.spec.js.map +0 -1
- package/lib/browser/frontend-module.d.ts +0 -5
- package/lib/browser/frontend-module.d.ts.map +0 -1
- package/lib/browser/frontend-module.js +0 -214
- package/lib/browser/frontend-module.js.map +0 -1
- package/lib/browser/github-chat-agent.d.ts +0 -48
- package/lib/browser/github-chat-agent.d.ts.map +0 -1
- package/lib/browser/github-chat-agent.js +0 -222
- package/lib/browser/github-chat-agent.js.map +0 -1
- package/lib/browser/github-prompt-template.d.ts +0 -6
- package/lib/browser/github-prompt-template.d.ts.map +0 -1
- package/lib/browser/github-prompt-template.js +0 -53
- package/lib/browser/github-prompt-template.js.map +0 -1
- package/lib/browser/github-repo-variable-contribution.d.ts +0 -15
- package/lib/browser/github-repo-variable-contribution.d.ts.map +0 -1
- package/lib/browser/github-repo-variable-contribution.js +0 -82
- package/lib/browser/github-repo-variable-contribution.js.map +0 -1
- package/lib/browser/ide-chat-welcome-message-provider.d.ts +0 -11
- package/lib/browser/ide-chat-welcome-message-provider.d.ts.map +0 -1
- package/lib/browser/ide-chat-welcome-message-provider.js +0 -142
- package/lib/browser/ide-chat-welcome-message-provider.js.map +0 -1
- package/lib/browser/project-info-agent.d.ts +0 -13
- package/lib/browser/project-info-agent.d.ts.map +0 -1
- package/lib/browser/project-info-agent.js +0 -45
- package/lib/browser/project-info-agent.js.map +0 -1
- package/lib/browser/summarize-session-command-contribution.d.ts +0 -19
- package/lib/browser/summarize-session-command-contribution.d.ts.map +0 -1
- package/lib/browser/summarize-session-command-contribution.js +0 -118
- package/lib/browser/summarize-session-command-contribution.js.map +0 -1
- package/lib/browser/task-background-summary-variable.d.ts +0 -9
- package/lib/browser/task-background-summary-variable.d.ts.map +0 -1
- package/lib/browser/task-background-summary-variable.js +0 -60
- package/lib/browser/task-background-summary-variable.js.map +0 -1
- package/lib/browser/task-context-agent.d.ts +0 -13
- package/lib/browser/task-context-agent.d.ts.map +0 -1
- package/lib/browser/task-context-agent.js +0 -45
- package/lib/browser/task-context-agent.js.map +0 -1
- package/lib/browser/task-context-file-storage-service.d.ts +0 -40
- package/lib/browser/task-context-file-storage-service.d.ts.map +0 -1
- package/lib/browser/task-context-file-storage-service.js +0 -232
- package/lib/browser/task-context-file-storage-service.js.map +0 -1
- package/lib/browser/template-preference-contribution.d.ts +0 -17
- package/lib/browser/template-preference-contribution.d.ts.map +0 -1
- package/lib/browser/template-preference-contribution.js +0 -94
- package/lib/browser/template-preference-contribution.js.map +0 -1
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts +0 -2
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.d.ts.map +0 -1
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.js +0 -52
- package/lib/browser/test/tool-provider-cancellation-test-util.spec.js.map +0 -1
- package/lib/browser/workspace-functions.d.ts +0 -75
- package/lib/browser/workspace-functions.d.ts.map +0 -1
- package/lib/browser/workspace-functions.js +0 -641
- package/lib/browser/workspace-functions.js.map +0 -1
- package/lib/browser/workspace-functions.spec.d.ts +0 -2
- package/lib/browser/workspace-functions.spec.d.ts.map +0 -1
- package/lib/browser/workspace-functions.spec.js +0 -161
- package/lib/browser/workspace-functions.spec.js.map +0 -1
- package/lib/browser/workspace-launch-provider.d.ts +0 -24
- package/lib/browser/workspace-launch-provider.d.ts.map +0 -1
- package/lib/browser/workspace-launch-provider.js +0 -216
- package/lib/browser/workspace-launch-provider.js.map +0 -1
- package/lib/browser/workspace-launch-provider.spec.d.ts +0 -2
- package/lib/browser/workspace-launch-provider.spec.d.ts.map +0 -1
- package/lib/browser/workspace-launch-provider.spec.js +0 -245
- package/lib/browser/workspace-launch-provider.spec.js.map +0 -1
- package/lib/browser/workspace-search-provider.d.ts +0 -15
- package/lib/browser/workspace-search-provider.d.ts.map +0 -1
- package/lib/browser/workspace-search-provider.js +0 -204
- package/lib/browser/workspace-search-provider.js.map +0 -1
- package/lib/browser/workspace-search-provider.spec.d.ts +0 -2
- package/lib/browser/workspace-search-provider.spec.d.ts.map +0 -1
- package/lib/browser/workspace-search-provider.spec.js +0 -82
- package/lib/browser/workspace-search-provider.spec.js.map +0 -1
- package/lib/browser/workspace-task-provider.d.ts +0 -15
- package/lib/browser/workspace-task-provider.d.ts.map +0 -1
- package/lib/browser/workspace-task-provider.js +0 -138
- package/lib/browser/workspace-task-provider.js.map +0 -1
- package/lib/browser/workspace-task-provider.spec.d.ts +0 -2
- package/lib/browser/workspace-task-provider.spec.d.ts.map +0 -1
- package/lib/browser/workspace-task-provider.spec.js +0 -109
- package/lib/browser/workspace-task-provider.spec.js.map +0 -1
- package/lib/common/ai-configuration-preferences.d.ts +0 -8
- package/lib/common/ai-configuration-preferences.d.ts.map +0 -1
- package/lib/common/ai-configuration-preferences.js +0 -41
- package/lib/common/ai-configuration-preferences.js.map +0 -1
- package/lib/common/ai-ide-preferences.d.ts +0 -5
- package/lib/common/ai-ide-preferences.d.ts.map +0 -1
- package/lib/common/ai-ide-preferences.js +0 -53
- package/lib/common/ai-ide-preferences.js.map +0 -1
- package/lib/common/ai-terminal-functions.d.ts +0 -2
- package/lib/common/ai-terminal-functions.d.ts.map +0 -1
- package/lib/common/ai-terminal-functions.js +0 -20
- package/lib/common/ai-terminal-functions.js.map +0 -1
- package/lib/common/app-tester-chat-functions.d.ts +0 -5
- package/lib/common/app-tester-chat-functions.d.ts.map +0 -1
- package/lib/common/app-tester-chat-functions.js +0 -23
- package/lib/common/app-tester-chat-functions.js.map +0 -1
- package/lib/common/architect-prompt-template.d.ts +0 -3
- package/lib/common/architect-prompt-template.d.ts.map +0 -1
- package/lib/common/architect-prompt-template.js +0 -81
- package/lib/common/architect-prompt-template.js.map +0 -1
- package/lib/common/browser-automation-protocol.d.ts +0 -15
- package/lib/common/browser-automation-protocol.d.ts.map +0 -1
- package/lib/common/browser-automation-protocol.js +0 -22
- package/lib/common/browser-automation-protocol.js.map +0 -1
- package/lib/common/coder-replace-prompt-template.d.ts +0 -11
- package/lib/common/coder-replace-prompt-template.d.ts.map +0 -1
- package/lib/common/coder-replace-prompt-template.js +0 -295
- package/lib/common/coder-replace-prompt-template.js.map +0 -1
- package/lib/common/command-chat-agents.d.ts +0 -36
- package/lib/common/command-chat-agents.d.ts.map +0 -1
- package/lib/common/command-chat-agents.js +0 -122
- package/lib/common/command-chat-agents.js.map +0 -1
- package/lib/common/command-prompt-template.d.ts +0 -3
- package/lib/common/command-prompt-template.d.ts.map +0 -1
- package/lib/common/command-prompt-template.js +0 -226
- package/lib/common/command-prompt-template.js.map +0 -1
- package/lib/common/context-files-variable.d.ts +0 -9
- package/lib/common/context-files-variable.d.ts.map +0 -1
- package/lib/common/context-files-variable.js +0 -52
- package/lib/common/context-files-variable.js.map +0 -1
- package/lib/common/context-functions.d.ts +0 -4
- package/lib/common/context-functions.d.ts.map +0 -1
- package/lib/common/context-functions.js +0 -22
- package/lib/common/context-functions.js.map +0 -1
- package/lib/common/context-variables.d.ts +0 -3
- package/lib/common/context-variables.d.ts.map +0 -1
- package/lib/common/context-variables.js +0 -21
- package/lib/common/context-variables.js.map +0 -1
- package/lib/common/file-changeset-function-ids.d.ts +0 -8
- package/lib/common/file-changeset-function-ids.d.ts.map +0 -1
- package/lib/common/file-changeset-function-ids.js +0 -26
- package/lib/common/file-changeset-function-ids.js.map +0 -1
- package/lib/common/github-repo-protocol.d.ts +0 -15
- package/lib/common/github-repo-protocol.d.ts.map +0 -1
- package/lib/common/github-repo-protocol.js +0 -21
- package/lib/common/github-repo-protocol.js.map +0 -1
- package/lib/common/orchestrator-chat-agent.d.ts +0 -36
- package/lib/common/orchestrator-chat-agent.d.ts.map +0 -1
- package/lib/common/orchestrator-chat-agent.js +0 -167
- package/lib/common/orchestrator-chat-agent.js.map +0 -1
- package/lib/common/orchestrator-prompt-template.d.ts +0 -3
- package/lib/common/orchestrator-prompt-template.d.ts.map +0 -1
- package/lib/common/orchestrator-prompt-template.js +0 -55
- package/lib/common/orchestrator-prompt-template.js.map +0 -1
- package/lib/common/project-info-prompt-template.d.ts +0 -6
- package/lib/common/project-info-prompt-template.d.ts.map +0 -1
- package/lib/common/project-info-prompt-template.js +0 -145
- package/lib/common/project-info-prompt-template.js.map +0 -1
- package/lib/common/summarize-session-commands.d.ts +0 -4
- package/lib/common/summarize-session-commands.d.ts.map +0 -1
- package/lib/common/summarize-session-commands.js +0 -28
- package/lib/common/summarize-session-commands.js.map +0 -1
- package/lib/common/task-context-prompt-template.d.ts +0 -8
- package/lib/common/task-context-prompt-template.d.ts.map +0 -1
- package/lib/common/task-context-prompt-template.js +0 -217
- package/lib/common/task-context-prompt-template.js.map +0 -1
- package/lib/common/universal-chat-agent.d.ts +0 -17
- package/lib/common/universal-chat-agent.d.ts.map +0 -1
- package/lib/common/universal-chat-agent.js +0 -47
- package/lib/common/universal-chat-agent.js.map +0 -1
- package/lib/common/universal-prompt-template.d.ts +0 -4
- package/lib/common/universal-prompt-template.d.ts.map +0 -1
- package/lib/common/universal-prompt-template.js +0 -32
- package/lib/common/universal-prompt-template.js.map +0 -1
- package/lib/common/workspace-functions.d.ts +0 -12
- package/lib/common/workspace-functions.d.ts.map +0 -1
- package/lib/common/workspace-functions.js +0 -30
- package/lib/common/workspace-functions.js.map +0 -1
- package/lib/common/workspace-preferences.d.ts +0 -10
- package/lib/common/workspace-preferences.d.ts.map +0 -1
- package/lib/common/workspace-preferences.js +0 -89
- package/lib/common/workspace-preferences.js.map +0 -1
- package/lib/common/workspace-search-provider-util.d.ts +0 -17
- package/lib/common/workspace-search-provider-util.d.ts.map +0 -1
- package/lib/common/workspace-search-provider-util.js +0 -51
- package/lib/common/workspace-search-provider-util.js.map +0 -1
- package/lib/node/app-tester-agent/browser-automation-impl.d.ts +0 -18
- package/lib/node/app-tester-agent/browser-automation-impl.d.ts.map +0 -1
- package/lib/node/app-tester-agent/browser-automation-impl.js +0 -96
- package/lib/node/app-tester-agent/browser-automation-impl.js.map +0 -1
- package/lib/node/backend-module.d.ts +0 -4
- package/lib/node/backend-module.d.ts.map +0 -1
- package/lib/node/backend-module.js +0 -45
- package/lib/node/backend-module.js.map +0 -1
- package/lib/node/github-repo-service-impl.d.ts +0 -7
- package/lib/node/github-repo-service-impl.d.ts.map +0 -1
- package/lib/node/github-repo-service-impl.js +0 -86
- package/lib/node/github-repo-service-impl.js.map +0 -1
- package/lib/package.spec.d.ts +0 -1
- package/lib/package.spec.d.ts.map +0 -1
- package/lib/package.spec.js +0 -26
- package/lib/package.spec.js.map +0 -1
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ The package provides a configuration view that enables you to adjust settings re
|
|
|
34
34
|
|
|
35
35
|
## Additional Information
|
|
36
36
|
|
|
37
|
+
- [API documentation for `@theia/ai-ide`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_ai-ide.html)
|
|
37
38
|
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
|
38
39
|
- [Theia - Website](https://theia-ide.org/)
|
|
39
40
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/ai-ide",
|
|
3
|
-
"version": "1.67.0-next.
|
|
3
|
+
"version": "1.67.0-next.56+d8f18cc386c",
|
|
4
4
|
"description": "AI IDE Agents Extension",
|
|
5
5
|
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -15,23 +15,23 @@
|
|
|
15
15
|
"theia-extension"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@theia/ai-chat": "1.67.0-next.
|
|
19
|
-
"@theia/ai-chat-ui": "1.67.0-next.
|
|
20
|
-
"@theia/ai-core": "1.67.0-next.
|
|
21
|
-
"@theia/ai-mcp": "1.67.0-next.
|
|
22
|
-
"@theia/core": "1.67.0-next.
|
|
23
|
-
"@theia/debug": "1.67.0-next.
|
|
24
|
-
"@theia/editor": "1.67.0-next.
|
|
25
|
-
"@theia/filesystem": "1.67.0-next.
|
|
26
|
-
"@theia/markers": "1.67.0-next.
|
|
27
|
-
"@theia/monaco": "1.67.0-next.
|
|
28
|
-
"@theia/navigator": "1.67.0-next.
|
|
29
|
-
"@theia/preferences": "1.67.0-next.
|
|
30
|
-
"@theia/scm": "1.67.0-next.
|
|
31
|
-
"@theia/search-in-workspace": "1.67.0-next.
|
|
32
|
-
"@theia/task": "1.67.0-next.
|
|
33
|
-
"@theia/terminal": "1.67.0-next.
|
|
34
|
-
"@theia/workspace": "1.67.0-next.
|
|
18
|
+
"@theia/ai-chat": "1.67.0-next.56+d8f18cc386c",
|
|
19
|
+
"@theia/ai-chat-ui": "1.67.0-next.56+d8f18cc386c",
|
|
20
|
+
"@theia/ai-core": "1.67.0-next.56+d8f18cc386c",
|
|
21
|
+
"@theia/ai-mcp": "1.67.0-next.56+d8f18cc386c",
|
|
22
|
+
"@theia/core": "1.67.0-next.56+d8f18cc386c",
|
|
23
|
+
"@theia/debug": "1.67.0-next.56+d8f18cc386c",
|
|
24
|
+
"@theia/editor": "1.67.0-next.56+d8f18cc386c",
|
|
25
|
+
"@theia/filesystem": "1.67.0-next.56+d8f18cc386c",
|
|
26
|
+
"@theia/markers": "1.67.0-next.56+d8f18cc386c",
|
|
27
|
+
"@theia/monaco": "1.67.0-next.56+d8f18cc386c",
|
|
28
|
+
"@theia/navigator": "1.67.0-next.56+d8f18cc386c",
|
|
29
|
+
"@theia/preferences": "1.67.0-next.56+d8f18cc386c",
|
|
30
|
+
"@theia/scm": "1.67.0-next.56+d8f18cc386c",
|
|
31
|
+
"@theia/search-in-workspace": "1.67.0-next.56+d8f18cc386c",
|
|
32
|
+
"@theia/task": "1.67.0-next.56+d8f18cc386c",
|
|
33
|
+
"@theia/terminal": "1.67.0-next.56+d8f18cc386c",
|
|
34
|
+
"@theia/workspace": "1.67.0-next.56+d8f18cc386c",
|
|
35
35
|
"date-fns": "^4.1.0",
|
|
36
36
|
"ignore": "^6.0.0",
|
|
37
37
|
"js-yaml": "^4.1.0",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@theia/cli": "1.67.0-next.
|
|
47
|
-
"@theia/test": "1.67.0-next.
|
|
46
|
+
"@theia/cli": "1.67.0-next.56+d8f18cc386c",
|
|
47
|
+
"@theia/test": "1.67.0-next.56+d8f18cc386c"
|
|
48
48
|
},
|
|
49
49
|
"theiaExtensions": [
|
|
50
50
|
{
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"nyc": {
|
|
69
69
|
"extends": "../../configs/nyc.json"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "d8f18cc386c45a736cd193d42eab02c8f64c6b10"
|
|
72
72
|
}
|
|
@@ -347,16 +347,16 @@ export class AIAgentConfigurationWidget extends ReactWidget {
|
|
|
347
347
|
this.updateParsedPromptParts();
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
private toggleAgentEnabled = () => {
|
|
350
|
+
private toggleAgentEnabled = async () => {
|
|
351
351
|
const agent = this.aiConfigurationSelectionService.getActiveAgent();
|
|
352
352
|
if (!agent) {
|
|
353
353
|
return false;
|
|
354
354
|
}
|
|
355
355
|
const enabled = this.agentService.isEnabled(agent.id);
|
|
356
356
|
if (enabled) {
|
|
357
|
-
this.agentService.disableAgent(agent.id);
|
|
357
|
+
await this.agentService.disableAgent(agent.id);
|
|
358
358
|
} else {
|
|
359
|
-
this.agentService.enableAgent(agent.id);
|
|
359
|
+
await this.agentService.enableAgent(agent.id);
|
|
360
360
|
}
|
|
361
361
|
this.update();
|
|
362
362
|
};
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
|
|
18
|
+
let disableJSDOM = enableJSDOM();
|
|
19
|
+
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
|
|
20
|
+
FrontendApplicationConfigProvider.set({});
|
|
21
|
+
|
|
22
|
+
import { expect } from 'chai';
|
|
23
|
+
import { Container } from '@theia/core/shared/inversify';
|
|
24
|
+
import { URI, PreferenceService } from '@theia/core';
|
|
25
|
+
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
26
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
|
27
|
+
import { FileStat } from '@theia/filesystem/lib/common/files';
|
|
28
|
+
import { ContextFileValidationService, FileValidationState } from '@theia/ai-chat/lib/browser/context-file-validation-service';
|
|
29
|
+
import { ContextFileValidationServiceImpl } from './context-file-validation-service-impl';
|
|
30
|
+
import { WorkspaceFunctionScope } from './workspace-functions';
|
|
31
|
+
|
|
32
|
+
disableJSDOM();
|
|
33
|
+
|
|
34
|
+
describe('ContextFileValidationService', () => {
|
|
35
|
+
let container: Container;
|
|
36
|
+
let validationService: ContextFileValidationService;
|
|
37
|
+
let mockFileService: FileService;
|
|
38
|
+
let mockWorkspaceService: WorkspaceService;
|
|
39
|
+
let mockPreferenceService: PreferenceService;
|
|
40
|
+
|
|
41
|
+
const workspaceRoot = new URI('file:///home/user/workspace');
|
|
42
|
+
|
|
43
|
+
// Store URIs as actual URI strings, exactly as URI.toString() would produce them
|
|
44
|
+
const existingFiles = new Map<string, boolean>([
|
|
45
|
+
// Files inside workspace
|
|
46
|
+
['file:///home/user/workspace/src/index.tsx', true],
|
|
47
|
+
['file:///home/user/workspace/package.json', true],
|
|
48
|
+
['file:///home/user/workspace/README.md', true],
|
|
49
|
+
['file:///home/user/workspace/src/components/Button.tsx', true],
|
|
50
|
+
['file:///home/user/workspace/config.json', true],
|
|
51
|
+
['file:///home/user/workspace/src/file%20with%20spaces.tsx', true],
|
|
52
|
+
// Files outside workspace (these exist but should be rejected)
|
|
53
|
+
['file:///etc/passwd', true],
|
|
54
|
+
['file:///etc/hosts', true],
|
|
55
|
+
['file:///home/other-user/secret.txt', true],
|
|
56
|
+
['file:///tmp/temporary-file.log', true]
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
before(() => {
|
|
60
|
+
disableJSDOM = enableJSDOM();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
after(() => {
|
|
64
|
+
disableJSDOM();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
beforeEach(async () => {
|
|
68
|
+
container = new Container();
|
|
69
|
+
|
|
70
|
+
// Mock WorkspaceService
|
|
71
|
+
mockWorkspaceService = {
|
|
72
|
+
tryGetRoots: () => [{
|
|
73
|
+
resource: workspaceRoot,
|
|
74
|
+
isDirectory: true
|
|
75
|
+
} as FileStat],
|
|
76
|
+
roots: Promise.resolve([{
|
|
77
|
+
resource: workspaceRoot,
|
|
78
|
+
isDirectory: true
|
|
79
|
+
} as FileStat])
|
|
80
|
+
} as unknown as WorkspaceService;
|
|
81
|
+
|
|
82
|
+
// Mock FileService
|
|
83
|
+
mockFileService = {
|
|
84
|
+
exists: async (uri: URI) => {
|
|
85
|
+
const normalizedUri = uri.path.normalize();
|
|
86
|
+
const normalizedUriString = uri.withPath(normalizedUri).toString();
|
|
87
|
+
const uriString = uri.toString();
|
|
88
|
+
|
|
89
|
+
const exists = (existingFiles.has(uriString) && existingFiles.get(uriString) === true) ||
|
|
90
|
+
(existingFiles.has(normalizedUriString) && existingFiles.get(normalizedUriString) === true);
|
|
91
|
+
return exists;
|
|
92
|
+
},
|
|
93
|
+
resolve: async (uri: URI) => {
|
|
94
|
+
const uriString = uri.toString();
|
|
95
|
+
if (existingFiles.has(uriString) && existingFiles.get(uriString) === true) {
|
|
96
|
+
return {
|
|
97
|
+
resource: uri,
|
|
98
|
+
isDirectory: false
|
|
99
|
+
} as FileStat;
|
|
100
|
+
}
|
|
101
|
+
throw new Error('File not found');
|
|
102
|
+
}
|
|
103
|
+
} as unknown as FileService;
|
|
104
|
+
|
|
105
|
+
// Mock PreferenceService
|
|
106
|
+
mockPreferenceService = {
|
|
107
|
+
get: () => false
|
|
108
|
+
} as unknown as PreferenceService;
|
|
109
|
+
|
|
110
|
+
container.bind(FileService).toConstantValue(mockFileService);
|
|
111
|
+
container.bind(WorkspaceService).toConstantValue(mockWorkspaceService);
|
|
112
|
+
container.bind(PreferenceService).toConstantValue(mockPreferenceService);
|
|
113
|
+
container.bind(WorkspaceFunctionScope).toSelf();
|
|
114
|
+
container.bind(ContextFileValidationServiceImpl).toSelf();
|
|
115
|
+
container.bind(ContextFileValidationService).toService(ContextFileValidationServiceImpl);
|
|
116
|
+
|
|
117
|
+
validationService = await container.getAsync(ContextFileValidationService);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('validateFile with relative paths', () => {
|
|
121
|
+
it('should validate existing file with relative path', async () => {
|
|
122
|
+
const result = await validationService.validateFile('src/index.tsx');
|
|
123
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should reject non-existing file with relative path', async () => {
|
|
127
|
+
const result = await validationService.validateFile('src/missing.tsx');
|
|
128
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should validate nested file with relative path', async () => {
|
|
132
|
+
const result = await validationService.validateFile('src/components/Button.tsx');
|
|
133
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should validate file in root with relative path', async () => {
|
|
137
|
+
const result = await validationService.validateFile('package.json');
|
|
138
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('validateFile with absolute file paths', () => {
|
|
143
|
+
it('should validate existing file with absolute path within workspace', async () => {
|
|
144
|
+
const result = await validationService.validateFile('/home/user/workspace/src/index.tsx');
|
|
145
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should reject non-existing file with absolute path within workspace', async () => {
|
|
149
|
+
const result = await validationService.validateFile('/home/user/workspace/src/missing.tsx');
|
|
150
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should reject existing file with absolute path outside workspace (/etc/passwd)', async () => {
|
|
154
|
+
const result = await validationService.validateFile('/etc/passwd');
|
|
155
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should reject existing file with absolute path outside workspace (/etc/hosts)', async () => {
|
|
159
|
+
const result = await validationService.validateFile('/etc/hosts');
|
|
160
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should reject existing file with absolute path in other user directory', async () => {
|
|
164
|
+
const result = await validationService.validateFile('/home/other-user/secret.txt');
|
|
165
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should reject existing file with absolute path in /tmp', async () => {
|
|
169
|
+
const result = await validationService.validateFile('/tmp/temporary-file.log');
|
|
170
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should reject non-existing file with absolute path outside workspace', async () => {
|
|
174
|
+
const result = await validationService.validateFile('/var/log/nonexistent.log');
|
|
175
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should validate nested file with absolute path within workspace', async () => {
|
|
179
|
+
const result = await validationService.validateFile('/home/user/workspace/src/components/Button.tsx');
|
|
180
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('validateFile with file:// URIs', () => {
|
|
185
|
+
it('should validate existing file with file:// URI within workspace', async () => {
|
|
186
|
+
const result = await validationService.validateFile('file:///home/user/workspace/src/index.tsx');
|
|
187
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should reject non-existing file with file:// URI within workspace', async () => {
|
|
191
|
+
const result = await validationService.validateFile('file:///home/user/workspace/src/missing.tsx');
|
|
192
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('should reject existing file with file:// URI outside workspace (/etc/passwd)', async () => {
|
|
196
|
+
const result = await validationService.validateFile('file:///etc/passwd');
|
|
197
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should reject existing file with file:// URI outside workspace (/etc/hosts)', async () => {
|
|
201
|
+
const result = await validationService.validateFile('file:///etc/hosts');
|
|
202
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should reject existing file with file:// URI in other user directory', async () => {
|
|
206
|
+
const result = await validationService.validateFile('file:///home/other-user/secret.txt');
|
|
207
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should reject existing file with file:// URI in /tmp', async () => {
|
|
211
|
+
const result = await validationService.validateFile('file:///tmp/temporary-file.log');
|
|
212
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should reject non-existing file with file:// URI outside workspace', async () => {
|
|
216
|
+
const result = await validationService.validateFile('file:///var/log/nonexistent.log');
|
|
217
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should validate file at workspace root with file:// URI', async () => {
|
|
221
|
+
const result = await validationService.validateFile('file:///home/user/workspace/package.json');
|
|
222
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe('validateFile with URI objects', () => {
|
|
227
|
+
it('should validate existing file with URI object within workspace', async () => {
|
|
228
|
+
const uri = new URI('file:///home/user/workspace/src/index.tsx');
|
|
229
|
+
const result = await validationService.validateFile(uri);
|
|
230
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should reject non-existing file with URI object within workspace', async () => {
|
|
234
|
+
const uri = new URI('file:///home/user/workspace/src/missing.tsx');
|
|
235
|
+
const result = await validationService.validateFile(uri);
|
|
236
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should reject existing file with URI object outside workspace', async () => {
|
|
240
|
+
const uri = new URI('file:///etc/passwd');
|
|
241
|
+
const result = await validationService.validateFile(uri);
|
|
242
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should reject another existing file with URI object outside workspace', async () => {
|
|
246
|
+
const uri = new URI('file:///home/other-user/secret.txt');
|
|
247
|
+
const result = await validationService.validateFile(uri);
|
|
248
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('validateFile with no workspace', () => {
|
|
253
|
+
beforeEach(async () => {
|
|
254
|
+
// Override mock to return no workspace roots
|
|
255
|
+
mockWorkspaceService.tryGetRoots = () => [];
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should reject any file when no workspace is open', async () => {
|
|
259
|
+
const result = await validationService.validateFile('src/index.tsx');
|
|
260
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should reject absolute path when no workspace is open', async () => {
|
|
264
|
+
const result = await validationService.validateFile('/home/user/file.txt');
|
|
265
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('should reject file:// URI when no workspace is open', async () => {
|
|
269
|
+
const result = await validationService.validateFile('file:///home/user/file.txt');
|
|
270
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe('validateFile with multiple workspace roots', () => {
|
|
275
|
+
const workspaceRoot2 = new URI('file:///home/user/other-project');
|
|
276
|
+
|
|
277
|
+
beforeEach(async () => {
|
|
278
|
+
// Override mock to return multiple workspace roots
|
|
279
|
+
mockWorkspaceService.tryGetRoots = () => [
|
|
280
|
+
{
|
|
281
|
+
resource: workspaceRoot,
|
|
282
|
+
isDirectory: true
|
|
283
|
+
} as FileStat,
|
|
284
|
+
{
|
|
285
|
+
resource: workspaceRoot2,
|
|
286
|
+
isDirectory: true
|
|
287
|
+
} as FileStat
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
// Add files in the second workspace
|
|
291
|
+
existingFiles.set('file:///home/user/other-project/index.js', true);
|
|
292
|
+
existingFiles.set('file:///home/user/other-project/lib/utils.js', true);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
afterEach(() => {
|
|
296
|
+
// Clean up files added for this test
|
|
297
|
+
existingFiles.delete('file:///home/user/other-project/index.js');
|
|
298
|
+
existingFiles.delete('file:///home/user/other-project/lib/utils.js');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should validate file in first workspace root', async () => {
|
|
302
|
+
const result = await validationService.validateFile('src/index.tsx');
|
|
303
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should validate file in second workspace root with relative path', async () => {
|
|
307
|
+
const result = await validationService.validateFile('index.js');
|
|
308
|
+
expect(result.state).to.equal(FileValidationState.INVALID_SECONDARY);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should validate file in second workspace root with absolute path', async () => {
|
|
312
|
+
const result = await validationService.validateFile('/home/user/other-project/index.js');
|
|
313
|
+
expect(result.state).to.equal(FileValidationState.INVALID_SECONDARY);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('should validate file in second workspace root with file:// URI', async () => {
|
|
317
|
+
const result = await validationService.validateFile('file:///home/user/other-project/lib/utils.js');
|
|
318
|
+
expect(result.state).to.equal(FileValidationState.INVALID_SECONDARY);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should still reject files outside both workspace roots', async () => {
|
|
322
|
+
const result = await validationService.validateFile('/etc/passwd');
|
|
323
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
describe('validateFile error handling', () => {
|
|
328
|
+
it('should return false when FileService.exists throws error', async () => {
|
|
329
|
+
mockFileService.exists = async () => {
|
|
330
|
+
throw new Error('Permission denied');
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const result = await validationService.validateFile('src/index.tsx');
|
|
334
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('should handle Windows-style paths', async () => {
|
|
338
|
+
// Add a Windows path to existing files
|
|
339
|
+
// Note: URI encoding will convert 'c:' to 'c%3A'
|
|
340
|
+
const windowsRoot = new URI('file:///c:/Users/user/project');
|
|
341
|
+
const windowsFile = new URI('file:///c:/Users/user/project/file.txt');
|
|
342
|
+
existingFiles.set(windowsFile.toString(), true);
|
|
343
|
+
|
|
344
|
+
// Override workspace to use Windows path
|
|
345
|
+
mockWorkspaceService.tryGetRoots = () => [{
|
|
346
|
+
resource: windowsRoot,
|
|
347
|
+
isDirectory: true
|
|
348
|
+
} as FileStat];
|
|
349
|
+
|
|
350
|
+
const result = await validationService.validateFile('file:///c:/Users/user/project/file.txt');
|
|
351
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
352
|
+
|
|
353
|
+
// Clean up
|
|
354
|
+
existingFiles.delete(windowsFile.toString());
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should reject Windows system files outside workspace', async () => {
|
|
358
|
+
// Add Windows system file
|
|
359
|
+
const windowsSystemFile = 'file:///c:/Windows/System32/config/sam';
|
|
360
|
+
existingFiles.set(windowsSystemFile, true);
|
|
361
|
+
|
|
362
|
+
// Keep workspace as Linux for this test
|
|
363
|
+
const result = await validationService.validateFile('file:///c:/Windows/System32/config/sam');
|
|
364
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
365
|
+
|
|
366
|
+
// Clean up
|
|
367
|
+
existingFiles.delete(windowsSystemFile);
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
describe('edge cases', () => {
|
|
372
|
+
it('should handle paths with special characters', async () => {
|
|
373
|
+
const result = await validationService.validateFile('file:///home/user/workspace/src/file%20with%20spaces.tsx');
|
|
374
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('should handle paths with normalized separators', async () => {
|
|
378
|
+
const result = await validationService.validateFile('src\\components\\Button.tsx');
|
|
379
|
+
expect(result.state).to.equal(FileValidationState.VALID);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('should reject empty path', async () => {
|
|
383
|
+
const result = await validationService.validateFile('');
|
|
384
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it('should reject parent directory references in relative paths', async () => {
|
|
388
|
+
// Parent directory references are not allowed for security and clarity
|
|
389
|
+
const result = await validationService.validateFile('src/../config.json');
|
|
390
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should reject path traversal attempts with parent directory references', async () => {
|
|
394
|
+
// Path traversal attempts should be rejected
|
|
395
|
+
const result = await validationService.validateFile('../../../../../../etc/passwd');
|
|
396
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('should reject absolute paths with parent directory references', async () => {
|
|
400
|
+
// Even absolute paths with .. should be rejected for consistency
|
|
401
|
+
const result = await validationService.validateFile('/home/user/workspace/src/../config.json');
|
|
402
|
+
expect(result.state).to.equal(FileValidationState.INVALID_NOT_FOUND);
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
18
|
+
import { URI } from '@theia/core';
|
|
19
|
+
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
20
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
|
21
|
+
import { ContextFileValidationService, FileValidationResult, FileValidationState } from '@theia/ai-chat/lib/browser/context-file-validation-service';
|
|
22
|
+
import { WorkspaceFunctionScope } from './workspace-functions';
|
|
23
|
+
|
|
24
|
+
@injectable()
|
|
25
|
+
export class ContextFileValidationServiceImpl implements ContextFileValidationService {
|
|
26
|
+
|
|
27
|
+
@inject(FileService)
|
|
28
|
+
protected readonly fileService: FileService;
|
|
29
|
+
|
|
30
|
+
@inject(WorkspaceFunctionScope)
|
|
31
|
+
protected readonly workspaceScope: WorkspaceFunctionScope;
|
|
32
|
+
|
|
33
|
+
@inject(WorkspaceService)
|
|
34
|
+
protected readonly workspaceService: WorkspaceService;
|
|
35
|
+
|
|
36
|
+
async validateFile(pathOrUri: string | URI): Promise<FileValidationResult> {
|
|
37
|
+
try {
|
|
38
|
+
const resolvedUri = await this.workspaceScope.resolveToUri(pathOrUri);
|
|
39
|
+
|
|
40
|
+
if (!resolvedUri) {
|
|
41
|
+
return {
|
|
42
|
+
state: FileValidationState.INVALID_NOT_FOUND,
|
|
43
|
+
message: 'File does not exist'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const exists = await this.fileService.exists(resolvedUri);
|
|
48
|
+
if (!exists) {
|
|
49
|
+
const secondaryRootUri = await this.findInSecondaryWorkspaceRoots(pathOrUri);
|
|
50
|
+
if (secondaryRootUri) {
|
|
51
|
+
return {
|
|
52
|
+
state: FileValidationState.INVALID_SECONDARY,
|
|
53
|
+
message: 'File is in a secondary workspace root. AI agents can only access files in the first workspace root.'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
state: FileValidationState.INVALID_NOT_FOUND,
|
|
58
|
+
message: 'File does not exist'
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (this.workspaceScope.isInPrimaryWorkspace(resolvedUri)) {
|
|
63
|
+
return {
|
|
64
|
+
state: FileValidationState.VALID
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this.workspaceScope.isInWorkspace(resolvedUri)) {
|
|
69
|
+
return {
|
|
70
|
+
state: FileValidationState.INVALID_SECONDARY,
|
|
71
|
+
message: 'File is in a secondary workspace root. AI agents can only access files in the first workspace root.'
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
state: FileValidationState.INVALID_NOT_FOUND,
|
|
77
|
+
message: 'File does not exist in the workspace'
|
|
78
|
+
};
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return {
|
|
81
|
+
state: FileValidationState.INVALID_NOT_FOUND,
|
|
82
|
+
message: 'File does not exist'
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected async findInSecondaryWorkspaceRoots(pathOrUri: string | URI): Promise<URI | undefined> {
|
|
88
|
+
const roots = this.workspaceService.tryGetRoots();
|
|
89
|
+
if (roots.length <= 1) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (let i = 1; i < roots.length; i++) {
|
|
94
|
+
const root = roots[i];
|
|
95
|
+
let candidateUri: URI;
|
|
96
|
+
|
|
97
|
+
if (pathOrUri instanceof URI) {
|
|
98
|
+
candidateUri = pathOrUri;
|
|
99
|
+
} else if (pathOrUri.includes('://')) {
|
|
100
|
+
try {
|
|
101
|
+
candidateUri = new URI(pathOrUri);
|
|
102
|
+
} catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
candidateUri = root.resource.resolve(pathOrUri);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
if (await this.fileService.exists(candidateUri)) {
|
|
111
|
+
return candidateUri;
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|