@codingame/monaco-vscode-chat-service-override 27.0.0 → 28.0.0
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/index.js +5 -2
- package/package.json +5 -5
- package/vscode/src/vs/sessions/contrib/chat/browser/aiCustomizationWorkspaceService.d.ts +54 -4
- package/vscode/src/vs/sessions/contrib/chat/browser/aiCustomizationWorkspaceService.js +179 -11
- package/vscode/src/vs/sessions/contrib/chat/browser/newSession.js +5 -1
- package/vscode/src/vs/sessions/contrib/chat/browser/sessionsConfigurationService.d.ts +6 -1
- package/vscode/src/vs/sessions/contrib/chat/browser/sessionsConfigurationService.js +25 -10
- package/vscode/src/vs/sessions/contrib/fileTreeView/browser/githubFileSystemProvider.d.ts +67 -0
- package/vscode/src/vs/sessions/contrib/fileTreeView/browser/githubFileSystemProvider.js +263 -0
- package/vscode/src/vs/sessions/contrib/sessions/browser/sessionsManagementService.d.ts +6 -0
- package/vscode/src/vs/sessions/contrib/sessions/browser/sessionsManagementService.js +25 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/accessibility/chatAccessibilityService.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/accessibility/chatResponseAccessibleView.js +15 -15
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityActions.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.js +59 -59
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatAgentRecommendationActions.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.js +12 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatCopyActions.js +13 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatDeveloperActions.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatFileTreeActions.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatForkActions.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatImportExport.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatLanguageModelActions.js +13 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatNewActions.js +11 -11
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatOpenAgentDebugPanelAction.js +5 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatPluginActions.d.ts +7 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatPluginActions.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatPromptNavigationActions.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatQueueActions.js +13 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.js +12 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.js +49 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/codeBlockOperations.js +18 -18
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginEditor.d.ts +58 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginEditor.js +537 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginEditorInput.d.ts +17 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginEditorInput.js +55 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginItems.d.ts +26 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/agentPluginItems.js +9 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginEditor/media/agentPluginEditor.css +32 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginRepositoryService.d.ts +17 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginRepositoryService.js +89 -11
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginsView.d.ts +4 -26
- package/vscode/src/vs/workbench/contrib/chat/browser/agentPluginsView.js +146 -53
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessions.contribution.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsActions.js +56 -54
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsPicker.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsQuickAccess.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjection.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjectionActions.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionProjectionService.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentSessionsExperiments.contribution.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.js +25 -25
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/unifiedQuickAccess.js +17 -17
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/unifiedQuickAccessActions.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationIcons.d.ts +4 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationIcons.js +13 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.d.ts +7 -9
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.js +189 -145
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagement.contribution.js +42 -44
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagement.d.ts +0 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagement.js +3 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagementEditor.d.ts +20 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagementEditor.js +210 -59
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagementEditorInput.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationWorkspaceService.js +14 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/customizationCreatorService.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/mcpListWidget.js +122 -53
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/media/aiCustomizationManagement.css +87 -9
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/pluginListWidget.d.ts +62 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/aiCustomization/pluginListWidget.js +702 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatAttachmentResolveService.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/simpleBrowserEditorOverlay.js +19 -19
- package/vscode/src/vs/workbench/contrib/chat/browser/chat.contribution.js +279 -214
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatCustomizationDiscoveryRenderer.js +21 -21
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugDetailPanel.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEditor.js +12 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEditorInput.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEventDetailRenderer.js +19 -19
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugEventList.js +7 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugFilters.d.ts +12 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugFilters.js +63 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugFlowChartView.js +7 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugFlowGraph.js +18 -18
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugHomeView.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugLogsView.d.ts +4 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugLogsView.js +62 -24
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugMessageContentRenderer.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugModelTurnContentRenderer.js +23 -23
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugOverviewView.js +28 -28
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugToolCallContentRenderer.js +9 -9
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/chatDebugTypes.d.ts +2 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatDebug/media/chatDebug.css +7 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCheckpointTimelineImpl.d.ts +2 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCheckpointTimelineImpl.js +32 -36
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingExplanationModelManager.js +4 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedDocumentEntry.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingServiceImpl.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/media/chatEditorController.css +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/notebook/chatEditingNotebookEditorIntegration.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatManagement/chatManagement.contribution.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/chatManagement/chatManagementEditor.js +13 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/chatManagement/chatManagementEditorInput.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/chatManagement/chatModelsViewModel.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/chatManagement/chatModelsWidget.js +49 -49
- package/vscode/src/vs/workbench/contrib/chat/browser/chatManagement/chatUsageWidget.js +11 -11
- package/vscode/src/vs/workbench/contrib/chat/browser/chatOutputItemRenderer.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.js +30 -30
- package/vscode/src/vs/workbench/contrib/chat/browser/chatRepoInfo.d.ts +9 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatRepoInfo.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetup.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupContributions.js +14 -14
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupController.js +10 -10
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupGrowthSession.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupProviders.js +26 -26
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupRunner.js +13 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSlashCommands.d.ts +3 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSlashCommands.js +103 -60
- package/vscode/src/vs/workbench/contrib/chat/browser/chatStatus/chatStatusDashboard.js +61 -61
- package/vscode/src/vs/workbench/contrib/chat/browser/chatStatus/chatStatusEntry.js +12 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipCatalog.d.ts +66 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipCatalog.js +245 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipEligibilityTracker.d.ts +78 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipEligibilityTracker.js +234 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipService.d.ts +31 -126
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipService.js +229 -524
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipStorageKeys.d.ts +41 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatTipStorageKeys.js +22 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatWindowNotifier.d.ts +4 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/chatWindowNotifier.js +54 -20
- package/vscode/src/vs/workbench/contrib/chat/browser/defaultModelContribution.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/pluginInstallService.d.ts +11 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/pluginInstallService.js +112 -39
- package/vscode/src/vs/workbench/contrib/chat/browser/pluginSources.d.ts +99 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/pluginSources.js +489 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/chatModeActions.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/hookActions.d.ts +6 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/hookActions.js +348 -285
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/hookUtils.d.ts +18 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/hookUtils.js +107 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/promptCodingAgentActionOverlay.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/promptUrlHandler.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/runPromptAction.js +7 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/saveAsPromptFileActions.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/promptSyntax/skillActions.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/languageModelToolsConfirmationService.d.ts +2 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/languageModelToolsConfirmationService.js +55 -38
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.d.ts +20 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.js +148 -60
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/renameTool.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/toolSetsContribution.js +13 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/usagesTool.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewsWelcomeHandler.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatQueuePickerActionItem.d.ts +2 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatQueuePickerActionItem.js +29 -14
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatStatusWidget.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/editor/chatInputCompletions.js +72 -14
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/editor/chatInputEditorContrib.js +5 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/editor/chatInputEditorHover.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/chatQuick.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/editor/chatEditor.js +5 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.js +11 -10
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewTitleControl.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/media/chatViewPane.css +8 -0
- package/vscode/src/vs/workbench/contrib/chat/common/aiCustomizationWorkspaceService.d.ts +1 -0
- package/vscode/src/vs/workbench/contrib/chat/common/aiCustomizationWorkspaceService.js +1 -0
- package/vscode/src/vs/workbench/contrib/chat/common/chatDebugServiceImpl.d.ts +8 -0
- package/vscode/src/vs/workbench/contrib/chat/common/chatDebugServiceImpl.js +20 -0
- package/vscode/src/vs/workbench/contrib/chat/common/chatService/chatServiceImpl.d.ts +1 -1
- package/vscode/src/vs/workbench/contrib/chat/common/chatService/chatServiceImpl.js +72 -23
- package/vscode/src/vs/workbench/contrib/chat/common/chatService/chatServiceTelemetry.d.ts +19 -1
- package/vscode/src/vs/workbench/contrib/chat/common/chatService/chatServiceTelemetry.js +5 -1
- package/vscode/src/vs/workbench/contrib/chat/common/model/chatSessionStore.d.ts +6 -1
- package/vscode/src/vs/workbench/contrib/chat/common/model/chatSessionStore.js +37 -8
- package/vscode/src/vs/workbench/contrib/chat/common/model/objectMutationLog.js +36 -3
- package/vscode/src/vs/workbench/contrib/chat/common/participants/chatSlashCommands.d.ts +4 -4
- package/vscode/src/vs/workbench/contrib/chat/common/participants/chatSlashCommands.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/common/plugins/agentPluginService.d.ts +6 -1
- package/vscode/src/vs/workbench/contrib/chat/common/plugins/agentPluginServiceImpl.d.ts +71 -25
- package/vscode/src/vs/workbench/contrib/chat/common/plugins/agentPluginServiceImpl.js +217 -91
- package/vscode/src/vs/workbench/contrib/chat/common/plugins/pluginMarketplaceService.d.ts +85 -3
- package/vscode/src/vs/workbench/contrib/chat/common/plugins/pluginMarketplaceService.js +257 -63
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/chatPromptFilesContribution.js +17 -17
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/hookClaudeCompat.d.ts +3 -16
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/hookClaudeCompat.js +7 -50
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/hookCompatibility.d.ts +2 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/hookCompatibility.js +32 -3
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/hookCopilotCliCompat.d.ts +1 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/hookCopilotCliCompat.js +3 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/PromptHeaderDefinitionProvider.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptCodeActions.js +7 -6
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptDocumentSemanticTokensProvider.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderAutocompletion.d.ts +26 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHeaderAutocompletion.js +287 -88
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHovers.d.ts +10 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptHovers.js +75 -20
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.d.ts +121 -0
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.js +1422 -0
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/promptFileContributions.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.d.ts +5 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.js +81 -41
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.d.ts +3 -1
- package/vscode/src/vs/workbench/contrib/chat/common/promptSyntax/utils/promptFilesLocator.js +8 -6
- package/vscode/src/vs/workbench/contrib/chat/common/voiceChatService.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/common/widget/chatResponseResourceFileSystemProvider.d.ts +14 -2
- package/vscode/src/vs/workbench/contrib/chat/common/widget/chatResponseResourceFileSystemProvider.js +54 -5
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.js +6 -5
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.d.ts +4 -4
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.js +38 -22
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatDefaultModel.js +2 -2
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.js +8 -8
- package/vscode/src/vs/workbench/contrib/mcp/browser/mcpPromptArgumentPick.js +14 -14
- package/vscode/src/vs/workbench/contrib/notebook/browser/contrib/chat/notebookChatUtils.js +1 -1
- package/vscode/src/vs/workbench/contrib/notebook/browser/controller/chat/cellChatActions.js +10 -10
- package/vscode/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.js +5 -5
- package/vscode/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatContext.js +1 -1
- package/vscode/src/vs/workbench/contrib/remoteCodingAgents/browser/remoteCodingAgents.contribution.js +7 -7
- package/vscode/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatAccessibilityHelp.js +16 -16
- package/vscode/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.js +20 -20
- package/vscode/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.js +1 -1
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/runInTerminalHelpers.js +6 -6
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/terminal.chatAgentTools.contribution.js +3 -3
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/awaitTerminalTool.js +3 -3
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/autoApprove/npmScriptAutoApprover.js +1 -1
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineAutoApproveAnalyzer.js +12 -12
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineFileWriteAnalyzer.js +2 -2
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/getTerminalLastCommandTool.js +3 -3
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/getTerminalOutputTool.js +3 -3
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/getTerminalSelectionTool.js +3 -3
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/killTerminalTool.js +3 -3
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/monitoring/outputMonitor.d.ts +8 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/monitoring/outputMonitor.js +36 -18
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalConfirmationTool.js +2 -2
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalTool.d.ts +6 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalTool.js +27 -13
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/sandboxOutputAnalyzer.js +1 -1
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/task/createAndRunTaskTool.js +14 -14
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/task/getTaskOutputTool.js +7 -7
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/task/runTaskTool.js +14 -14
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/task/taskHelpers.js +1 -1
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalSandboxService.d.ts +1 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalSandboxService.js +8 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatVariables.d.ts +0 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatVariables.js +0 -67
|
@@ -0,0 +1,1422 @@
|
|
|
1
|
+
|
|
2
|
+
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
|
|
3
|
+
import { splitGlobAware, parse, isEmptyPattern } from '@codingame/monaco-vscode-api/vscode/vs/base/common/glob';
|
|
4
|
+
import { Iterable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/iterator';
|
|
5
|
+
import { Range } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/range';
|
|
6
|
+
import { IModelService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/services/model.service';
|
|
7
|
+
import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
|
|
8
|
+
import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
|
|
9
|
+
import { MarkerSeverity } from '@codingame/monaco-vscode-api/vscode/vs/platform/markers/common/markers';
|
|
10
|
+
import { IMarkerService } from '@codingame/monaco-vscode-api/vscode/vs/platform/markers/common/markers.service';
|
|
11
|
+
import { ChatMode } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatModes';
|
|
12
|
+
import { IChatModeService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatModes.service';
|
|
13
|
+
import { ChatModeKind } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/constants';
|
|
14
|
+
import { ILanguageModelChatMetadata } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModels';
|
|
15
|
+
import { ILanguageModelsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModels.service';
|
|
16
|
+
import { SpecedToolAliases } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/tools/languageModelToolsService';
|
|
17
|
+
import { ILanguageModelToolsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/tools/languageModelToolsService.service';
|
|
18
|
+
import { PromptsType, Target, getPromptsTypeForLanguageId } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/promptTypes';
|
|
19
|
+
import { PromptHeaderAttributes, parseCommaSeparatedList } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser';
|
|
20
|
+
import { Disposable, DisposableStore, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
|
|
21
|
+
import { Delayer } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
|
|
22
|
+
import { ResourceMap } from '@codingame/monaco-vscode-api/vscode/vs/base/common/map';
|
|
23
|
+
import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
|
|
24
|
+
import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service';
|
|
25
|
+
import { IPromptsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.service';
|
|
26
|
+
import { ILabelService } from '@codingame/monaco-vscode-api/vscode/vs/platform/label/common/label.service';
|
|
27
|
+
import { LEGACY_MODE_FILE_EXTENSION, AGENTS_SOURCE_FOLDER, CLAUDE_AGENTS_SOURCE_FOLDER, isInClaudeRulesFolder } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/config/promptFileLocations';
|
|
28
|
+
import { Lazy } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lazy';
|
|
29
|
+
import { CancellationToken } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
|
|
30
|
+
import { dirname } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
|
|
31
|
+
import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
|
|
32
|
+
import { HOOKS_BY_TARGET } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/hookTypes';
|
|
33
|
+
import { PromptsConfig } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/config/config';
|
|
34
|
+
import { GithubPromptHeaderAttributes } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptFileAttributes';
|
|
35
|
+
|
|
36
|
+
const MARKERS_OWNER_ID = "prompts-diagnostics-provider";
|
|
37
|
+
let PromptValidator = class PromptValidator {
|
|
38
|
+
constructor(
|
|
39
|
+
languageModelsService,
|
|
40
|
+
languageModelToolsService,
|
|
41
|
+
chatModeService,
|
|
42
|
+
fileService,
|
|
43
|
+
labelService,
|
|
44
|
+
promptsService,
|
|
45
|
+
configurationService
|
|
46
|
+
) {
|
|
47
|
+
this.languageModelsService = languageModelsService;
|
|
48
|
+
this.languageModelToolsService = languageModelToolsService;
|
|
49
|
+
this.chatModeService = chatModeService;
|
|
50
|
+
this.fileService = fileService;
|
|
51
|
+
this.labelService = labelService;
|
|
52
|
+
this.promptsService = promptsService;
|
|
53
|
+
this.configurationService = configurationService;
|
|
54
|
+
}
|
|
55
|
+
async validate(promptAST, promptType, report) {
|
|
56
|
+
promptAST.header?.errors.forEach(
|
|
57
|
+
error => report(toMarker(error.message, error.range, MarkerSeverity.Error))
|
|
58
|
+
);
|
|
59
|
+
const target = getTarget(promptType, promptAST.header ?? promptAST.uri);
|
|
60
|
+
await this.validateHeader(promptAST, promptType, target, report);
|
|
61
|
+
await this.validateBody(promptAST, target, report);
|
|
62
|
+
await this.validateFileName(promptAST, promptType, report);
|
|
63
|
+
await this.validateSkillFolderName(promptAST, promptType, report);
|
|
64
|
+
}
|
|
65
|
+
async validateFileName(promptAST, promptType, report) {
|
|
66
|
+
if (promptType === PromptsType.agent && promptAST.uri.path.endsWith(LEGACY_MODE_FILE_EXTENSION)) {
|
|
67
|
+
const location = this.promptsService.getAgentFileURIFromModeFile(promptAST.uri);
|
|
68
|
+
if (location && (await this.fileService.canCreateFile(location))) {
|
|
69
|
+
report(toMarker(( localize(
|
|
70
|
+
7187,
|
|
71
|
+
"Chat modes have been renamed to agents. Please move this file to {0}",
|
|
72
|
+
(location.toString())
|
|
73
|
+
)), ( new Range(1, 1, 1, 4)), MarkerSeverity.Warning));
|
|
74
|
+
} else {
|
|
75
|
+
report(toMarker(( localize(
|
|
76
|
+
7188,
|
|
77
|
+
"Chat modes have been renamed to agents. Please move the file to {0}",
|
|
78
|
+
AGENTS_SOURCE_FOLDER
|
|
79
|
+
)), ( new Range(1, 1, 1, 4)), MarkerSeverity.Warning));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async validateSkillFolderName(promptAST, promptType, report) {
|
|
84
|
+
if (promptType !== PromptsType.skill) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const nameAttribute = promptAST.header?.attributes.find(attr => attr.key === PromptHeaderAttributes.name);
|
|
88
|
+
if (!nameAttribute || nameAttribute.value.type !== "scalar") {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const skillName = nameAttribute.value.value.trim();
|
|
92
|
+
if (!skillName) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const pathParts = promptAST.uri.path.split("/");
|
|
96
|
+
const skillIndex = pathParts.findIndex(part => part === "SKILL.md");
|
|
97
|
+
if (skillIndex > 0) {
|
|
98
|
+
const folderName = pathParts[skillIndex - 1];
|
|
99
|
+
if (folderName && skillName !== folderName) {
|
|
100
|
+
report(toMarker(( localize(
|
|
101
|
+
7189,
|
|
102
|
+
"The skill name '{0}' should match the folder name '{1}'.",
|
|
103
|
+
skillName,
|
|
104
|
+
folderName
|
|
105
|
+
)), nameAttribute.value.range, MarkerSeverity.Warning));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async validateBody(promptAST, target, report) {
|
|
110
|
+
const body = promptAST.body;
|
|
111
|
+
if (!body) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const fileReferenceChecks = [];
|
|
115
|
+
for (const ref of body.fileReferences) {
|
|
116
|
+
const resolved = body.resolveFilePath(ref.content);
|
|
117
|
+
if (!resolved) {
|
|
118
|
+
report(toMarker(( localize(7190, "Invalid file reference '{0}'.", ref.content)), ref.range, MarkerSeverity.Warning));
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (promptAST.uri.scheme === resolved.scheme) {
|
|
122
|
+
fileReferenceChecks.push((async () => {
|
|
123
|
+
try {
|
|
124
|
+
const exists = await this.fileService.exists(resolved);
|
|
125
|
+
if (exists) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
} catch {}
|
|
129
|
+
const loc = this.labelService.getUriLabel(resolved);
|
|
130
|
+
report(toMarker(( localize(7191, "File '{0}' not found at '{1}'.", ref.content, loc)), ref.range, MarkerSeverity.Warning));
|
|
131
|
+
})());
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (body.variableReferences.length && isVSCodeOrDefaultTarget(target)) {
|
|
135
|
+
const headerTools = promptAST.header?.tools;
|
|
136
|
+
const headerToolsMap = headerTools ? this.languageModelToolsService.toToolAndToolSetEnablementMap(headerTools, undefined) : undefined;
|
|
137
|
+
const available = ( new Set(this.languageModelToolsService.getFullReferenceNames()));
|
|
138
|
+
const deprecatedNames = this.languageModelToolsService.getDeprecatedFullReferenceNames();
|
|
139
|
+
for (const variable of body.variableReferences) {
|
|
140
|
+
if (!( available.has(variable.name))) {
|
|
141
|
+
if (( deprecatedNames.has(variable.name))) {
|
|
142
|
+
const currentNames = deprecatedNames.get(variable.name);
|
|
143
|
+
if (currentNames && currentNames.size > 0) {
|
|
144
|
+
if (currentNames.size === 1) {
|
|
145
|
+
const newName = Array.from(currentNames)[0];
|
|
146
|
+
report(toMarker(( localize(
|
|
147
|
+
7192,
|
|
148
|
+
"Tool or toolset '{0}' has been renamed, use '{1}' instead.",
|
|
149
|
+
variable.name,
|
|
150
|
+
newName
|
|
151
|
+
)), variable.range, MarkerSeverity.Info));
|
|
152
|
+
} else {
|
|
153
|
+
const newNames = Array.from(currentNames).sort((a, b) => a.localeCompare(b)).join(", ");
|
|
154
|
+
report(toMarker(( localize(
|
|
155
|
+
7193,
|
|
156
|
+
"Tool or toolset '{0}' has been renamed, use the following tools instead: {1}",
|
|
157
|
+
variable.name,
|
|
158
|
+
newNames
|
|
159
|
+
)), variable.range, MarkerSeverity.Info));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
report(toMarker(( localize(7194, "Unknown tool or toolset '{0}'.", variable.name)), variable.range, MarkerSeverity.Warning));
|
|
164
|
+
}
|
|
165
|
+
} else if (headerToolsMap) {
|
|
166
|
+
const tool = this.languageModelToolsService.getToolByFullReferenceName(variable.name);
|
|
167
|
+
if (tool && headerToolsMap.get(tool) === false) {
|
|
168
|
+
report(toMarker(( localize(
|
|
169
|
+
7195,
|
|
170
|
+
"Tool or toolset '{0}' also needs to be enabled in the header.",
|
|
171
|
+
variable.name
|
|
172
|
+
)), variable.range, MarkerSeverity.Warning));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
await Promise.all(fileReferenceChecks);
|
|
178
|
+
}
|
|
179
|
+
async validateHeader(promptAST, promptType, target, report) {
|
|
180
|
+
const header = promptAST.header;
|
|
181
|
+
if (!header) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const attributes = header.attributes;
|
|
185
|
+
this.checkForInvalidArguments(attributes, promptType, target, report);
|
|
186
|
+
this.validateName(attributes, report);
|
|
187
|
+
this.validateDescription(attributes, report);
|
|
188
|
+
this.validateArgumentHint(attributes, report);
|
|
189
|
+
switch (promptType) {
|
|
190
|
+
case PromptsType.prompt:
|
|
191
|
+
{
|
|
192
|
+
const agent = this.validateAgent(attributes, report);
|
|
193
|
+
this.validateTools(attributes, agent?.kind ?? ChatModeKind.Agent, target, report);
|
|
194
|
+
this.validateModel(attributes, agent?.kind ?? ChatModeKind.Agent, report);
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case PromptsType.instructions:
|
|
198
|
+
if (target === Target.Claude) {
|
|
199
|
+
this.validatePaths(attributes, report);
|
|
200
|
+
} else {
|
|
201
|
+
this.validateApplyTo(attributes, report);
|
|
202
|
+
}
|
|
203
|
+
this.validateExcludeAgent(attributes, report);
|
|
204
|
+
break;
|
|
205
|
+
case PromptsType.agent:
|
|
206
|
+
{
|
|
207
|
+
this.validateTarget(attributes, report);
|
|
208
|
+
this.validateInfer(attributes, report);
|
|
209
|
+
this.validateUserInvocable(attributes, report);
|
|
210
|
+
this.validateUserInvokable(attributes, report);
|
|
211
|
+
this.validateDisableModelInvocation(attributes, report);
|
|
212
|
+
this.validateTools(attributes, ChatModeKind.Agent, target, report);
|
|
213
|
+
if (this.configurationService.getValue(PromptsConfig.USE_CUSTOM_AGENT_HOOKS)) {
|
|
214
|
+
this.validateHooks(attributes, target, report);
|
|
215
|
+
}
|
|
216
|
+
if (isVSCodeOrDefaultTarget(target)) {
|
|
217
|
+
this.validateModel(attributes, ChatModeKind.Agent, report);
|
|
218
|
+
this.validateHandoffs(attributes, report);
|
|
219
|
+
await this.validateAgentsAttribute(attributes, header, report);
|
|
220
|
+
this.validateGithubPermissions(attributes, report);
|
|
221
|
+
} else if (target === Target.Claude) {
|
|
222
|
+
this.validateClaudeAttributes(attributes, report);
|
|
223
|
+
} else if (target === Target.GitHubCopilot) {
|
|
224
|
+
this.validateGithubPermissions(attributes, report);
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case PromptsType.skill:
|
|
229
|
+
this.validateUserInvocable(attributes, report);
|
|
230
|
+
this.validateUserInvokable(attributes, report);
|
|
231
|
+
this.validateDisableModelInvocation(attributes, report);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
checkForInvalidArguments(attributes, promptType, target, report) {
|
|
236
|
+
let validAttributeNames = getValidAttributeNames(promptType, true, target);
|
|
237
|
+
if (!this.configurationService.getValue(PromptsConfig.USE_CUSTOM_AGENT_HOOKS)) {
|
|
238
|
+
validAttributeNames = validAttributeNames.filter(name => name !== PromptHeaderAttributes.hooks);
|
|
239
|
+
}
|
|
240
|
+
const useCustomAgentHooks = this.configurationService.getValue(PromptsConfig.USE_CUSTOM_AGENT_HOOKS);
|
|
241
|
+
const validGithubCopilotAttributeNames = ( new Lazy(() => ( new Set(getValidAttributeNames(promptType, false, Target.GitHubCopilot)))));
|
|
242
|
+
for (const attribute of attributes) {
|
|
243
|
+
if (!validAttributeNames.includes(attribute.key)) {
|
|
244
|
+
const supportedNames = ( new Lazy(() => {
|
|
245
|
+
let names = getValidAttributeNames(promptType, false, target);
|
|
246
|
+
if (!useCustomAgentHooks) {
|
|
247
|
+
names = names.filter(name => name !== PromptHeaderAttributes.hooks);
|
|
248
|
+
}
|
|
249
|
+
return names.sort().join(", ");
|
|
250
|
+
}));
|
|
251
|
+
switch (promptType) {
|
|
252
|
+
case PromptsType.prompt:
|
|
253
|
+
report(toMarker(( localize(
|
|
254
|
+
7196,
|
|
255
|
+
"Attribute '{0}' is not supported in prompt files. Supported: {1}.",
|
|
256
|
+
attribute.key,
|
|
257
|
+
supportedNames.value
|
|
258
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
259
|
+
break;
|
|
260
|
+
case PromptsType.agent:
|
|
261
|
+
if (target === Target.GitHubCopilot) {
|
|
262
|
+
report(toMarker(( localize(
|
|
263
|
+
7197,
|
|
264
|
+
"Attribute '{0}' is not supported in custom GitHub Copilot agent files. Supported: {1}.",
|
|
265
|
+
attribute.key,
|
|
266
|
+
supportedNames.value
|
|
267
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
268
|
+
} else if (target === Target.Claude)
|
|
269
|
+
; else {
|
|
270
|
+
if (( validGithubCopilotAttributeNames.value.has(attribute.key))) {
|
|
271
|
+
report(toMarker(( localize(
|
|
272
|
+
7198,
|
|
273
|
+
"Attribute '{0}' is ignored when running locally in VS Code.",
|
|
274
|
+
attribute.key
|
|
275
|
+
)), attribute.range, MarkerSeverity.Info));
|
|
276
|
+
} else {
|
|
277
|
+
report(toMarker(( localize(
|
|
278
|
+
7199,
|
|
279
|
+
"Attribute '{0}' is not supported in VS Code agent files. Supported: {1}.",
|
|
280
|
+
attribute.key,
|
|
281
|
+
supportedNames.value
|
|
282
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
case PromptsType.instructions:
|
|
287
|
+
if (target === Target.Claude) {
|
|
288
|
+
report(toMarker(( localize(
|
|
289
|
+
7200,
|
|
290
|
+
"Attribute '{0}' is not supported in rules files. Supported: {1}.",
|
|
291
|
+
attribute.key,
|
|
292
|
+
supportedNames.value
|
|
293
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
294
|
+
} else {
|
|
295
|
+
report(toMarker(( localize(
|
|
296
|
+
7201,
|
|
297
|
+
"Attribute '{0}' is not supported in instructions files. Supported: {1}.",
|
|
298
|
+
attribute.key,
|
|
299
|
+
supportedNames.value
|
|
300
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case PromptsType.skill:
|
|
304
|
+
report(toMarker(( localize(
|
|
305
|
+
7202,
|
|
306
|
+
"Attribute '{0}' is not supported in skill files. Supported: {1}.",
|
|
307
|
+
attribute.key,
|
|
308
|
+
supportedNames.value
|
|
309
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
validateName(attributes, report) {
|
|
316
|
+
const nameAttribute = attributes.find(attr => attr.key === PromptHeaderAttributes.name);
|
|
317
|
+
if (!nameAttribute) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (nameAttribute.value.type !== "scalar") {
|
|
321
|
+
report(toMarker(( localize(7203, "The 'name' attribute must be a string.")), nameAttribute.range, MarkerSeverity.Error));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (nameAttribute.value.value.trim().length === 0) {
|
|
325
|
+
report(toMarker(( localize(7204, "The 'name' attribute must not be empty.")), nameAttribute.value.range, MarkerSeverity.Error));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
validateDescription(attributes, report) {
|
|
330
|
+
const descriptionAttribute = attributes.find(attr => attr.key === PromptHeaderAttributes.description);
|
|
331
|
+
if (!descriptionAttribute) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (descriptionAttribute.value.type !== "scalar") {
|
|
335
|
+
report(toMarker(( localize(7205, "The 'description' attribute must be a string.")), descriptionAttribute.range, MarkerSeverity.Error));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (descriptionAttribute.value.value.trim().length === 0) {
|
|
339
|
+
report(toMarker(( localize(7206, "The 'description' attribute should not be empty.")), descriptionAttribute.value.range, MarkerSeverity.Error));
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
validateArgumentHint(attributes, report) {
|
|
344
|
+
const argumentHintAttribute = attributes.find(attr => attr.key === PromptHeaderAttributes.argumentHint);
|
|
345
|
+
if (!argumentHintAttribute) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (argumentHintAttribute.value.type !== "scalar") {
|
|
349
|
+
report(toMarker(( localize(7207, "The 'argument-hint' attribute must be a string.")), argumentHintAttribute.range, MarkerSeverity.Error));
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (argumentHintAttribute.value.value.trim().length === 0) {
|
|
353
|
+
report(toMarker(( localize(7208, "The 'argument-hint' attribute should not be empty.")), argumentHintAttribute.value.range, MarkerSeverity.Error));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
validateModel(attributes, agentKind, report) {
|
|
358
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.model);
|
|
359
|
+
if (!attribute) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (attribute.value.type !== "scalar" && attribute.value.type !== "sequence") {
|
|
363
|
+
report(toMarker(( localize(7209, "The 'model' attribute must be a string or an array of strings.")), attribute.value.range, MarkerSeverity.Error));
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const modelNames = [];
|
|
367
|
+
if (attribute.value.type === "scalar") {
|
|
368
|
+
const modelName = attribute.value.value.trim();
|
|
369
|
+
if (modelName.length === 0) {
|
|
370
|
+
report(toMarker(( localize(7210, "The 'model' attribute must be a non-empty string.")), attribute.value.range, MarkerSeverity.Error));
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
modelNames.push([modelName, attribute.value.range]);
|
|
374
|
+
} else if (attribute.value.type === "sequence") {
|
|
375
|
+
if (attribute.value.items.length === 0) {
|
|
376
|
+
report(toMarker(( localize(7211, "The 'model' array must not be empty.")), attribute.value.range, MarkerSeverity.Error));
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
for (const item of attribute.value.items) {
|
|
380
|
+
if (item.type !== "scalar") {
|
|
381
|
+
report(toMarker(( localize(7212, "The 'model' array must contain only strings.")), item.range, MarkerSeverity.Error));
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const modelName = item.value.trim();
|
|
385
|
+
if (modelName.length === 0) {
|
|
386
|
+
report(toMarker(( localize(7213, "Model names in the array must be non-empty strings.")), item.range, MarkerSeverity.Error));
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
modelNames.push([modelName, item.range]);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const languageModels = this.languageModelsService.getLanguageModelIds();
|
|
393
|
+
if (languageModels.length === 0) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
for (const [modelName, range] of modelNames) {
|
|
397
|
+
const modelMetadata = this.findModelByName(modelName);
|
|
398
|
+
if (!modelMetadata) {
|
|
399
|
+
report(toMarker(( localize(7214, "Unknown model '{0}'.", modelName)), range, MarkerSeverity.Warning));
|
|
400
|
+
} else if (agentKind === ChatModeKind.Agent && !ILanguageModelChatMetadata.suitableForAgentMode(modelMetadata)) {
|
|
401
|
+
report(toMarker(( localize(7215, "Model '{0}' is not suited for agent mode.", modelName)), range, MarkerSeverity.Warning));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
validateClaudeAttributes(attributes, report) {
|
|
406
|
+
for (const claudeAttributeName in claudeAgentAttributes) {
|
|
407
|
+
const claudeAttribute = claudeAgentAttributes[claudeAttributeName];
|
|
408
|
+
const enumValues = claudeAttribute.enums;
|
|
409
|
+
if (enumValues) {
|
|
410
|
+
const attribute = attributes.find(attr => attr.key === claudeAttributeName);
|
|
411
|
+
if (!attribute) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (attribute.value.type !== "scalar") {
|
|
415
|
+
report(toMarker(( localize(7216, "The '{0}' attribute must be a string.", claudeAttributeName)), attribute.value.range, MarkerSeverity.Error));
|
|
416
|
+
continue;
|
|
417
|
+
} else {
|
|
418
|
+
const modelName = attribute.value.value.trim();
|
|
419
|
+
if (enumValues.every(model => model.name !== modelName)) {
|
|
420
|
+
const validValues = ( enumValues.map(model => model.name)).join(", ");
|
|
421
|
+
report(toMarker(( localize(7217, "Unknown value '{0}', valid: {1}.", modelName, validValues)), attribute.value.range, MarkerSeverity.Warning));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
findModelByName(modelName) {
|
|
428
|
+
const metadataAndId = this.languageModelsService.lookupLanguageModelByQualifiedName(modelName);
|
|
429
|
+
if (metadataAndId && metadataAndId.metadata.isUserSelectable !== false) {
|
|
430
|
+
return metadataAndId.metadata;
|
|
431
|
+
}
|
|
432
|
+
return undefined;
|
|
433
|
+
}
|
|
434
|
+
validateAgent(attributes, report) {
|
|
435
|
+
const agentAttribute = attributes.find(attr => attr.key === PromptHeaderAttributes.agent);
|
|
436
|
+
const modeAttribute = attributes.find(attr => attr.key === PromptHeaderAttributes.mode);
|
|
437
|
+
if (modeAttribute) {
|
|
438
|
+
if (agentAttribute) {
|
|
439
|
+
report(toMarker(( localize(
|
|
440
|
+
7218,
|
|
441
|
+
"The 'mode' attribute has been deprecated. The 'agent' attribute is used instead."
|
|
442
|
+
)), modeAttribute.range, MarkerSeverity.Warning));
|
|
443
|
+
} else {
|
|
444
|
+
report(toMarker(( localize(
|
|
445
|
+
7219,
|
|
446
|
+
"The 'mode' attribute has been deprecated. Please rename it to 'agent'."
|
|
447
|
+
)), modeAttribute.range, MarkerSeverity.Error));
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.agent) ?? modeAttribute;
|
|
451
|
+
if (!attribute) {
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
if (attribute.value.type !== "scalar") {
|
|
455
|
+
report(toMarker(( localize(7220, "The '{0}' attribute must be a string.", attribute.key)), attribute.value.range, MarkerSeverity.Error));
|
|
456
|
+
return undefined;
|
|
457
|
+
}
|
|
458
|
+
const agentValue = attribute.value.value;
|
|
459
|
+
if (agentValue.trim().length === 0) {
|
|
460
|
+
report(toMarker(( localize(7221, "The '{0}' attribute must be a non-empty string.", attribute.key)), attribute.value.range, MarkerSeverity.Error));
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
return this.validateAgentValue(attribute.value, report);
|
|
464
|
+
}
|
|
465
|
+
validateAgentValue(value, report) {
|
|
466
|
+
const agents = this.chatModeService.getModes();
|
|
467
|
+
const availableAgents = [];
|
|
468
|
+
for (const agent of Iterable.concat(agents.builtin, agents.custom)) {
|
|
469
|
+
if (agent.name.get() === value.value) {
|
|
470
|
+
return agent;
|
|
471
|
+
}
|
|
472
|
+
availableAgents.push(agent.name.get());
|
|
473
|
+
}
|
|
474
|
+
const errorMessage = ( localize(
|
|
475
|
+
7222,
|
|
476
|
+
"Unknown agent '{0}'. Available agents: {1}.",
|
|
477
|
+
value.value,
|
|
478
|
+
availableAgents.join(", ")
|
|
479
|
+
));
|
|
480
|
+
report(toMarker(errorMessage, value.range, MarkerSeverity.Warning));
|
|
481
|
+
return undefined;
|
|
482
|
+
}
|
|
483
|
+
validateTools(attributes, agentKind, target, report) {
|
|
484
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.tools);
|
|
485
|
+
if (!attribute) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (agentKind !== ChatModeKind.Agent) {
|
|
489
|
+
report(toMarker(( localize(
|
|
490
|
+
7223,
|
|
491
|
+
"The 'tools' attribute is only supported when using agents. Attribute will be ignored."
|
|
492
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
493
|
+
}
|
|
494
|
+
let value = attribute.value;
|
|
495
|
+
if (value.type === "scalar") {
|
|
496
|
+
value = parseCommaSeparatedList(value);
|
|
497
|
+
}
|
|
498
|
+
if (value.type !== "sequence") {
|
|
499
|
+
report(toMarker(( localize(
|
|
500
|
+
7224,
|
|
501
|
+
"The 'tools' attribute must be an array or a comma separated string."
|
|
502
|
+
)), attribute.value.range, MarkerSeverity.Error));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
if (target === Target.GitHubCopilot || target === Target.Claude)
|
|
506
|
+
; else {
|
|
507
|
+
this.validateVSCodeTools(value, report);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
validateVSCodeTools(valueItem, report) {
|
|
511
|
+
if (valueItem.items.length > 0) {
|
|
512
|
+
const available = ( new Set(this.languageModelToolsService.getFullReferenceNames()));
|
|
513
|
+
const deprecatedNames = this.languageModelToolsService.getDeprecatedFullReferenceNames();
|
|
514
|
+
for (const item of valueItem.items) {
|
|
515
|
+
if (item.type !== "scalar") {
|
|
516
|
+
report(toMarker(( localize(7225, "Each tool name in the 'tools' attribute must be a string.")), item.range, MarkerSeverity.Error));
|
|
517
|
+
} else if (item.value) {
|
|
518
|
+
if (!( available.has(item.value))) {
|
|
519
|
+
const currentNames = deprecatedNames.get(item.value);
|
|
520
|
+
if (currentNames) {
|
|
521
|
+
if (currentNames?.size === 1) {
|
|
522
|
+
const newName = Array.from(currentNames)[0];
|
|
523
|
+
report(toMarker(( localize(
|
|
524
|
+
7226,
|
|
525
|
+
"Tool or toolset '{0}' has been renamed, use '{1}' instead.",
|
|
526
|
+
item.value,
|
|
527
|
+
newName
|
|
528
|
+
)), item.range, MarkerSeverity.Info));
|
|
529
|
+
} else {
|
|
530
|
+
const newNames = Array.from(currentNames).sort((a, b) => a.localeCompare(b)).join(", ");
|
|
531
|
+
report(toMarker(( localize(
|
|
532
|
+
7227,
|
|
533
|
+
"Tool or toolset '{0}' has been renamed, use the following tools instead: {1}",
|
|
534
|
+
item.value,
|
|
535
|
+
newNames
|
|
536
|
+
)), item.range, MarkerSeverity.Info));
|
|
537
|
+
}
|
|
538
|
+
} else {
|
|
539
|
+
report(toMarker(( localize(7228, "Unknown tool '{0}'.", item.value)), item.range, MarkerSeverity.Warning));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
validateApplyTo(attributes, report) {
|
|
547
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.applyTo);
|
|
548
|
+
if (!attribute) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (attribute.value.type !== "scalar") {
|
|
552
|
+
report(toMarker(( localize(7229, "The 'applyTo' attribute must be a string.")), attribute.value.range, MarkerSeverity.Error));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const pattern = attribute.value.value;
|
|
556
|
+
try {
|
|
557
|
+
const patterns = splitGlobAware(pattern, ",");
|
|
558
|
+
if (patterns.length === 0) {
|
|
559
|
+
report(toMarker(( localize(7230, "The 'applyTo' attribute must be a valid glob pattern.")), attribute.value.range, MarkerSeverity.Error));
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
for (const pattern of patterns) {
|
|
563
|
+
const globPattern = parse(pattern);
|
|
564
|
+
if (isEmptyPattern(globPattern)) {
|
|
565
|
+
report(toMarker(( localize(7230, "The 'applyTo' attribute must be a valid glob pattern.")), attribute.value.range, MarkerSeverity.Error));
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
} catch (_error) {
|
|
570
|
+
report(toMarker(( localize(7230, "The 'applyTo' attribute must be a valid glob pattern.")), attribute.value.range, MarkerSeverity.Error));
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
validatePaths(attributes, report) {
|
|
574
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.paths);
|
|
575
|
+
if (!attribute) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (attribute.value.type !== "sequence") {
|
|
579
|
+
report(toMarker(( localize(7231, "The 'paths' attribute must be an array of glob patterns.")), attribute.value.range, MarkerSeverity.Error));
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
for (const item of attribute.value.items) {
|
|
583
|
+
if (item.type !== "scalar") {
|
|
584
|
+
report(toMarker(( localize(7232, "Each entry in the 'paths' attribute must be a string.")), item.range, MarkerSeverity.Error));
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
const pattern = item.value.trim();
|
|
588
|
+
if (pattern.length === 0) {
|
|
589
|
+
report(toMarker(( localize(7233, "Path entries must be non-empty glob patterns.")), item.range, MarkerSeverity.Error));
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
try {
|
|
593
|
+
const globPattern = parse(pattern);
|
|
594
|
+
if (isEmptyPattern(globPattern)) {
|
|
595
|
+
report(toMarker(( localize(7234, "'{0}' is not a valid glob pattern.", pattern)), item.range, MarkerSeverity.Error));
|
|
596
|
+
}
|
|
597
|
+
} catch (_error) {
|
|
598
|
+
report(toMarker(( localize(7234, "'{0}' is not a valid glob pattern.", pattern)), item.range, MarkerSeverity.Error));
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
validateExcludeAgent(attributes, report) {
|
|
603
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.excludeAgent);
|
|
604
|
+
if (!attribute) {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (attribute.value.type !== "sequence" && attribute.value.type !== "scalar") {
|
|
608
|
+
report(toMarker(( localize(7235, "The 'excludeAgent' attribute must be an string or array.")), attribute.value.range, MarkerSeverity.Error));
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
validateHooks(attributes, target, report) {
|
|
613
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.hooks);
|
|
614
|
+
if (!attribute) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (attribute.value.type !== "map") {
|
|
618
|
+
report(toMarker(( localize(
|
|
619
|
+
7236,
|
|
620
|
+
"The 'hooks' attribute must be a map of hook event types to command arrays."
|
|
621
|
+
)), attribute.value.range, MarkerSeverity.Error));
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const validHookNames = ( new Set(( Object.keys(HOOKS_BY_TARGET[target] ?? HOOKS_BY_TARGET[Target.Undefined]))));
|
|
625
|
+
for (const prop of attribute.value.properties) {
|
|
626
|
+
if (!( validHookNames.has(prop.key.value))) {
|
|
627
|
+
report(toMarker(( localize(
|
|
628
|
+
7237,
|
|
629
|
+
"Unknown hook event type '{0}'. Supported: {1}.",
|
|
630
|
+
prop.key.value,
|
|
631
|
+
Array.from(validHookNames).join(", ")
|
|
632
|
+
)), prop.key.range, MarkerSeverity.Warning));
|
|
633
|
+
}
|
|
634
|
+
if (prop.value.type !== "sequence") {
|
|
635
|
+
report(toMarker(( localize(
|
|
636
|
+
7238,
|
|
637
|
+
"Hook event '{0}' must have an array of command objects as its value.",
|
|
638
|
+
prop.key.value
|
|
639
|
+
)), prop.value.range, MarkerSeverity.Error));
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
for (const item of prop.value.items) {
|
|
643
|
+
this.validateHookCommand(item, target, report);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
validateHookCommand(item, target, report) {
|
|
648
|
+
if (item.type !== "map") {
|
|
649
|
+
report(toMarker(( localize(7239, "Each hook command must be an object.")), item.range, MarkerSeverity.Error));
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const hooksProperty = item.properties.find(p => p.key.value === "hooks");
|
|
653
|
+
if (hooksProperty) {
|
|
654
|
+
for (const prop of item.properties) {
|
|
655
|
+
if (prop.key.value !== "hooks" && prop.key.value !== "matcher") {
|
|
656
|
+
report(toMarker(( localize(7240, "Unknown property '{0}' in hook matcher.", prop.key.value)), prop.key.range, MarkerSeverity.Warning));
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (hooksProperty.value.type !== "sequence") {
|
|
660
|
+
report(toMarker(( localize(
|
|
661
|
+
7241,
|
|
662
|
+
"The 'hooks' property in a matcher must be an array of command objects."
|
|
663
|
+
)), hooksProperty.value.range, MarkerSeverity.Error));
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
for (const nestedItem of hooksProperty.value.items) {
|
|
667
|
+
this.validateHookCommand(nestedItem, target, report);
|
|
668
|
+
}
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const isCopilotCli = target === Target.GitHubCopilot;
|
|
672
|
+
const validCommandFields = isCopilotCli ? ( new Set(["bash", "powershell"])) : ( new Set(["command", "windows", "linux", "osx", "bash", "powershell"]));
|
|
673
|
+
const validProperties = isCopilotCli ? ( new Set(["type", "bash", "powershell", "cwd", "env", "timeoutSec"])) : ( new Set([
|
|
674
|
+
"type",
|
|
675
|
+
"command",
|
|
676
|
+
"windows",
|
|
677
|
+
"linux",
|
|
678
|
+
"osx",
|
|
679
|
+
"bash",
|
|
680
|
+
"powershell",
|
|
681
|
+
"cwd",
|
|
682
|
+
"env",
|
|
683
|
+
"timeout"
|
|
684
|
+
]));
|
|
685
|
+
let hasType = false;
|
|
686
|
+
let hasCommandField = false;
|
|
687
|
+
for (const prop of item.properties) {
|
|
688
|
+
const key = prop.key.value;
|
|
689
|
+
if (!( validProperties.has(key))) {
|
|
690
|
+
report(toMarker(( localize(7242, "Unknown property '{0}' in hook command.", key)), prop.key.range, MarkerSeverity.Warning));
|
|
691
|
+
}
|
|
692
|
+
if (key === "type") {
|
|
693
|
+
hasType = true;
|
|
694
|
+
if (prop.value.type !== "scalar" || prop.value.value !== "command") {
|
|
695
|
+
report(toMarker(( localize(7243, "The 'type' property in a hook command must be 'command'.")), prop.value.range, MarkerSeverity.Error));
|
|
696
|
+
}
|
|
697
|
+
} else if (( validCommandFields.has(key))) {
|
|
698
|
+
hasCommandField = true;
|
|
699
|
+
if (prop.value.type !== "scalar" || prop.value.value.trim().length === 0) {
|
|
700
|
+
report(toMarker(( localize(
|
|
701
|
+
7244,
|
|
702
|
+
"The '{0}' property in a hook command must be a non-empty string.",
|
|
703
|
+
key
|
|
704
|
+
)), prop.value.range, MarkerSeverity.Error));
|
|
705
|
+
}
|
|
706
|
+
} else if (key === "cwd") {
|
|
707
|
+
if (prop.value.type !== "scalar") {
|
|
708
|
+
report(toMarker(( localize(7245, "The 'cwd' property in a hook command must be a string.")), prop.value.range, MarkerSeverity.Error));
|
|
709
|
+
}
|
|
710
|
+
} else if (key === "env") {
|
|
711
|
+
if (prop.value.type !== "map") {
|
|
712
|
+
report(toMarker(( localize(
|
|
713
|
+
7246,
|
|
714
|
+
"The 'env' property in a hook command must be a map of string values."
|
|
715
|
+
)), prop.value.range, MarkerSeverity.Error));
|
|
716
|
+
} else {
|
|
717
|
+
for (const envProp of prop.value.properties) {
|
|
718
|
+
if (envProp.value.type !== "scalar") {
|
|
719
|
+
report(toMarker(( localize(
|
|
720
|
+
7247,
|
|
721
|
+
"Environment variable '{0}' must have a string value.",
|
|
722
|
+
envProp.key.value
|
|
723
|
+
)), envProp.value.range, MarkerSeverity.Error));
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
} else if (key === "timeout" || key === "timeoutSec") {
|
|
728
|
+
if (prop.value.type !== "scalar" || isNaN(Number(prop.value.value))) {
|
|
729
|
+
report(toMarker(( localize(7248, "The '{0}' property in a hook command must be a number.", key)), prop.value.range, MarkerSeverity.Error));
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (!hasType) {
|
|
734
|
+
report(toMarker(( localize(7249, "Hook command is missing required property 'type'.")), item.range, MarkerSeverity.Error));
|
|
735
|
+
}
|
|
736
|
+
if (!hasCommandField) {
|
|
737
|
+
if (isCopilotCli) {
|
|
738
|
+
report(toMarker(( localize(7250, "Hook command must specify at least one of 'bash' or 'powershell'.")), item.range, MarkerSeverity.Error));
|
|
739
|
+
} else {
|
|
740
|
+
report(toMarker(( localize(
|
|
741
|
+
7251,
|
|
742
|
+
"Hook command must specify at least one of 'command', 'windows', 'linux', or 'osx'."
|
|
743
|
+
)), item.range, MarkerSeverity.Error));
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
validateHandoffs(attributes, report) {
|
|
748
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.handOffs);
|
|
749
|
+
if (!attribute) {
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (attribute.value.type !== "sequence") {
|
|
753
|
+
report(toMarker(( localize(7252, "The 'handoffs' attribute must be an array.")), attribute.value.range, MarkerSeverity.Error));
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
for (const item of attribute.value.items) {
|
|
757
|
+
if (item.type !== "map") {
|
|
758
|
+
report(toMarker(( localize(
|
|
759
|
+
7253,
|
|
760
|
+
"Each handoff in the 'handoffs' attribute must be an object with 'label', 'agent', 'prompt' and optional 'send'."
|
|
761
|
+
)), item.range, MarkerSeverity.Error));
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
const required = ( new Set(["label", "agent", "prompt"]));
|
|
765
|
+
for (const prop of item.properties) {
|
|
766
|
+
switch (prop.key.value) {
|
|
767
|
+
case "label":
|
|
768
|
+
if (prop.value.type !== "scalar" || prop.value.value.trim().length === 0) {
|
|
769
|
+
report(toMarker(( localize(7254, "The 'label' property in a handoff must be a non-empty string.")), prop.value.range, MarkerSeverity.Error));
|
|
770
|
+
}
|
|
771
|
+
break;
|
|
772
|
+
case "agent":
|
|
773
|
+
if (prop.value.type !== "scalar" || prop.value.value.trim().length === 0) {
|
|
774
|
+
report(toMarker(( localize(7255, "The 'agent' property in a handoff must be a non-empty string.")), prop.value.range, MarkerSeverity.Error));
|
|
775
|
+
} else {
|
|
776
|
+
this.validateAgentValue(prop.value, report);
|
|
777
|
+
}
|
|
778
|
+
break;
|
|
779
|
+
case "prompt":
|
|
780
|
+
if (prop.value.type !== "scalar") {
|
|
781
|
+
report(toMarker(( localize(7256, "The 'prompt' property in a handoff must be a string.")), prop.value.range, MarkerSeverity.Error));
|
|
782
|
+
}
|
|
783
|
+
break;
|
|
784
|
+
case "send":
|
|
785
|
+
if (!isTrueOrFalse(prop.value)) {
|
|
786
|
+
report(toMarker(( localize(7257, "The 'send' property in a handoff must be a boolean.")), prop.value.range, MarkerSeverity.Error));
|
|
787
|
+
}
|
|
788
|
+
break;
|
|
789
|
+
case "showContinueOn":
|
|
790
|
+
if (!isTrueOrFalse(prop.value)) {
|
|
791
|
+
report(toMarker(( localize(7258, "The 'showContinueOn' property in a handoff must be a boolean.")), prop.value.range, MarkerSeverity.Error));
|
|
792
|
+
}
|
|
793
|
+
break;
|
|
794
|
+
case "model":
|
|
795
|
+
if (prop.value.type !== "scalar") {
|
|
796
|
+
report(toMarker(( localize(7259, "The 'model' property in a handoff must be a string.")), prop.value.range, MarkerSeverity.Error));
|
|
797
|
+
}
|
|
798
|
+
break;
|
|
799
|
+
default:
|
|
800
|
+
report(toMarker(( localize(
|
|
801
|
+
7260,
|
|
802
|
+
"Unknown property '{0}' in handoff object. Supported properties are 'label', 'agent', 'prompt' and optional 'send', 'showContinueOn', 'model'.",
|
|
803
|
+
prop.key.value
|
|
804
|
+
)), prop.value.range, MarkerSeverity.Warning));
|
|
805
|
+
}
|
|
806
|
+
required.delete(prop.key.value);
|
|
807
|
+
}
|
|
808
|
+
if (required.size > 0) {
|
|
809
|
+
report(toMarker(( localize(
|
|
810
|
+
7261,
|
|
811
|
+
"Missing required properties {0} in handoff object.",
|
|
812
|
+
( Array.from(required).map(s => `'${s}'`)).join(", ")
|
|
813
|
+
)), item.range, MarkerSeverity.Error));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
validateInfer(attributes, report) {
|
|
818
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.infer);
|
|
819
|
+
if (!attribute) {
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
report(toMarker(( localize(
|
|
823
|
+
7262,
|
|
824
|
+
"The 'infer' attribute is deprecated in favour of 'user-invocable' and 'disable-model-invocation'."
|
|
825
|
+
)), attribute.value.range, MarkerSeverity.Error));
|
|
826
|
+
}
|
|
827
|
+
validateTarget(attributes, report) {
|
|
828
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.target);
|
|
829
|
+
if (!attribute) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (attribute.value.type !== "scalar") {
|
|
833
|
+
report(toMarker(( localize(7263, "The 'target' attribute must be a string.")), attribute.value.range, MarkerSeverity.Error));
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const targetValue = attribute.value.value.trim();
|
|
837
|
+
if (targetValue.length === 0) {
|
|
838
|
+
report(toMarker(( localize(7264, "The 'target' attribute must be a non-empty string.")), attribute.value.range, MarkerSeverity.Error));
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
const validTargets = ["github-copilot", "vscode"];
|
|
842
|
+
if (!validTargets.includes(targetValue)) {
|
|
843
|
+
report(toMarker(( localize(
|
|
844
|
+
7265,
|
|
845
|
+
"The 'target' attribute must be one of: {0}.",
|
|
846
|
+
validTargets.join(", ")
|
|
847
|
+
)), attribute.value.range, MarkerSeverity.Error));
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
validateUserInvocable(attributes, report) {
|
|
851
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.userInvocable);
|
|
852
|
+
if (!attribute) {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (!isTrueOrFalse(attribute.value)) {
|
|
856
|
+
report(toMarker(( localize(7266, "The 'user-invocable' attribute must be 'true' or 'false'.")), attribute.value.range, MarkerSeverity.Error));
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
validateUserInvokable(attributes, report) {
|
|
861
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.userInvokable);
|
|
862
|
+
if (!attribute) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
report(toMarker(( localize(
|
|
866
|
+
7267,
|
|
867
|
+
"The 'user-invokable' attribute is deprecated. Use 'user-invocable' instead."
|
|
868
|
+
)), attribute.range, MarkerSeverity.Warning));
|
|
869
|
+
}
|
|
870
|
+
validateDisableModelInvocation(attributes, report) {
|
|
871
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.disableModelInvocation);
|
|
872
|
+
if (!attribute) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (!isTrueOrFalse(attribute.value)) {
|
|
876
|
+
report(toMarker(( localize(
|
|
877
|
+
7268,
|
|
878
|
+
"The 'disable-model-invocation' attribute must be 'true' or 'false'."
|
|
879
|
+
)), attribute.value.range, MarkerSeverity.Error));
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
async validateAgentsAttribute(attributes, header, report) {
|
|
884
|
+
const attribute = attributes.find(attr => attr.key === PromptHeaderAttributes.agents);
|
|
885
|
+
if (!attribute) {
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
if (attribute.value.type !== "sequence") {
|
|
889
|
+
report(toMarker(( localize(7269, "The 'agents' attribute must be an array.")), attribute.value.range, MarkerSeverity.Error));
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
const agents = await this.promptsService.getCustomAgents(CancellationToken.None);
|
|
893
|
+
const availableAgentNames = ( new Set(( agents.map(agent => agent.name))));
|
|
894
|
+
availableAgentNames.add(ChatMode.Agent.name.get());
|
|
895
|
+
const agentNames = [];
|
|
896
|
+
for (const item of attribute.value.items) {
|
|
897
|
+
if (item.type !== "scalar") {
|
|
898
|
+
report(toMarker(( localize(7270, "Each agent name in the 'agents' attribute must be a string.")), item.range, MarkerSeverity.Error));
|
|
899
|
+
} else if (item.value) {
|
|
900
|
+
agentNames.push(item.value);
|
|
901
|
+
if (item.value !== "*" && !( availableAgentNames.has(item.value))) {
|
|
902
|
+
report(toMarker(( localize(
|
|
903
|
+
7271,
|
|
904
|
+
"Unknown agent '{0}'. Available agents: {1}.",
|
|
905
|
+
item.value,
|
|
906
|
+
Array.from(availableAgentNames).join(", ")
|
|
907
|
+
)), item.range, MarkerSeverity.Warning));
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (agentNames.length > 0) {
|
|
912
|
+
const tools = header.tools;
|
|
913
|
+
if (tools && !tools.includes(SpecedToolAliases.agent)) {
|
|
914
|
+
report(toMarker(( localize(
|
|
915
|
+
7272,
|
|
916
|
+
"When 'agents' and 'tools' are specified, the 'agent' tool must be included in the 'tools' attribute."
|
|
917
|
+
)), attribute.value.range, MarkerSeverity.Warning));
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
validateGithubPermissions(attributes, report) {
|
|
922
|
+
const attribute = attributes.find(attr => attr.key === GithubPromptHeaderAttributes.github);
|
|
923
|
+
if (!attribute) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (attribute.value.type !== "map") {
|
|
927
|
+
report(toMarker(( localize(7273, "The 'github' attribute must be an object.")), attribute.value.range, MarkerSeverity.Error));
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
for (const prop of attribute.value.properties) {
|
|
931
|
+
if (prop.key.value !== "permissions") {
|
|
932
|
+
report(toMarker(( localize(
|
|
933
|
+
7274,
|
|
934
|
+
"Unknown property '{0}' in 'github' object. Supported: 'permissions'.",
|
|
935
|
+
prop.key.value
|
|
936
|
+
)), prop.key.range, MarkerSeverity.Warning));
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
if (prop.value.type !== "map") {
|
|
940
|
+
report(toMarker(( localize(7275, "The 'permissions' property must be an object.")), prop.value.range, MarkerSeverity.Error));
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
943
|
+
for (const permProp of prop.value.properties) {
|
|
944
|
+
const scope = permProp.key.value;
|
|
945
|
+
const scopeInfo = githubPermissionScopes[scope];
|
|
946
|
+
if (!scopeInfo) {
|
|
947
|
+
const validScopes = ( Object.keys(githubPermissionScopes)).sort().join(", ");
|
|
948
|
+
report(toMarker(( localize(
|
|
949
|
+
7276,
|
|
950
|
+
"Unknown permission scope '{0}'. Valid scopes: {1}.",
|
|
951
|
+
scope,
|
|
952
|
+
validScopes
|
|
953
|
+
)), permProp.key.range, MarkerSeverity.Warning));
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
if (permProp.value.type !== "scalar") {
|
|
957
|
+
report(toMarker(( localize(7277, "The permission value for '{0}' must be a string.", scope)), permProp.value.range, MarkerSeverity.Error));
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
const value = permProp.value.value;
|
|
961
|
+
if (!scopeInfo.allowedValues.includes(value)) {
|
|
962
|
+
report(toMarker(( localize(
|
|
963
|
+
7278,
|
|
964
|
+
"Invalid permission value '{0}' for scope '{1}'. Allowed values: {2}.",
|
|
965
|
+
value,
|
|
966
|
+
scope,
|
|
967
|
+
scopeInfo.allowedValues.join(", ")
|
|
968
|
+
)), permProp.value.range, MarkerSeverity.Error));
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
PromptValidator = ( __decorate([( __param(0, ILanguageModelsService)), ( __param(1, ILanguageModelToolsService)), ( __param(2, IChatModeService)), ( __param(3, IFileService)), ( __param(4, ILabelService)), ( __param(5, IPromptsService)), ( __param(6, IConfigurationService))], PromptValidator));
|
|
975
|
+
const githubPermissionScopes = {
|
|
976
|
+
"actions": {
|
|
977
|
+
allowedValues: ["read", "write", "none"],
|
|
978
|
+
description: ( localize(7279, "Access to GitHub Actions workflows and runs"))
|
|
979
|
+
},
|
|
980
|
+
"checks": {
|
|
981
|
+
allowedValues: ["read", "none"],
|
|
982
|
+
description: ( localize(7280, "Access to check runs and statuses"))
|
|
983
|
+
},
|
|
984
|
+
"contents": {
|
|
985
|
+
allowedValues: ["read", "write", "none"],
|
|
986
|
+
description: ( localize(7281, "Access to repository contents (files, commits, branches)"))
|
|
987
|
+
},
|
|
988
|
+
"discussions": {
|
|
989
|
+
allowedValues: ["read", "write", "none"],
|
|
990
|
+
description: ( localize(7282, "Access to discussions"))
|
|
991
|
+
},
|
|
992
|
+
"issues": {
|
|
993
|
+
allowedValues: ["read", "write", "none"],
|
|
994
|
+
description: ( localize(7283, "Access to issues (read, create, update, comment)"))
|
|
995
|
+
},
|
|
996
|
+
"metadata": {
|
|
997
|
+
allowedValues: ["read"],
|
|
998
|
+
description: ( localize(7284, "Repository metadata (always read-only)"))
|
|
999
|
+
},
|
|
1000
|
+
"pull-requests": {
|
|
1001
|
+
allowedValues: ["read", "write", "none"],
|
|
1002
|
+
description: ( localize(7285, "Access to pull requests (read, create, update, review)"))
|
|
1003
|
+
},
|
|
1004
|
+
"security-events": {
|
|
1005
|
+
allowedValues: ["read", "none"],
|
|
1006
|
+
description: ( localize(7286, "Access to security-related events"))
|
|
1007
|
+
},
|
|
1008
|
+
"workflows": {
|
|
1009
|
+
allowedValues: ["write", "none"],
|
|
1010
|
+
description: ( localize(7287, "Access to modify workflow files"))
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
function isTrueOrFalse(value) {
|
|
1014
|
+
if (value.type === "scalar") {
|
|
1015
|
+
return (value.value === "true" || value.value === "false") && value.format === "none";
|
|
1016
|
+
}
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
const allAttributeNames = {
|
|
1020
|
+
[PromptsType.prompt]: [
|
|
1021
|
+
PromptHeaderAttributes.name,
|
|
1022
|
+
PromptHeaderAttributes.description,
|
|
1023
|
+
PromptHeaderAttributes.model,
|
|
1024
|
+
PromptHeaderAttributes.tools,
|
|
1025
|
+
PromptHeaderAttributes.mode,
|
|
1026
|
+
PromptHeaderAttributes.agent,
|
|
1027
|
+
PromptHeaderAttributes.argumentHint
|
|
1028
|
+
],
|
|
1029
|
+
[PromptsType.instructions]: [
|
|
1030
|
+
PromptHeaderAttributes.name,
|
|
1031
|
+
PromptHeaderAttributes.description,
|
|
1032
|
+
PromptHeaderAttributes.applyTo,
|
|
1033
|
+
PromptHeaderAttributes.excludeAgent
|
|
1034
|
+
],
|
|
1035
|
+
[PromptsType.agent]: [
|
|
1036
|
+
PromptHeaderAttributes.name,
|
|
1037
|
+
PromptHeaderAttributes.description,
|
|
1038
|
+
PromptHeaderAttributes.model,
|
|
1039
|
+
PromptHeaderAttributes.tools,
|
|
1040
|
+
PromptHeaderAttributes.advancedOptions,
|
|
1041
|
+
PromptHeaderAttributes.handOffs,
|
|
1042
|
+
PromptHeaderAttributes.argumentHint,
|
|
1043
|
+
PromptHeaderAttributes.target,
|
|
1044
|
+
PromptHeaderAttributes.infer,
|
|
1045
|
+
PromptHeaderAttributes.agents,
|
|
1046
|
+
PromptHeaderAttributes.hooks,
|
|
1047
|
+
PromptHeaderAttributes.userInvocable,
|
|
1048
|
+
PromptHeaderAttributes.userInvokable,
|
|
1049
|
+
PromptHeaderAttributes.disableModelInvocation,
|
|
1050
|
+
GithubPromptHeaderAttributes.github
|
|
1051
|
+
],
|
|
1052
|
+
[PromptsType.skill]: [
|
|
1053
|
+
PromptHeaderAttributes.name,
|
|
1054
|
+
PromptHeaderAttributes.description,
|
|
1055
|
+
PromptHeaderAttributes.license,
|
|
1056
|
+
PromptHeaderAttributes.compatibility,
|
|
1057
|
+
PromptHeaderAttributes.metadata,
|
|
1058
|
+
PromptHeaderAttributes.argumentHint,
|
|
1059
|
+
PromptHeaderAttributes.userInvocable,
|
|
1060
|
+
PromptHeaderAttributes.userInvokable,
|
|
1061
|
+
PromptHeaderAttributes.disableModelInvocation
|
|
1062
|
+
],
|
|
1063
|
+
[PromptsType.hook]: []
|
|
1064
|
+
};
|
|
1065
|
+
const githubCopilotAgentAttributeNames = [
|
|
1066
|
+
PromptHeaderAttributes.name,
|
|
1067
|
+
PromptHeaderAttributes.description,
|
|
1068
|
+
PromptHeaderAttributes.tools,
|
|
1069
|
+
PromptHeaderAttributes.target,
|
|
1070
|
+
GithubPromptHeaderAttributes.mcpServers,
|
|
1071
|
+
GithubPromptHeaderAttributes.github,
|
|
1072
|
+
PromptHeaderAttributes.infer
|
|
1073
|
+
];
|
|
1074
|
+
const recommendedAttributeNames = {
|
|
1075
|
+
[PromptsType.prompt]: allAttributeNames[PromptsType.prompt].filter(name => !isNonRecommendedAttribute(name)),
|
|
1076
|
+
[PromptsType.instructions]: allAttributeNames[PromptsType.instructions].filter(name => !isNonRecommendedAttribute(name)),
|
|
1077
|
+
[PromptsType.agent]: allAttributeNames[PromptsType.agent].filter(name => !isNonRecommendedAttribute(name)),
|
|
1078
|
+
[PromptsType.skill]: allAttributeNames[PromptsType.skill].filter(name => !isNonRecommendedAttribute(name)),
|
|
1079
|
+
[PromptsType.hook]: []
|
|
1080
|
+
};
|
|
1081
|
+
function getValidAttributeNames(promptType, includeNonRecommended, target) {
|
|
1082
|
+
if (target === Target.Claude) {
|
|
1083
|
+
if (promptType === PromptsType.instructions) {
|
|
1084
|
+
return ( Object.keys(claudeRulesAttributes));
|
|
1085
|
+
}
|
|
1086
|
+
return ( Object.keys(claudeAgentAttributes));
|
|
1087
|
+
} else if (target === Target.GitHubCopilot) {
|
|
1088
|
+
if (promptType === PromptsType.agent) {
|
|
1089
|
+
return githubCopilotAgentAttributeNames;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return includeNonRecommended ? allAttributeNames[promptType] : recommendedAttributeNames[promptType];
|
|
1093
|
+
}
|
|
1094
|
+
function isNonRecommendedAttribute(attributeName) {
|
|
1095
|
+
return attributeName === PromptHeaderAttributes.advancedOptions || attributeName === PromptHeaderAttributes.excludeAgent || attributeName === PromptHeaderAttributes.mode || attributeName === PromptHeaderAttributes.infer || attributeName === PromptHeaderAttributes.userInvokable;
|
|
1096
|
+
}
|
|
1097
|
+
const knownClaudeTools = [{
|
|
1098
|
+
name: "Bash",
|
|
1099
|
+
description: ( localize(7288, "Execute shell commands")),
|
|
1100
|
+
toolEquivalent: [SpecedToolAliases.execute]
|
|
1101
|
+
}, {
|
|
1102
|
+
name: "Edit",
|
|
1103
|
+
description: ( localize(7289, "Make targeted file edits")),
|
|
1104
|
+
toolEquivalent: ["edit/editNotebook", "edit/editFiles"]
|
|
1105
|
+
}, {
|
|
1106
|
+
name: "Glob",
|
|
1107
|
+
description: ( localize(7290, "Find files by pattern")),
|
|
1108
|
+
toolEquivalent: ["search/fileSearch"]
|
|
1109
|
+
}, {
|
|
1110
|
+
name: "Grep",
|
|
1111
|
+
description: ( localize(7291, "Search file contents with regex")),
|
|
1112
|
+
toolEquivalent: ["search/textSearch"]
|
|
1113
|
+
}, {
|
|
1114
|
+
name: "Read",
|
|
1115
|
+
description: ( localize(7292, "Read file contents")),
|
|
1116
|
+
toolEquivalent: ["read/readFile", "read/getNotebookSummary"]
|
|
1117
|
+
}, {
|
|
1118
|
+
name: "Write",
|
|
1119
|
+
description: ( localize(7293, "Create/overwrite files")),
|
|
1120
|
+
toolEquivalent: ["edit/createDirectory", "edit/createFile", "edit/createJupyterNotebook"]
|
|
1121
|
+
}, {
|
|
1122
|
+
name: "WebFetch",
|
|
1123
|
+
description: ( localize(7294, "Fetch URL content")),
|
|
1124
|
+
toolEquivalent: [SpecedToolAliases.web]
|
|
1125
|
+
}, {
|
|
1126
|
+
name: "WebSearch",
|
|
1127
|
+
description: ( localize(7295, "Perform web searches")),
|
|
1128
|
+
toolEquivalent: [SpecedToolAliases.web]
|
|
1129
|
+
}, {
|
|
1130
|
+
name: "Task",
|
|
1131
|
+
description: ( localize(7296, "Run subagents for complex tasks")),
|
|
1132
|
+
toolEquivalent: [SpecedToolAliases.agent]
|
|
1133
|
+
}, {
|
|
1134
|
+
name: "Skill",
|
|
1135
|
+
description: ( localize(7297, "Execute skills")),
|
|
1136
|
+
toolEquivalent: []
|
|
1137
|
+
}, {
|
|
1138
|
+
name: "LSP",
|
|
1139
|
+
description: ( localize(7298, "Code intelligence (requires plugin)")),
|
|
1140
|
+
toolEquivalent: []
|
|
1141
|
+
}, {
|
|
1142
|
+
name: "NotebookEdit",
|
|
1143
|
+
description: ( localize(7299, "Modify Jupyter notebooks")),
|
|
1144
|
+
toolEquivalent: ["edit/editNotebook"]
|
|
1145
|
+
}, {
|
|
1146
|
+
name: "AskUserQuestion",
|
|
1147
|
+
description: ( localize(7300, "Ask multiple-choice questions")),
|
|
1148
|
+
toolEquivalent: ["vscode/askQuestions"]
|
|
1149
|
+
}, {
|
|
1150
|
+
name: "MCPSearch",
|
|
1151
|
+
description: ( localize(7301, "Searches for MCP tools when tool search is enabled")),
|
|
1152
|
+
toolEquivalent: []
|
|
1153
|
+
}];
|
|
1154
|
+
const knownClaudeModels = [{
|
|
1155
|
+
name: "sonnet",
|
|
1156
|
+
description: ( localize(7302, "Latest Claude Sonnet")),
|
|
1157
|
+
modelEquivalent: "Claude Sonnet 4.5 (copilot)"
|
|
1158
|
+
}, {
|
|
1159
|
+
name: "opus",
|
|
1160
|
+
description: ( localize(7303, "Latest Claude Opus")),
|
|
1161
|
+
modelEquivalent: "Claude Opus 4.6 (copilot)"
|
|
1162
|
+
}, {
|
|
1163
|
+
name: "haiku",
|
|
1164
|
+
description: ( localize(7304, "Latest Claude Haiku, fast for simple tasks")),
|
|
1165
|
+
modelEquivalent: "Claude Haiku 4.5 (copilot)"
|
|
1166
|
+
}, {
|
|
1167
|
+
name: "inherit",
|
|
1168
|
+
description: ( localize(7305, "Inherit model from parent agent or prompt")),
|
|
1169
|
+
modelEquivalent: undefined
|
|
1170
|
+
}];
|
|
1171
|
+
const claudeAgentAttributes = {
|
|
1172
|
+
"name": {
|
|
1173
|
+
type: "scalar",
|
|
1174
|
+
description: ( localize(7306, "Unique identifier using lowercase letters and hyphens (required)"))
|
|
1175
|
+
},
|
|
1176
|
+
"description": {
|
|
1177
|
+
type: "scalar",
|
|
1178
|
+
description: ( localize(7307, "When to delegate to this subagent (required)"))
|
|
1179
|
+
},
|
|
1180
|
+
"tools": {
|
|
1181
|
+
type: "sequence",
|
|
1182
|
+
description: ( localize(7308, "Array of tools the subagent can use. Inherits all tools if omitted")),
|
|
1183
|
+
defaults: ["Read, Edit, Bash"],
|
|
1184
|
+
items: knownClaudeTools
|
|
1185
|
+
},
|
|
1186
|
+
"disallowedTools": {
|
|
1187
|
+
type: "sequence",
|
|
1188
|
+
description: ( localize(7309, "Tools to deny, removed from inherited or specified list")),
|
|
1189
|
+
defaults: ["Write, Edit, Bash"],
|
|
1190
|
+
items: knownClaudeTools
|
|
1191
|
+
},
|
|
1192
|
+
"model": {
|
|
1193
|
+
type: "scalar",
|
|
1194
|
+
description: ( localize(
|
|
1195
|
+
7310,
|
|
1196
|
+
"Model to use: sonnet, opus, haiku, or inherit. Defaults to inherit."
|
|
1197
|
+
)),
|
|
1198
|
+
defaults: ["sonnet", "opus", "haiku", "inherit"],
|
|
1199
|
+
enums: knownClaudeModels
|
|
1200
|
+
},
|
|
1201
|
+
"permissionMode": {
|
|
1202
|
+
type: "scalar",
|
|
1203
|
+
description: ( localize(
|
|
1204
|
+
7311,
|
|
1205
|
+
"Permission mode: default, acceptEdits, dontAsk, bypassPermissions, or plan."
|
|
1206
|
+
)),
|
|
1207
|
+
defaults: ["default", "acceptEdits", "dontAsk", "bypassPermissions", "plan"],
|
|
1208
|
+
enums: [{
|
|
1209
|
+
name: "default",
|
|
1210
|
+
description: ( localize(
|
|
1211
|
+
7312,
|
|
1212
|
+
"Standard behavior: prompts for permission on first use of each tool."
|
|
1213
|
+
))
|
|
1214
|
+
}, {
|
|
1215
|
+
name: "acceptEdits",
|
|
1216
|
+
description: ( localize(7313, "Automatically accepts file edit permissions for the session."))
|
|
1217
|
+
}, {
|
|
1218
|
+
name: "plan",
|
|
1219
|
+
description: ( localize(
|
|
1220
|
+
7314,
|
|
1221
|
+
"Plan Mode: Claude can analyze but not modify files or execute commands."
|
|
1222
|
+
))
|
|
1223
|
+
}, {
|
|
1224
|
+
name: "delegate",
|
|
1225
|
+
description: ( localize(
|
|
1226
|
+
7315,
|
|
1227
|
+
"Coordination-only mode for agent team leads. Only available when an agent team is active."
|
|
1228
|
+
))
|
|
1229
|
+
}, {
|
|
1230
|
+
name: "dontAsk",
|
|
1231
|
+
description: ( localize(
|
|
1232
|
+
7316,
|
|
1233
|
+
"Auto-denies tools unless pre-approved via /permissions or permissions.allow rules."
|
|
1234
|
+
))
|
|
1235
|
+
}, {
|
|
1236
|
+
name: "bypassPermissions",
|
|
1237
|
+
description: ( localize(
|
|
1238
|
+
7317,
|
|
1239
|
+
"Skips all permission prompts (requires safe environment like containers)."
|
|
1240
|
+
))
|
|
1241
|
+
}]
|
|
1242
|
+
},
|
|
1243
|
+
"skills": {
|
|
1244
|
+
type: "sequence",
|
|
1245
|
+
description: ( localize(7318, "Skills to load into the subagent's context at startup."))
|
|
1246
|
+
},
|
|
1247
|
+
"mcpServers": {
|
|
1248
|
+
type: "sequence",
|
|
1249
|
+
description: ( localize(7319, "MCP servers available to this subagent."))
|
|
1250
|
+
},
|
|
1251
|
+
"hooks": {
|
|
1252
|
+
type: "object",
|
|
1253
|
+
description: ( localize(7320, "Lifecycle hooks scoped to this subagent."))
|
|
1254
|
+
},
|
|
1255
|
+
"memory": {
|
|
1256
|
+
type: "scalar",
|
|
1257
|
+
description: ( localize(
|
|
1258
|
+
7321,
|
|
1259
|
+
"Persistent memory scope: user, project, or local. Enables cross-session learning."
|
|
1260
|
+
)),
|
|
1261
|
+
defaults: ["user", "project", "local"],
|
|
1262
|
+
enums: [{
|
|
1263
|
+
name: "user",
|
|
1264
|
+
description: ( localize(7322, "Remember learnings across all projects."))
|
|
1265
|
+
}, {
|
|
1266
|
+
name: "project",
|
|
1267
|
+
description: ( localize(
|
|
1268
|
+
7323,
|
|
1269
|
+
"The subagent's knowledge is project-specific and shareable via version control."
|
|
1270
|
+
))
|
|
1271
|
+
}, {
|
|
1272
|
+
name: "local",
|
|
1273
|
+
description: ( localize(
|
|
1274
|
+
7324,
|
|
1275
|
+
"The subagent's knowledge is project-specific but should not be checked into version control."
|
|
1276
|
+
))
|
|
1277
|
+
}]
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
const claudeRulesAttributes = {
|
|
1281
|
+
"description": {
|
|
1282
|
+
type: "scalar",
|
|
1283
|
+
description: ( localize(
|
|
1284
|
+
7325,
|
|
1285
|
+
"A description of what this rule covers, used to provide context about when it applies."
|
|
1286
|
+
))
|
|
1287
|
+
},
|
|
1288
|
+
"paths": {
|
|
1289
|
+
type: "sequence",
|
|
1290
|
+
description: ( localize(
|
|
1291
|
+
7326,
|
|
1292
|
+
"Array of glob patterns that describe for which files the rule applies. Based on these patterns, the file is automatically included in the prompt when the context contains a file that matches.\nExample: `['src/**/*.ts', 'test/**']`"
|
|
1293
|
+
))
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
function isVSCodeOrDefaultTarget(target) {
|
|
1297
|
+
return target === Target.VSCode || target === Target.Undefined;
|
|
1298
|
+
}
|
|
1299
|
+
function getTarget(promptType, header) {
|
|
1300
|
+
const uri = header instanceof URI ? header : header.uri;
|
|
1301
|
+
if (promptType === PromptsType.agent) {
|
|
1302
|
+
const parentDir = dirname(uri);
|
|
1303
|
+
if (parentDir.path.endsWith(`/${CLAUDE_AGENTS_SOURCE_FOLDER}`)) {
|
|
1304
|
+
return Target.Claude;
|
|
1305
|
+
}
|
|
1306
|
+
if (!(header instanceof URI)) {
|
|
1307
|
+
const target = header.target;
|
|
1308
|
+
if (target === Target.GitHubCopilot || target === Target.VSCode) {
|
|
1309
|
+
return target;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
return Target.Undefined;
|
|
1313
|
+
} else if (promptType === PromptsType.instructions) {
|
|
1314
|
+
if (isInClaudeRulesFolder(uri)) {
|
|
1315
|
+
return Target.Claude;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return Target.Undefined;
|
|
1319
|
+
}
|
|
1320
|
+
function toMarker(message, range, severity = MarkerSeverity.Error) {
|
|
1321
|
+
return {
|
|
1322
|
+
severity,
|
|
1323
|
+
message,
|
|
1324
|
+
...range
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
let PromptValidatorContribution = class PromptValidatorContribution extends Disposable {
|
|
1328
|
+
constructor(
|
|
1329
|
+
modelService,
|
|
1330
|
+
instantiationService,
|
|
1331
|
+
markerService,
|
|
1332
|
+
promptsService,
|
|
1333
|
+
languageModelsService,
|
|
1334
|
+
languageModelToolsService,
|
|
1335
|
+
chatModeService
|
|
1336
|
+
) {
|
|
1337
|
+
super();
|
|
1338
|
+
this.modelService = modelService;
|
|
1339
|
+
this.markerService = markerService;
|
|
1340
|
+
this.promptsService = promptsService;
|
|
1341
|
+
this.languageModelsService = languageModelsService;
|
|
1342
|
+
this.languageModelToolsService = languageModelToolsService;
|
|
1343
|
+
this.chatModeService = chatModeService;
|
|
1344
|
+
this.localDisposables = this._register(( new DisposableStore()));
|
|
1345
|
+
this.validator = instantiationService.createInstance(PromptValidator);
|
|
1346
|
+
this.updateRegistration();
|
|
1347
|
+
}
|
|
1348
|
+
updateRegistration() {
|
|
1349
|
+
this.localDisposables.clear();
|
|
1350
|
+
const trackers = ( new ResourceMap());
|
|
1351
|
+
this.localDisposables.add(toDisposable(() => {
|
|
1352
|
+
trackers.forEach(tracker => tracker.dispose());
|
|
1353
|
+
trackers.clear();
|
|
1354
|
+
}));
|
|
1355
|
+
this.modelService.getModels().forEach(model => {
|
|
1356
|
+
const promptType = getPromptsTypeForLanguageId(model.getLanguageId());
|
|
1357
|
+
if (promptType) {
|
|
1358
|
+
trackers.set(model.uri, ( new ModelTracker(model, promptType, this.validator, this.promptsService, this.markerService)));
|
|
1359
|
+
}
|
|
1360
|
+
});
|
|
1361
|
+
this.localDisposables.add(this.modelService.onModelAdded(model => {
|
|
1362
|
+
const promptType = getPromptsTypeForLanguageId(model.getLanguageId());
|
|
1363
|
+
if (promptType && !( trackers.has(model.uri))) {
|
|
1364
|
+
trackers.set(model.uri, ( new ModelTracker(model, promptType, this.validator, this.promptsService, this.markerService)));
|
|
1365
|
+
}
|
|
1366
|
+
}));
|
|
1367
|
+
this.localDisposables.add(this.modelService.onModelRemoved(model => {
|
|
1368
|
+
const tracker = trackers.get(model.uri);
|
|
1369
|
+
if (tracker) {
|
|
1370
|
+
tracker.dispose();
|
|
1371
|
+
trackers.delete(model.uri);
|
|
1372
|
+
}
|
|
1373
|
+
}));
|
|
1374
|
+
this.localDisposables.add(this.modelService.onModelLanguageChanged(event => {
|
|
1375
|
+
const {
|
|
1376
|
+
model
|
|
1377
|
+
} = event;
|
|
1378
|
+
const tracker = trackers.get(model.uri);
|
|
1379
|
+
if (tracker) {
|
|
1380
|
+
tracker.dispose();
|
|
1381
|
+
trackers.delete(model.uri);
|
|
1382
|
+
}
|
|
1383
|
+
const promptType = getPromptsTypeForLanguageId(model.getLanguageId());
|
|
1384
|
+
if (promptType) {
|
|
1385
|
+
trackers.set(model.uri, ( new ModelTracker(model, promptType, this.validator, this.promptsService, this.markerService)));
|
|
1386
|
+
}
|
|
1387
|
+
}));
|
|
1388
|
+
const validateAll = () => trackers.forEach(tracker => tracker.validate());
|
|
1389
|
+
this.localDisposables.add(this.languageModelToolsService.onDidChangeTools(() => validateAll()));
|
|
1390
|
+
this.localDisposables.add(this.chatModeService.onDidChangeChatModes(() => validateAll()));
|
|
1391
|
+
this.localDisposables.add(this.languageModelsService.onDidChangeLanguageModels(() => validateAll()));
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1394
|
+
PromptValidatorContribution = ( __decorate([( __param(0, IModelService)), ( __param(1, IInstantiationService)), ( __param(2, IMarkerService)), ( __param(3, IPromptsService)), ( __param(4, ILanguageModelsService)), ( __param(5, ILanguageModelToolsService)), ( __param(6, IChatModeService))], PromptValidatorContribution));
|
|
1395
|
+
let ModelTracker = class ModelTracker extends Disposable {
|
|
1396
|
+
constructor(textModel, promptType, validator, promptsService, markerService) {
|
|
1397
|
+
super();
|
|
1398
|
+
this.textModel = textModel;
|
|
1399
|
+
this.promptType = promptType;
|
|
1400
|
+
this.validator = validator;
|
|
1401
|
+
this.promptsService = promptsService;
|
|
1402
|
+
this.markerService = markerService;
|
|
1403
|
+
this.delayer = this._register(( new Delayer(200)));
|
|
1404
|
+
this._register(textModel.onDidChangeContent(() => this.validate()));
|
|
1405
|
+
this.validate();
|
|
1406
|
+
}
|
|
1407
|
+
validate() {
|
|
1408
|
+
this.delayer.trigger(async () => {
|
|
1409
|
+
const markers = [];
|
|
1410
|
+
const ast = this.promptsService.getParsedPromptFile(this.textModel);
|
|
1411
|
+
await this.validator.validate(ast, this.promptType, m => markers.push(m));
|
|
1412
|
+
this.markerService.changeOne(MARKERS_OWNER_ID, this.textModel.uri, markers);
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
dispose() {
|
|
1416
|
+
this.markerService.remove(MARKERS_OWNER_ID, [this.textModel.uri]);
|
|
1417
|
+
super.dispose();
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
ModelTracker = ( __decorate([( __param(3, IPromptsService)), ( __param(4, IMarkerService))], ModelTracker));
|
|
1421
|
+
|
|
1422
|
+
export { MARKERS_OWNER_ID, PromptValidator, PromptValidatorContribution, claudeAgentAttributes, claudeRulesAttributes, getTarget, getValidAttributeNames, githubPermissionScopes, isNonRecommendedAttribute, isVSCodeOrDefaultTarget, knownClaudeModels, knownClaudeTools };
|