@codingame/monaco-vscode-katex-common 30.0.0 → 31.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/package.json +3 -3
- package/vscode/src/vs/platform/actions/browser/actionbar.d.ts +16 -0
- package/vscode/src/vs/platform/actions/browser/actionbar.js +22 -0
- package/vscode/src/vs/platform/actions/browser/buttonbar.js +2 -2
- package/vscode/src/vs/platform/networkFilter/common/domainMatcher.d.ts +50 -0
- package/vscode/src/vs/platform/networkFilter/common/domainMatcher.js +138 -0
- package/vscode/src/vs/platform/networkFilter/common/settings.d.ts +12 -0
- package/vscode/src/vs/platform/networkFilter/common/settings.js +14 -0
- package/vscode/src/vs/platform/sandbox/common/sandboxHelperIpc.d.ts +18 -0
- package/vscode/src/vs/platform/sandbox/common/sandboxHelperIpc.js +13 -0
- package/vscode/src/vs/platform/sandbox/common/terminalSandboxService.d.ts +73 -0
- package/vscode/src/vs/platform/sandbox/common/terminalSandboxService.js +10 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/accessibility/chatAccessibilityProvider.js +16 -16
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatContinueInAction.d.ts +3 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatContinueInAction.js +51 -24
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatElicitationActions.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.d.ts +2 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.js +64 -72
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.js +10 -10
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.d.ts +2 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.js +17 -14
- package/vscode/src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.js +13 -13
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionApprovalModel.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionHoverWidget.js +17 -18
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsControl.js +5 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsFilter.d.ts +5 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsFilter.js +73 -9
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsOpener.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer.js +32 -32
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatAttachmentModel.d.ts +1 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatAttachmentModel.js +20 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatAttachmentWidgets.d.ts +1 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/chatAttachmentWidgets.js +73 -49
- package/vscode/src/vs/workbench/contrib/chat/browser/attachments/implicitContextAttachment.js +12 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.d.ts +0 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.js +41 -99
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorActions.js +14 -14
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorOverlay.d.ts +2 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorOverlay.js +13 -9
- package/vscode/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingExplanationWidget.js +12 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSessions/chatSessionPickerActionItem.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/tools/toolSetsContribution.js +14 -15
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatAgentHover.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatArtifactsWidget.d.ts +11 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatArtifactsWidget.js +339 -161
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentMarkdownRenderer.js +9 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAgentCommandContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAnonymousRateLimitedPart.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAttachmentsContentPart.d.ts +9 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAttachmentsContentPart.js +33 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatChangesSummaryPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatCodeCitationContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatCollections.d.ts +43 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatCollections.js +147 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatCommandContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatConfirmationContentPart.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatConfirmationWidget.d.ts +4 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatConfirmationWidget.js +55 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatContentCodePools.d.ts +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatContentCodePools.js +7 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatContentParts.d.ts +1 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatDiffBlockPart.js +42 -10
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatDisabledClaudeHooksContentPart.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatExtensionsContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatHookContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/animations/animation.d.ts +18 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/animations/animationRegistry.d.ts +15 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/animations/animationRegistry.js +16 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/animations/blockAnimations.d.ts +13 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/animations/blockAnimations.js +33 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/buffer.d.ts +46 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/bufferRegistry.d.ts +11 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/bufferRegistry.js +12 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/offBuffer.d.ts +9 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/offBuffer.js +12 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/paragraphBuffer.d.ts +23 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/paragraphBuffer.js +37 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/wordBuffer.d.ts +34 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/buffers/wordBuffer.js +68 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/chatIncrementalRendering.d.ts +77 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/chatIncrementalRendering.js +170 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatIncrementalRendering/media/chatIncrementalRendering.css +112 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatInlineAnchorWidget.d.ts +3 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatInlineAnchorWidget.js +26 -16
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatMarkdownContentPart.d.ts +24 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatMarkdownContentPart.js +111 -145
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatMcpServersInteractionContentPart.js +8 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatMultiDiffContentPart.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatPlanReviewPart.d.ts +58 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatPlanReviewPart.js +425 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.d.ts +16 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatProgressContentPart.js +68 -25
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.d.ts +5 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuestionCarouselPart.js +101 -45
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatQuotaExceededPart.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatReferencesContentPart.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatResourceGroupWidget.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.d.ts +36 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSubagentContentPart.js +217 -25
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatSuggestNextWidget.js +6 -6
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatTextEditContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.d.ts +23 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatThinkingContentPart.js +168 -60
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatTipContentPart.js +10 -10
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatTodoListWidget.js +18 -17
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatToolInputOutputContentPart.d.ts +1 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatToolInputOutputContentPart.js +7 -18
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatToolOutputContentSubPart.d.ts +1 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatToolOutputContentSubPart.js +7 -19
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatTreeContentPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatWorkspaceEditContentPart.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/codeBlockPart.d.ts +24 -19
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/codeBlockPart.js +104 -78
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatConfirmationWidget.css +11 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatPlanReview.css +257 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatQuestionCarousel.css +19 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatSubagentContent.css +30 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatTerminalToolProgressPart.css +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatThinkingContent.css +12 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatToolConfirmationCarousel.css +286 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/abstractToolConfirmationSubPart.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatExtensionsInstallToolSubPart.js +4 -4
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatMcpAppModel.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatMcpAppSubPart.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatMissingSandboxDepsConfirmationSubPart.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatModifiedFilesConfirmationSubPart.js +15 -11
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatTerminalToolConfirmationSubPart.d.ts +1 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatTerminalToolConfirmationSubPart.js +25 -47
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatTerminalToolProgressPart.d.ts +29 -53
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatTerminalToolProgressPart.js +258 -321
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolConfirmationCarouselPart.d.ts +53 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolConfirmationCarouselPart.js +392 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolConfirmationSubPart.d.ts +1 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolConfirmationSubPart.js +24 -30
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolInvocationPart.d.ts +2 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolInvocationPart.js +9 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolOutputPart.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolPartUtilities.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/chatToolPostExecuteConfirmationPart.js +5 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/terminalToolAutoExpand.d.ts +6 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatContentParts/toolInvocationParts/terminalToolAutoExpand.js +2 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatDragAndDrop.js +11 -11
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.d.ts +38 -11
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.js +577 -113
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatListWidget.d.ts +0 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatListWidget.js +4 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatWidget.d.ts +1 -8
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/chatWidget.js +58 -75
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatFollowups.js +1 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.d.ts +44 -12
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.js +362 -188
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPickerActionItem.d.ts +0 -2
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.d.ts +4 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatModelPicker.js +42 -95
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/chatModelSelectionLogic.d.ts +2 -1
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.js +9 -10
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/modePickerActionItem.js +57 -38
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/modelPickerActionItem.d.ts +21 -15
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/{modelPickerActionItem2.js → modelPickerActionItem.js} +5 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/permissionPickerActionItem.js +38 -31
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/sessionTargetPickerActionItem.js +4 -5
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/workspacePickerActionItem.js +3 -3
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/media/chat.css +94 -40
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatContextUsageDetails.js +7 -7
- package/vscode/src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatContextUsageWidget.js +2 -2
- package/vscode/src/vs/workbench/contrib/chat/common/chatArtifactExtraction.d.ts +16 -0
- package/vscode/src/vs/workbench/contrib/chat/common/chatArtifactExtraction.js +218 -0
- package/vscode/src/vs/workbench/contrib/chat/common/chatImageExtraction.js +7 -7
- package/vscode/src/vs/workbench/contrib/chat/common/widget/annotations.js +6 -1
- package/vscode/src/vs/workbench/contrib/chat/common/widget/chatColors.js +15 -15
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatAffordance.js +12 -21
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.d.ts +2 -32
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.js +355 -156
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.d.ts +2 -13
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.js +72 -65
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatOverlayWidget.d.ts +4 -43
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatOverlayWidget.js +238 -204
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.d.ts +4 -19
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.js +128 -115
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.d.ts +6 -9
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.js +152 -49
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/media/inlineChat.css +64 -0
- package/vscode/src/vs/workbench/contrib/inlineChat/common/inlineChat.js +40 -40
- package/vscode/src/vs/workbench/contrib/interactive/browser/replInputHintContentWidget.js +3 -3
- package/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/executionStatusBarItemController.js +7 -7
- package/vscode/src/vs/workbench/contrib/notebook/browser/contrib/find/notebookFindWidget.js +2 -2
- package/vscode/src/vs/workbench/contrib/notebook/browser/controller/cellOperations.js +2 -2
- package/vscode/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.js +24 -24
- package/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.js +3 -3
- package/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.js +7 -7
- package/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditor.js +1 -1
- package/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.js +5 -5
- package/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffList.js +1 -1
- package/vscode/src/vs/workbench/contrib/replNotebook/browser/replEditor.js +1 -1
- package/vscode/src/vs/workbench/contrib/replNotebook/browser/replEditorInput.js +1 -1
- package/vscode/src/vs/workbench/contrib/terminal/terminalContribChatExports.d.ts +2 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/alternativeRecommendation.d.ts +2 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/alternativeRecommendation.js +41 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/commandParsers/commandFileWriteParser.d.ts +24 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/commandParsers/sedFileWriteParser.d.ts +26 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/commandParsers/sedFileWriteParser.js +142 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/basicExecuteStrategy.d.ts +45 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/basicExecuteStrategy.js +165 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/executeStrategy.d.ts +53 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/executeStrategy.js +163 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/noneExecuteStrategy.d.ts +27 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/noneExecuteStrategy.js +142 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/richExecuteStrategy.d.ts +29 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/richExecuteStrategy.js +144 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/strategyHelpers.d.ts +40 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/strategyHelpers.js +174 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/outputHelpers.d.ts +7 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/outputHelpers.js +43 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/runInTerminalHelpers.d.ts +42 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/runInTerminalHelpers.js +256 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/runInTerminalToolTelemetry.d.ts +42 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/runInTerminalToolTelemetry.js +94 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/toolTerminalCreator.d.ts +42 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/toolTerminalCreator.js +221 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/autoApprove/commandLineAutoApprover.d.ts +31 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/autoApprove/commandLineAutoApprover.js +392 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/autoApprove/npmScriptAutoApprover.d.ts +45 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/autoApprove/npmScriptAutoApprover.js +243 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineAnalyzer.d.ts +52 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineAnalyzer.js +10 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineAutoApproveAnalyzer.d.ts +20 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineAutoApproveAnalyzer.js +310 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineFileWriteAnalyzer.d.ts +19 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineFileWriteAnalyzer.js +168 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineSandboxAnalyzer.d.ts +11 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineAnalyzer/commandLineSandboxAnalyzer.js +33 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/commandLinePresenter.d.ts +41 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/nodeCommandLinePresenter.d.ts +19 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/nodeCommandLinePresenter.js +37 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/pythonCommandLinePresenter.d.ts +19 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/pythonCommandLinePresenter.js +37 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/rubyCommandLinePresenter.d.ts +19 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/rubyCommandLinePresenter.js +44 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/sandboxedCommandLinePresenter.d.ts +13 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLinePresenter/sandboxedCommandLinePresenter.js +22 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineBackgroundDetachRewriter.d.ts +22 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineBackgroundDetachRewriter.js +47 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineCdPrefixRewriter.d.ts +5 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineCdPrefixRewriter.js +27 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLinePreventHistoryRewriter.d.ts +14 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLinePreventHistoryRewriter.js +29 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLinePwshChainOperatorRewriter.d.ts +8 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLinePwshChainOperatorRewriter.js +33 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineRewriter.d.ts +24 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineSandboxRewriter.d.ts +8 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/commandLineRewriter/commandLineSandboxRewriter.js +32 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/monitoring/outputMonitor.d.ts +108 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/monitoring/outputMonitor.js +412 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/monitoring/types.d.ts +42 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/monitoring/types.js +23 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/outputAnalyzer.d.ts +9 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalTool.d.ts +192 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalTool.js +2258 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/sandboxOutputAnalyzer.d.ts +22 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/sandboxOutputAnalyzer.js +43 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/terminalCommandArtifactCollector.d.ts +17 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/terminalCommandArtifactCollector.js +118 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/terminalToolAutoApprove.d.ts +22 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/terminalToolAutoApprove.js +44 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/toolIds.d.ts +1 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/treeSitterCommandParser.d.ts +25 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/treeSitterCommandParser.js +141 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalSandboxService.d.ts +85 -0
- package/vscode/src/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalSandboxService.js +608 -0
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSessions/searchableOptionPickerActionItem.d.ts +0 -40
- package/vscode/src/vs/workbench/contrib/chat/browser/chatSessions/searchableOptionPickerActionItem.js +0 -196
- package/vscode/src/vs/workbench/contrib/chat/browser/widget/input/modelPickerActionItem2.d.ts +0 -29
- package/vscode/src/vs/workbench/contrib/chat/common/widget/codeBlockModelCollection.d.ts +0 -46
- package/vscode/src/vs/workbench/contrib/chat/common/widget/codeBlockModelCollection.js +0 -215
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatGutterAffordance.d.ts +0 -18
- package/vscode/src/vs/workbench/contrib/inlineChat/browser/inlineChatGutterAffordance.js +0 -107
|
@@ -0,0 +1,2258 @@
|
|
|
1
|
+
|
|
2
|
+
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
|
|
3
|
+
import { timeout, DeferredPromise } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
|
|
4
|
+
import { CancellationTokenSource } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
|
|
5
|
+
import { Codicon } from '@codingame/monaco-vscode-api/vscode/vs/base/common/codicons';
|
|
6
|
+
import { CancellationError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
|
|
7
|
+
import { Event } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
|
|
8
|
+
import { MarkdownString, escapeMarkdownSyntaxTokens } from '@codingame/monaco-vscode-api/vscode/vs/base/common/htmlContent';
|
|
9
|
+
import { Disposable, MutableDisposable, DisposableMap, DisposableStore, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
|
|
10
|
+
import { ResourceMap } from '@codingame/monaco-vscode-api/vscode/vs/base/common/map';
|
|
11
|
+
import { getMediaMime } from '@codingame/monaco-vscode-api/vscode/vs/base/common/mime';
|
|
12
|
+
import { clamp } from '@codingame/monaco-vscode-api/vscode/vs/base/common/numbers';
|
|
13
|
+
import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
|
|
14
|
+
import { basename, win32, posix } from '@codingame/monaco-vscode-api/vscode/vs/base/common/path';
|
|
15
|
+
import { OS, OperatingSystem } from '@codingame/monaco-vscode-api/vscode/vs/base/common/platform';
|
|
16
|
+
import { count } from '@codingame/monaco-vscode-api/vscode/vs/base/common/strings';
|
|
17
|
+
import { isNumber, isString } from '@codingame/monaco-vscode-api/vscode/vs/base/common/types';
|
|
18
|
+
import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
|
|
19
|
+
import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
|
|
20
|
+
import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
|
|
21
|
+
import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service';
|
|
22
|
+
import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
|
|
23
|
+
import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
|
|
24
|
+
import { ILabelService } from '@codingame/monaco-vscode-api/vscode/vs/platform/label/common/label.service';
|
|
25
|
+
import { StorageScope, StorageTarget } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage';
|
|
26
|
+
import { IStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage.service';
|
|
27
|
+
import { TerminalCapability } from '@codingame/monaco-vscode-api/vscode/vs/platform/terminal/common/capabilities/capabilities';
|
|
28
|
+
import { ITerminalLogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/terminal/common/terminal.service';
|
|
29
|
+
import { IWorkspaceContextService } from '@codingame/monaco-vscode-api/vscode/vs/platform/workspace/common/workspace.service';
|
|
30
|
+
import { IHistoryService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/history/common/history.service';
|
|
31
|
+
import { IRemoteAgentService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/remote/common/remoteAgentService.service';
|
|
32
|
+
import { IAgentSessionsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsService.service';
|
|
33
|
+
import { IChatWidgetService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/chat.service';
|
|
34
|
+
import { TerminalToolConfirmationStorageKeys } from '../../../../chat/browser/widget/chatContentParts/toolInvocationParts/chatTerminalToolConfirmationSubPart.js';
|
|
35
|
+
import { ElicitationState, ChatRequestQueueKind } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatService/chatService';
|
|
36
|
+
import { IChatService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatService/chatService.service';
|
|
37
|
+
import { LanguageModelPartAudience } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModels';
|
|
38
|
+
import { ChatModel } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/model/chatModel';
|
|
39
|
+
import { ChatElicitationRequestPart } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/model/chatProgressTypes/chatElicitationRequestPart';
|
|
40
|
+
import { ChatQuestionCarouselData } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/model/chatProgressTypes/chatQuestionCarouselData';
|
|
41
|
+
import { LocalChatSessionUri, chatSessionResourceToId } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/model/chatUri';
|
|
42
|
+
import { ToolDataSource, ToolInvocationPresentation } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/tools/languageModelToolsService';
|
|
43
|
+
import { ILanguageModelToolsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/tools/languageModelToolsService.service';
|
|
44
|
+
import { ITerminalChatService, ITerminalService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/terminal/browser/terminal.service';
|
|
45
|
+
import { ITerminalProfileResolverService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/terminal/common/terminal.service';
|
|
46
|
+
import { TerminalChatCommandId } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat';
|
|
47
|
+
import { TerminalChatAgentToolsSettingId } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalChatAgentToolsConfiguration';
|
|
48
|
+
import '../../common/terminalSandboxService.js';
|
|
49
|
+
import { getRecommendedToolsOverRunInTerminal } from '../alternativeRecommendation.js';
|
|
50
|
+
import { BasicExecuteStrategy } from '../executeStrategy/basicExecuteStrategy.js';
|
|
51
|
+
import { NoneExecuteStrategy } from '../executeStrategy/noneExecuteStrategy.js';
|
|
52
|
+
import { RichExecuteStrategy } from '../executeStrategy/richExecuteStrategy.js';
|
|
53
|
+
import { getOutput } from '../outputHelpers.js';
|
|
54
|
+
import { isWindowsPowerShell, isPowerShell, isZsh, isFish, buildCommandDisplayText, normalizeTerminalCommandForDisplay, extractCdPrefix } from '../runInTerminalHelpers.js';
|
|
55
|
+
import { RunInTerminalToolTelemetry } from '../runInTerminalToolTelemetry.js';
|
|
56
|
+
import { ToolTerminalCreator, ShellIntegrationQuality } from '../toolTerminalCreator.js';
|
|
57
|
+
import { TreeSitterCommandParser, TreeSitterCommandParserLanguage } from '../treeSitterCommandParser.js';
|
|
58
|
+
import { CommandLineAutoApproveAnalyzer } from './commandLineAnalyzer/commandLineAutoApproveAnalyzer.js';
|
|
59
|
+
import { CommandLineFileWriteAnalyzer } from './commandLineAnalyzer/commandLineFileWriteAnalyzer.js';
|
|
60
|
+
import { CommandLineSandboxAnalyzer } from './commandLineAnalyzer/commandLineSandboxAnalyzer.js';
|
|
61
|
+
import { NodeCommandLinePresenter } from './commandLinePresenter/nodeCommandLinePresenter.js';
|
|
62
|
+
import { PythonCommandLinePresenter } from './commandLinePresenter/pythonCommandLinePresenter.js';
|
|
63
|
+
import { RubyCommandLinePresenter } from './commandLinePresenter/rubyCommandLinePresenter.js';
|
|
64
|
+
import { SandboxedCommandLinePresenter } from './commandLinePresenter/sandboxedCommandLinePresenter.js';
|
|
65
|
+
import { CommandLineBackgroundDetachRewriter } from './commandLineRewriter/commandLineBackgroundDetachRewriter.js';
|
|
66
|
+
import { CommandLineCdPrefixRewriter } from './commandLineRewriter/commandLineCdPrefixRewriter.js';
|
|
67
|
+
import { CommandLinePreventHistoryRewriter } from './commandLineRewriter/commandLinePreventHistoryRewriter.js';
|
|
68
|
+
import { CommandLinePwshChainOperatorRewriter } from './commandLineRewriter/commandLinePwshChainOperatorRewriter.js';
|
|
69
|
+
import { CommandLineSandboxRewriter } from './commandLineRewriter/commandLineSandboxRewriter.js';
|
|
70
|
+
import { OutputMonitor } from './monitoring/outputMonitor.js';
|
|
71
|
+
import { OutputMonitorState } from './monitoring/types.js';
|
|
72
|
+
import { outputLooksSandboxBlocked, SandboxOutputAnalyzer } from './sandboxOutputAnalyzer.js';
|
|
73
|
+
import { TerminalCommandArtifactCollector } from './terminalCommandArtifactCollector.js';
|
|
74
|
+
import { isToolEligibleForTerminalAutoApproval, isTerminalAutoApproveAllowed, isSessionAutoApproveLevel } from './terminalToolAutoApprove.js';
|
|
75
|
+
import { TerminalToolId } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/tools/terminalToolIds';
|
|
76
|
+
import { TerminalSandboxPrerequisiteCheck } from '../../../../../../platform/sandbox/common/terminalSandboxService.js';
|
|
77
|
+
import { autorun } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/reactions/autorun';
|
|
78
|
+
import { ITerminalSandboxService } from '@codingame/monaco-vscode-api/vscode/vs/platform/sandbox/common/terminalSandboxService.service';
|
|
79
|
+
import { constObservable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/constObservable';
|
|
80
|
+
|
|
81
|
+
var RunInTerminalTool_1;
|
|
82
|
+
const TERMINAL_SANDBOX_DOCUMENTATION_URL = "https://aka.ms/vscode-sandboxing";
|
|
83
|
+
const TOOL_REFERENCE_NAME = "runInTerminal";
|
|
84
|
+
const LEGACY_TOOL_REFERENCE_FULL_NAMES = ["runCommands/runInTerminal"];
|
|
85
|
+
const INPUT_NEEDED_NOTIFICATION_THROTTLE_MS = 5000;
|
|
86
|
+
function createPowerShellModelDescription(shell, isSandboxEnabled, networkDomains) {
|
|
87
|
+
const isWinPwsh = isWindowsPowerShell(shell);
|
|
88
|
+
const parts = [
|
|
89
|
+
`This tool allows you to execute ${isWinPwsh ? "Windows PowerShell 5.1" : "PowerShell"} commands in a persistent terminal session, preserving environment variables, working directory, and other context across multiple commands.`,
|
|
90
|
+
"",
|
|
91
|
+
"Command Execution:",
|
|
92
|
+
isWinPwsh ? "- Use semicolons ; to chain commands on one line, NEVER use && even when asked explicitly" : "- Prefer ; when chaining commands on one line",
|
|
93
|
+
"- Prefer pipelines | for object-based data flow",
|
|
94
|
+
"- Never create a sub-shell (eg. powershell -c \"command\") unless explicitly asked",
|
|
95
|
+
"",
|
|
96
|
+
"Directory Management:",
|
|
97
|
+
"- Prefer relative paths when navigating directories, only use absolute when the path is far away or the current cwd is not expected",
|
|
98
|
+
"- By default (mode=sync), shell and cwd are reused by subsequent sync commands",
|
|
99
|
+
"- Use $PWD or Get-Location for current directory",
|
|
100
|
+
"- Use Push-Location/Pop-Location for directory stack",
|
|
101
|
+
"",
|
|
102
|
+
"Program Execution:",
|
|
103
|
+
"- Supports .NET, Python, Node.js, and other executables",
|
|
104
|
+
"- Install modules via Install-Module, Install-Package",
|
|
105
|
+
"- Use Get-Command to verify cmdlet/function availability",
|
|
106
|
+
"",
|
|
107
|
+
"Async Mode:",
|
|
108
|
+
"- For long-running tasks (e.g., servers), use mode=async",
|
|
109
|
+
"- Returns a terminal ID for checking status and runtime later",
|
|
110
|
+
"- Use Start-Job for background PowerShell jobs",
|
|
111
|
+
"",
|
|
112
|
+
`Use ${TerminalToolId.SendToTerminal} to send commands or input to a terminal session.`
|
|
113
|
+
];
|
|
114
|
+
if (isSandboxEnabled) {
|
|
115
|
+
parts.push(...createSandboxLines(networkDomains));
|
|
116
|
+
}
|
|
117
|
+
parts.push(
|
|
118
|
+
"",
|
|
119
|
+
"Output Management:",
|
|
120
|
+
"- Output is automatically truncated if longer than 60KB to prevent context overflow",
|
|
121
|
+
"- Use Select-Object, Where-Object, Format-Table to filter output",
|
|
122
|
+
"- Use -First/-Last parameters to limit results",
|
|
123
|
+
"- For pager commands, add | Out-String or | Format-List",
|
|
124
|
+
"",
|
|
125
|
+
"Best Practices:",
|
|
126
|
+
"- Use proper cmdlet names instead of aliases in scripts",
|
|
127
|
+
"- Quote paths with spaces: \"C:\\Path With Spaces\"",
|
|
128
|
+
"- Prefer PowerShell cmdlets over external commands when available",
|
|
129
|
+
"- Prefer idiomatic PowerShell like Get-ChildItem instead of dir or ls for file listings",
|
|
130
|
+
"- Use Test-Path to check file/directory existence",
|
|
131
|
+
"- Be specific with Select-Object properties to avoid excessive output",
|
|
132
|
+
"- Avoid printing credentials unless absolutely required",
|
|
133
|
+
`- NEVER run Start-Sleep or similar wait commands. You will be automatically notified on your next turn when async terminal commands or timed-out sync commands complete or need input. Use ${TerminalToolId.GetTerminalOutput} to check output before then`,
|
|
134
|
+
"",
|
|
135
|
+
"Interactive Input Handling:",
|
|
136
|
+
"- When a terminal command is waiting for interactive input, do NOT suggest alternatives or ask the user whether to proceed. Instead, use the vscode_askQuestions tool to collect the needed values from the user, then send them.",
|
|
137
|
+
`- Send exactly one answer per prompt using ${TerminalToolId.SendToTerminal}. Never send multiple answers in a single send.`,
|
|
138
|
+
`- After each send, call ${TerminalToolId.GetTerminalOutput} to read the next prompt before sending the next answer.`,
|
|
139
|
+
"- Continue one prompt at a time until the command finishes."
|
|
140
|
+
);
|
|
141
|
+
return parts.join("\n");
|
|
142
|
+
}
|
|
143
|
+
function createSandboxLines(networkDomains) {
|
|
144
|
+
const lines = [
|
|
145
|
+
"",
|
|
146
|
+
"Sandboxing:",
|
|
147
|
+
"- ATTENTION: Terminal sandboxing is enabled, commands run in a sandbox by default",
|
|
148
|
+
"- When executing commands within the sandboxed environment, all operations requiring a temporary directory must utilize the $TMPDIR environment variable. The /tmp directory is not guaranteed to be accessible or writable and must be avoided",
|
|
149
|
+
"- Tools and scripts should respect the TMPDIR environment variable, which is automatically set to an appropriate path within the sandbox",
|
|
150
|
+
"- When a command fails due to sandbox restrictions, immediately re-run it with requestUnsandboxedExecution=true. Do NOT ask the user for permission — setting this flag automatically shows a confirmation prompt to the user",
|
|
151
|
+
"- Only set requestUnsandboxedExecution=true when there is evidence of failures caused by the sandbox, e.g. 'Operation not permitted' errors, network failures, or file access errors, etc",
|
|
152
|
+
"- Do NOT set requestUnsandboxedExecution=true without first executing the command in sandbox mode. Always try the command in the sandbox first, and only set requestUnsandboxedExecution=true when retrying after that sandboxed execution failed due to sandbox restrictions.",
|
|
153
|
+
"- When setting requestUnsandboxedExecution=true, also provide requestUnsandboxedExecutionReason explaining why the command needs unsandboxed access"
|
|
154
|
+
];
|
|
155
|
+
if (networkDomains) {
|
|
156
|
+
const deniedSet = ( new Set(networkDomains.deniedDomains));
|
|
157
|
+
const effectiveAllowed = networkDomains.allowedDomains.filter(d => !( deniedSet.has(d)));
|
|
158
|
+
if (effectiveAllowed.length === 0) {
|
|
159
|
+
lines.push("- All network access is blocked in the sandbox");
|
|
160
|
+
} else {
|
|
161
|
+
lines.push(
|
|
162
|
+
`- Only the following domains are accessible in the sandbox (all other network access is blocked): ${effectiveAllowed.join(", ")}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (networkDomains.deniedDomains.length > 0) {
|
|
166
|
+
lines.push(
|
|
167
|
+
`- The following domains are explicitly blocked in the sandbox: ${networkDomains.deniedDomains.join(", ")}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return lines;
|
|
172
|
+
}
|
|
173
|
+
function createGenericDescription(isSandboxEnabled, networkDomains) {
|
|
174
|
+
const parts = [`
|
|
175
|
+
Command Execution:
|
|
176
|
+
- Use && to chain simple commands on one line
|
|
177
|
+
- Prefer pipelines | over temporary files for data flow
|
|
178
|
+
- Never create a sub-shell (eg. bash -c "command") unless explicitly asked
|
|
179
|
+
|
|
180
|
+
Directory Management:
|
|
181
|
+
- Prefer relative paths when navigating directories, only use absolute when the path is far away or the current cwd is not expected
|
|
182
|
+
- By default (mode=sync), shell and cwd are reused by subsequent sync commands
|
|
183
|
+
- Use $PWD for current directory references
|
|
184
|
+
- Consider using pushd/popd for directory stack management
|
|
185
|
+
- Supports directory shortcuts like ~ and -
|
|
186
|
+
|
|
187
|
+
Program Execution:
|
|
188
|
+
- Supports Python, Node.js, and other executables
|
|
189
|
+
- Install packages via package managers (brew, apt, etc.)
|
|
190
|
+
- Use which or command -v to verify command availability
|
|
191
|
+
|
|
192
|
+
Async Mode:
|
|
193
|
+
- For long-running tasks (e.g., servers), use mode=async
|
|
194
|
+
- Returns a terminal ID for checking status and runtime later
|
|
195
|
+
|
|
196
|
+
Use ${TerminalToolId.SendToTerminal} to send commands or input to a terminal session.`];
|
|
197
|
+
if (isSandboxEnabled) {
|
|
198
|
+
parts.push(createSandboxLines(networkDomains).join("\n"));
|
|
199
|
+
}
|
|
200
|
+
parts.push(`
|
|
201
|
+
|
|
202
|
+
Output Management:
|
|
203
|
+
- Output is automatically truncated if longer than 60KB to prevent context overflow
|
|
204
|
+
- Use head, tail, grep, awk to filter and limit output size
|
|
205
|
+
- For pager commands, disable paging: git --no-pager or add | cat
|
|
206
|
+
- Use wc -l to count lines before displaying large outputs
|
|
207
|
+
|
|
208
|
+
Best Practices:
|
|
209
|
+
- Quote variables: "$var" instead of $var to handle spaces
|
|
210
|
+
- Use find with -exec or xargs for file operations
|
|
211
|
+
- Be specific with commands to avoid excessive output
|
|
212
|
+
- Avoid printing credentials unless absolutely required
|
|
213
|
+
- NEVER run sleep or similar wait commands in a terminal. You will be automatically notified on your next turn when async terminal commands or timed-out sync commands complete or need input. Use ${TerminalToolId.GetTerminalOutput} to check output before then
|
|
214
|
+
|
|
215
|
+
Interactive Input Handling:
|
|
216
|
+
- When a terminal command is waiting for interactive input, do NOT suggest alternatives or ask the user whether to proceed. Instead, use the vscode_askQuestions tool to collect the needed values from the user, then send them.
|
|
217
|
+
- Send exactly one answer per prompt using ${TerminalToolId.SendToTerminal}. Never send multiple answers in a single send.
|
|
218
|
+
- After each send, call ${TerminalToolId.GetTerminalOutput} to read the next prompt before sending the next answer.
|
|
219
|
+
- Continue one prompt at a time until the command finishes.`);
|
|
220
|
+
return parts.join("");
|
|
221
|
+
}
|
|
222
|
+
function createBashModelDescription(isSandboxEnabled, networkDomains) {
|
|
223
|
+
return [
|
|
224
|
+
"This tool allows you to execute shell commands in a persistent bash terminal session, preserving environment variables, working directory, and other context across multiple commands.",
|
|
225
|
+
createGenericDescription(isSandboxEnabled, networkDomains),
|
|
226
|
+
"- Use [[ ]] for conditional tests instead of [ ]",
|
|
227
|
+
"- Prefer $() over backticks for command substitution",
|
|
228
|
+
"- Use set -e at start of complex commands to exit on errors"
|
|
229
|
+
].join("\n");
|
|
230
|
+
}
|
|
231
|
+
function createZshModelDescription(isSandboxEnabled, networkDomains) {
|
|
232
|
+
return [
|
|
233
|
+
"This tool allows you to execute shell commands in a persistent zsh terminal session, preserving environment variables, working directory, and other context across multiple commands.",
|
|
234
|
+
createGenericDescription(isSandboxEnabled, networkDomains),
|
|
235
|
+
"- Use type to check command type (builtin, function, alias)",
|
|
236
|
+
"- Use jobs, fg, bg for job control",
|
|
237
|
+
"- Use [[ ]] for conditional tests instead of [ ]",
|
|
238
|
+
"- Prefer $() over backticks for command substitution",
|
|
239
|
+
"- Use setopt errexit for strict error handling",
|
|
240
|
+
"- Take advantage of zsh globbing features (**, extended globs)"
|
|
241
|
+
].join("\n");
|
|
242
|
+
}
|
|
243
|
+
function createFishModelDescription(isSandboxEnabled, networkDomains) {
|
|
244
|
+
return [
|
|
245
|
+
"This tool allows you to execute shell commands in a persistent fish terminal session, preserving environment variables, working directory, and other context across multiple commands.",
|
|
246
|
+
createGenericDescription(isSandboxEnabled, networkDomains),
|
|
247
|
+
"- Use type to check command type (builtin, function, alias)",
|
|
248
|
+
"- Use jobs, fg, bg for job control",
|
|
249
|
+
"- Use test expressions for conditionals (no [[ ]] syntax)",
|
|
250
|
+
"- Prefer command substitution with () syntax",
|
|
251
|
+
"- Variables are arrays by default, use $var[1] for first element",
|
|
252
|
+
"- Use set -e for strict error handling",
|
|
253
|
+
"- Take advantage of fish's autosuggestions and completions"
|
|
254
|
+
].join("\n");
|
|
255
|
+
}
|
|
256
|
+
async function createRunInTerminalToolData(accessor) {
|
|
257
|
+
const instantiationService = accessor.get(IInstantiationService);
|
|
258
|
+
const terminalSandboxService = accessor.get(ITerminalSandboxService);
|
|
259
|
+
const profileFetcher = instantiationService.createInstance(TerminalProfileFetcher);
|
|
260
|
+
const [shell, os, isSandboxEnabled] = await Promise.all([
|
|
261
|
+
profileFetcher.getCopilotShell(),
|
|
262
|
+
profileFetcher.osBackend,
|
|
263
|
+
terminalSandboxService.isEnabled()
|
|
264
|
+
]);
|
|
265
|
+
const networkDomains = isSandboxEnabled ? terminalSandboxService.getResolvedNetworkDomains() : undefined;
|
|
266
|
+
let modelDescription;
|
|
267
|
+
if (shell && os && isPowerShell(shell, os)) {
|
|
268
|
+
modelDescription = createPowerShellModelDescription(shell, isSandboxEnabled, networkDomains);
|
|
269
|
+
} else if (shell && os && isZsh(shell, os)) {
|
|
270
|
+
modelDescription = createZshModelDescription(isSandboxEnabled, networkDomains);
|
|
271
|
+
} else if (shell && os && isFish(shell, os)) {
|
|
272
|
+
modelDescription = createFishModelDescription(isSandboxEnabled, networkDomains);
|
|
273
|
+
} else {
|
|
274
|
+
modelDescription = createBashModelDescription(isSandboxEnabled, networkDomains);
|
|
275
|
+
}
|
|
276
|
+
const sharedProperties = {
|
|
277
|
+
command: {
|
|
278
|
+
type: "string",
|
|
279
|
+
description: "The command to run in the terminal."
|
|
280
|
+
},
|
|
281
|
+
explanation: {
|
|
282
|
+
type: "string",
|
|
283
|
+
description: "A one-sentence description of what the command does. This will be shown to the user before the command is run."
|
|
284
|
+
},
|
|
285
|
+
goal: {
|
|
286
|
+
type: "string",
|
|
287
|
+
description: "A short description of the goal or purpose of the command (e.g., \"Install dependencies\", \"Start development server\")."
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const sandboxProperties = isSandboxEnabled ? {
|
|
291
|
+
requestUnsandboxedExecution: {
|
|
292
|
+
type: "boolean",
|
|
293
|
+
description: "Request that this command run outside the terminal sandbox. Only set this after first executing the command in sandbox and observing that sandboxing caused the failure. The user will be prompted before the command runs unsandboxed."
|
|
294
|
+
},
|
|
295
|
+
requestUnsandboxedExecutionReason: {
|
|
296
|
+
type: "string",
|
|
297
|
+
description: "A short explanation of the sandboxed execution failure or blocked-domain requirement that justifies retrying outside the sandbox. Only provide this when requestUnsandboxedExecution is true."
|
|
298
|
+
}
|
|
299
|
+
} : {};
|
|
300
|
+
return {
|
|
301
|
+
id: TerminalToolId.RunInTerminal,
|
|
302
|
+
toolReferenceName: TOOL_REFERENCE_NAME,
|
|
303
|
+
legacyToolReferenceFullNames: LEGACY_TOOL_REFERENCE_FULL_NAMES,
|
|
304
|
+
displayName: ( localize(14038, "Run in Terminal")),
|
|
305
|
+
modelDescription: `${modelDescription}\n\nExecution mode:\n- mode='sync': wait for completion up to timeout; if still running, return with a terminal ID.\n- mode='async': wait for an initial idle/output signal, then return with terminal output snapshot and ID. Timeout caps how long to wait for the initial idle/output signal.\n- Prefer mode='sync' for commands that will prompt for interactive input (e.g., npm init, interactive installers, configuration wizards).\n\nTerminal notifications: When an async command finishes or a sync command times out, you will be automatically notified on your next turn with the exit code and terminal output. You will also be notified if the terminal needs input. Use ${TerminalToolId.GetTerminalOutput} to check output before then. Do NOT poll or sleep to wait for completion.`,
|
|
306
|
+
userDescription: ( localize(14039, "Run commands in the terminal")),
|
|
307
|
+
source: ToolDataSource.Internal,
|
|
308
|
+
icon: Codicon.terminal,
|
|
309
|
+
inputSchema: {
|
|
310
|
+
type: "object",
|
|
311
|
+
properties: {
|
|
312
|
+
...sharedProperties,
|
|
313
|
+
...sandboxProperties,
|
|
314
|
+
mode: {
|
|
315
|
+
type: "string",
|
|
316
|
+
enum: ["sync", "async"],
|
|
317
|
+
enumDescriptions: [
|
|
318
|
+
"Wait for completion up to timeout, then return with collected output. If still running at timeout, the terminal session continues in the background.",
|
|
319
|
+
"Wait for an initial idle/output signal, then return with a terminal ID and output snapshot while the session may continue running."
|
|
320
|
+
],
|
|
321
|
+
description: "Execution mode for this command."
|
|
322
|
+
},
|
|
323
|
+
isBackground: {
|
|
324
|
+
type: "boolean",
|
|
325
|
+
description: "Legacy execution mode flag. Deprecated in favor of \"mode\". If true, equivalent to mode=async. If false, equivalent to mode=sync."
|
|
326
|
+
},
|
|
327
|
+
timeout: {
|
|
328
|
+
type: "number",
|
|
329
|
+
description: "Timeout in milliseconds that determines how long to wait before returning. Use 0 for no timeout."
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
required: ["command", "explanation", "goal", "mode", "timeout"]
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
var TerminalToolStorageKeysInternal;
|
|
337
|
+
(function(TerminalToolStorageKeysInternal) {
|
|
338
|
+
TerminalToolStorageKeysInternal["TerminalSession"] = "chat.terminalSessions";
|
|
339
|
+
})(TerminalToolStorageKeysInternal || (TerminalToolStorageKeysInternal = {}));
|
|
340
|
+
function shouldAutomaticallyRetryUnsandboxed(options) {
|
|
341
|
+
return options.didSandboxWrapCommand && options.requestUnsandboxedExecution !== true && !options.isPersistentSession && !options.isBackgroundExecution && !options.didTimeout && options.exitCode !== 0 && outputLooksSandboxBlocked(options.output);
|
|
342
|
+
}
|
|
343
|
+
const telemetryIgnoredSequences = [
|
|
344
|
+
"\u001b[I",
|
|
345
|
+
"\u001b[O"];
|
|
346
|
+
const altBufferMessage = "\n" + ( localize(14040, "The command opened the alternate buffer."));
|
|
347
|
+
let RunInTerminalTool = class RunInTerminalTool extends Disposable {
|
|
348
|
+
static {
|
|
349
|
+
RunInTerminalTool_1 = this;
|
|
350
|
+
}
|
|
351
|
+
static {
|
|
352
|
+
this._activeExecutions = ( new Map());
|
|
353
|
+
}
|
|
354
|
+
static getBackgroundOutput(id) {
|
|
355
|
+
const execution = RunInTerminalTool_1._activeExecutions.get(id);
|
|
356
|
+
if (!execution) {
|
|
357
|
+
throw ( new Error("Invalid terminal ID"));
|
|
358
|
+
}
|
|
359
|
+
return execution.getOutput();
|
|
360
|
+
}
|
|
361
|
+
static getExecution(id) {
|
|
362
|
+
return RunInTerminalTool_1._activeExecutions.get(id);
|
|
363
|
+
}
|
|
364
|
+
static removeExecution(id) {
|
|
365
|
+
const execution = RunInTerminalTool_1._activeExecutions.get(id);
|
|
366
|
+
if (!execution) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
execution.dispose();
|
|
370
|
+
RunInTerminalTool_1._activeExecutions.delete(id);
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
_resolveExecutionOptions(args) {
|
|
374
|
+
const mode = args.mode ?? (args.isBackground ? "async" : "sync");
|
|
375
|
+
switch (mode) {
|
|
376
|
+
case "async":
|
|
377
|
+
return {
|
|
378
|
+
mode: "async",
|
|
379
|
+
persistentSession: true,
|
|
380
|
+
waitStrategy: "idle"
|
|
381
|
+
};
|
|
382
|
+
case "sync":
|
|
383
|
+
default:
|
|
384
|
+
return {
|
|
385
|
+
mode: "sync",
|
|
386
|
+
persistentSession: false,
|
|
387
|
+
waitStrategy: "completion"
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
get _enableCommandLineSandboxRewriting() {
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
constructor(
|
|
395
|
+
_chatService,
|
|
396
|
+
_configurationService,
|
|
397
|
+
_fileService,
|
|
398
|
+
_historyService,
|
|
399
|
+
_instantiationService,
|
|
400
|
+
_labelService,
|
|
401
|
+
_languageModelToolsService,
|
|
402
|
+
_remoteAgentService,
|
|
403
|
+
_storageService,
|
|
404
|
+
_terminalChatService,
|
|
405
|
+
_logService,
|
|
406
|
+
_terminalService,
|
|
407
|
+
_terminalSandboxService,
|
|
408
|
+
_workspaceContextService,
|
|
409
|
+
_chatWidgetService,
|
|
410
|
+
_agentSessionsService
|
|
411
|
+
) {
|
|
412
|
+
super();
|
|
413
|
+
this._chatService = _chatService;
|
|
414
|
+
this._configurationService = _configurationService;
|
|
415
|
+
this._fileService = _fileService;
|
|
416
|
+
this._historyService = _historyService;
|
|
417
|
+
this._instantiationService = _instantiationService;
|
|
418
|
+
this._labelService = _labelService;
|
|
419
|
+
this._languageModelToolsService = _languageModelToolsService;
|
|
420
|
+
this._remoteAgentService = _remoteAgentService;
|
|
421
|
+
this._storageService = _storageService;
|
|
422
|
+
this._terminalChatService = _terminalChatService;
|
|
423
|
+
this._logService = _logService;
|
|
424
|
+
this._terminalService = _terminalService;
|
|
425
|
+
this._terminalSandboxService = _terminalSandboxService;
|
|
426
|
+
this._workspaceContextService = _workspaceContextService;
|
|
427
|
+
this._chatWidgetService = _chatWidgetService;
|
|
428
|
+
this._agentSessionsService = _agentSessionsService;
|
|
429
|
+
this._archivedSessionListener = this._register(( new MutableDisposable()));
|
|
430
|
+
this._sessionTerminalAssociations = ( new ResourceMap());
|
|
431
|
+
this._sessionTerminalInstances = ( new ResourceMap());
|
|
432
|
+
this._terminalsBeingDisposedBySessionCleanup = ( new Set());
|
|
433
|
+
this._backgroundNotifications = this._register(( new DisposableMap()));
|
|
434
|
+
this._osBackend = this._remoteAgentService.getEnvironment().then(remoteEnv => remoteEnv?.os ?? OS);
|
|
435
|
+
this._terminalToolCreator = this._instantiationService.createInstance(ToolTerminalCreator);
|
|
436
|
+
this._treeSitterCommandParser = this._register(this._instantiationService.createInstance(TreeSitterCommandParser));
|
|
437
|
+
this._telemetry = this._instantiationService.createInstance(RunInTerminalToolTelemetry);
|
|
438
|
+
this._commandArtifactCollector = this._instantiationService.createInstance(TerminalCommandArtifactCollector);
|
|
439
|
+
this._profileFetcher = this._instantiationService.createInstance(TerminalProfileFetcher);
|
|
440
|
+
this._commandLineRewriters = [
|
|
441
|
+
this._register(this._instantiationService.createInstance(CommandLineCdPrefixRewriter)),
|
|
442
|
+
this._register(
|
|
443
|
+
this._instantiationService.createInstance(CommandLinePwshChainOperatorRewriter, this._treeSitterCommandParser)
|
|
444
|
+
)
|
|
445
|
+
];
|
|
446
|
+
if (this._enableCommandLineSandboxRewriting) {
|
|
447
|
+
this._commandLineRewriters.push(
|
|
448
|
+
this._register(this._instantiationService.createInstance(CommandLineSandboxRewriter))
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
this._commandLineRewriters.push(this._register(
|
|
452
|
+
this._instantiationService.createInstance(CommandLineBackgroundDetachRewriter)
|
|
453
|
+
));
|
|
454
|
+
this._commandLineRewriters.push(this._register(
|
|
455
|
+
this._instantiationService.createInstance(CommandLinePreventHistoryRewriter)
|
|
456
|
+
));
|
|
457
|
+
this._commandLineAnalyzers = [this._register(this._instantiationService.createInstance(
|
|
458
|
+
CommandLineFileWriteAnalyzer,
|
|
459
|
+
this._treeSitterCommandParser,
|
|
460
|
+
(message, args) => this._logService.info(`RunInTerminalTool#CommandLineFileWriteAnalyzer: ${message}`, args)
|
|
461
|
+
)), this._register(this._instantiationService.createInstance(
|
|
462
|
+
CommandLineAutoApproveAnalyzer,
|
|
463
|
+
this._treeSitterCommandParser,
|
|
464
|
+
this._telemetry,
|
|
465
|
+
(message, args) => this._logService.info(`RunInTerminalTool#CommandLineAutoApproveAnalyzer: ${message}`, args)
|
|
466
|
+
))];
|
|
467
|
+
if (this._enableCommandLineSandboxRewriting) {
|
|
468
|
+
this._commandLineAnalyzers.push(
|
|
469
|
+
this._register(this._instantiationService.createInstance(CommandLineSandboxAnalyzer))
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
this._commandLinePresenters = [
|
|
473
|
+
this._instantiationService.createInstance(SandboxedCommandLinePresenter),
|
|
474
|
+
( new NodeCommandLinePresenter()),
|
|
475
|
+
( new PythonCommandLinePresenter()),
|
|
476
|
+
( new RubyCommandLinePresenter())
|
|
477
|
+
];
|
|
478
|
+
this._outputAnalyzers = [
|
|
479
|
+
this._register(this._instantiationService.createInstance(SandboxOutputAnalyzer))
|
|
480
|
+
];
|
|
481
|
+
this._register(
|
|
482
|
+
Event.runAndSubscribe(this._configurationService.onDidChangeConfiguration, e => {
|
|
483
|
+
if (!e || e.affectsConfiguration(TerminalChatAgentToolsSettingId.EnableAutoApprove)) {
|
|
484
|
+
if (this._configurationService.getValue(TerminalChatAgentToolsSettingId.EnableAutoApprove) !== true) {
|
|
485
|
+
this._storageService.remove(
|
|
486
|
+
TerminalToolConfirmationStorageKeys.TerminalAutoApproveWarningAccepted,
|
|
487
|
+
StorageScope.APPLICATION
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
})
|
|
492
|
+
);
|
|
493
|
+
this._restoreTerminalAssociations();
|
|
494
|
+
this._register(this._terminalService.onDidDisposeInstance(e => {
|
|
495
|
+
this._removeTerminalAssociations(e);
|
|
496
|
+
}));
|
|
497
|
+
this._register(this._chatService.onDidDisposeSession(e => {
|
|
498
|
+
for (const resource of e.sessionResources) {
|
|
499
|
+
this._cleanupSessionTerminals(resource);
|
|
500
|
+
}
|
|
501
|
+
}));
|
|
502
|
+
}
|
|
503
|
+
async handleToolStream(context, _token) {
|
|
504
|
+
const partialInput = context.rawInput;
|
|
505
|
+
if (partialInput && typeof partialInput === "object" && partialInput.command) {
|
|
506
|
+
const truncatedCommand = buildCommandDisplayText(partialInput.command);
|
|
507
|
+
const invocationMessage = ( new MarkdownString(( localize(14041, "Running `{0}`", escapeMarkdownSyntaxTokens(truncatedCommand)))));
|
|
508
|
+
return {
|
|
509
|
+
invocationMessage
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
invocationMessage: ( localize(14042, "Running command"))
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
async prepareToolInvocation(context, token) {
|
|
517
|
+
const args = context.parameters;
|
|
518
|
+
const executionOptions = this._resolveExecutionOptions(args);
|
|
519
|
+
const chatSessionResource = context.chatSessionResource;
|
|
520
|
+
let instance;
|
|
521
|
+
if (chatSessionResource) {
|
|
522
|
+
const toolTerminal = this._sessionTerminalAssociations.get(chatSessionResource);
|
|
523
|
+
if (toolTerminal && !toolTerminal.isBackground) {
|
|
524
|
+
instance = toolTerminal.instance;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const [os, shell, cwd, sandboxPrereqs] = await Promise.all([this._osBackend, this._profileFetcher.getCopilotShell(), (async () => {
|
|
528
|
+
let cwd = await instance?.getCwdResource();
|
|
529
|
+
if (!cwd) {
|
|
530
|
+
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
|
|
531
|
+
const workspaceFolder = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined;
|
|
532
|
+
cwd = workspaceFolder?.uri;
|
|
533
|
+
}
|
|
534
|
+
return cwd;
|
|
535
|
+
})(), this._terminalSandboxService.checkForSandboxingPrereqs()]);
|
|
536
|
+
const language = os === OperatingSystem.Windows ? "pwsh" : "sh";
|
|
537
|
+
const isTerminalSandboxEnabled = sandboxPrereqs.enabled;
|
|
538
|
+
const explicitUnsandboxRequest = isTerminalSandboxEnabled && args.requestUnsandboxedExecution === true;
|
|
539
|
+
let requiresUnsandboxConfirmation = explicitUnsandboxRequest;
|
|
540
|
+
let requestUnsandboxedExecutionReason = explicitUnsandboxRequest ? args.requestUnsandboxedExecutionReason : undefined;
|
|
541
|
+
const missingDependencies = sandboxPrereqs.failedCheck === TerminalSandboxPrerequisiteCheck.Dependencies && sandboxPrereqs.missingDependencies?.length ? sandboxPrereqs.missingDependencies : undefined;
|
|
542
|
+
const terminalToolSessionId = generateUuid();
|
|
543
|
+
const terminalCommandId = `tool-${generateUuid()}`;
|
|
544
|
+
const rewriteResult = await this._rewriteCommandLine(args.command, {
|
|
545
|
+
cwd,
|
|
546
|
+
shell,
|
|
547
|
+
os,
|
|
548
|
+
isBackground: executionOptions.persistentSession,
|
|
549
|
+
requestUnsandboxedExecution: requiresUnsandboxConfirmation,
|
|
550
|
+
requestUnsandboxedExecutionReason
|
|
551
|
+
});
|
|
552
|
+
const rewrittenCommand = rewriteResult.rewrittenCommand;
|
|
553
|
+
const forDisplayCommand = rewriteResult.forDisplayCommand;
|
|
554
|
+
const isSandboxWrapped = rewriteResult.isSandboxWrapped;
|
|
555
|
+
requiresUnsandboxConfirmation = rewriteResult.requiresUnsandboxConfirmation;
|
|
556
|
+
requestUnsandboxedExecutionReason = rewriteResult.requestUnsandboxedExecutionReason;
|
|
557
|
+
const blockedDomains = rewriteResult.blockedDomains;
|
|
558
|
+
const toolSpecificData = {
|
|
559
|
+
kind: "terminal",
|
|
560
|
+
terminalToolSessionId,
|
|
561
|
+
terminalCommandId,
|
|
562
|
+
commandLine: {
|
|
563
|
+
original: args.command,
|
|
564
|
+
toolEdited: rewrittenCommand === args.command ? undefined : rewrittenCommand,
|
|
565
|
+
forDisplay: forDisplayCommand ?? normalizeTerminalCommandForDisplay(rewrittenCommand ?? args.command),
|
|
566
|
+
isSandboxWrapped
|
|
567
|
+
},
|
|
568
|
+
cwd,
|
|
569
|
+
language,
|
|
570
|
+
isBackground: executionOptions.persistentSession,
|
|
571
|
+
requestUnsandboxedExecution: requiresUnsandboxConfirmation,
|
|
572
|
+
requestUnsandboxedExecutionReason,
|
|
573
|
+
missingSandboxDependencies: missingDependencies
|
|
574
|
+
};
|
|
575
|
+
let sandboxConfirmationMessageForMissingDeps = undefined;
|
|
576
|
+
if (missingDependencies) {
|
|
577
|
+
const depsList = missingDependencies.join(", ");
|
|
578
|
+
sandboxConfirmationMessageForMissingDeps = {
|
|
579
|
+
title: ( localize(14043, "Missing Sandbox Dependencies")),
|
|
580
|
+
message: ( new MarkdownString(( localize(
|
|
581
|
+
14044,
|
|
582
|
+
"The following dependencies required for sandboxed execution are not installed: {0}. Would you like to install them?",
|
|
583
|
+
depsList
|
|
584
|
+
)))),
|
|
585
|
+
customButtons: [( localize(14045, "Install")), ( localize(14046, "Cancel"))]
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
const alternativeRecommendation = getRecommendedToolsOverRunInTerminal(args.command, this._languageModelToolsService);
|
|
589
|
+
if (alternativeRecommendation) {
|
|
590
|
+
toolSpecificData.alternativeRecommendation = alternativeRecommendation;
|
|
591
|
+
return {
|
|
592
|
+
confirmationMessages: undefined,
|
|
593
|
+
presentation: ToolInvocationPresentation.Hidden,
|
|
594
|
+
toolSpecificData
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
const commandLine = forDisplayCommand ?? rewrittenCommand ?? args.command;
|
|
598
|
+
const isEligibleForAutoApproval = () => isToolEligibleForTerminalAutoApproval(
|
|
599
|
+
TOOL_REFERENCE_NAME,
|
|
600
|
+
this._configurationService,
|
|
601
|
+
LEGACY_TOOL_REFERENCE_FULL_NAMES
|
|
602
|
+
);
|
|
603
|
+
const isAutoApproveEnabled = this._configurationService.getValue(TerminalChatAgentToolsSettingId.EnableAutoApprove) === true;
|
|
604
|
+
const isAutoApproveAllowed = isTerminalAutoApproveAllowed(
|
|
605
|
+
TOOL_REFERENCE_NAME,
|
|
606
|
+
this._configurationService,
|
|
607
|
+
this._storageService,
|
|
608
|
+
LEGACY_TOOL_REFERENCE_FULL_NAMES
|
|
609
|
+
);
|
|
610
|
+
const commandLineAnalyzerOptions = {
|
|
611
|
+
commandLine,
|
|
612
|
+
cwd,
|
|
613
|
+
os,
|
|
614
|
+
shell,
|
|
615
|
+
treeSitterLanguage: isPowerShell(shell, os) ? TreeSitterCommandParserLanguage.PowerShell : TreeSitterCommandParserLanguage.Bash,
|
|
616
|
+
terminalToolSessionId,
|
|
617
|
+
chatSessionResource,
|
|
618
|
+
requiresUnsandboxConfirmation
|
|
619
|
+
};
|
|
620
|
+
const isSessionAutoApproved = chatSessionResource && isSessionAutoApproveLevel(
|
|
621
|
+
chatSessionResource,
|
|
622
|
+
this._configurationService,
|
|
623
|
+
this._chatWidgetService,
|
|
624
|
+
this._chatService
|
|
625
|
+
);
|
|
626
|
+
const commandLineAnalyzers = isSessionAutoApproved ? this._commandLineAnalyzers.filter(e => !(e instanceof CommandLineAutoApproveAnalyzer)) : this._commandLineAnalyzers;
|
|
627
|
+
const commandLineAnalyzerResults = await Promise.all(( commandLineAnalyzers.map(e => e.analyze(commandLineAnalyzerOptions))));
|
|
628
|
+
const disclaimersRaw = ( commandLineAnalyzerResults.map(e => e.disclaimers)).filter(e => !!e).flatMap(e => e);
|
|
629
|
+
let disclaimer;
|
|
630
|
+
if (disclaimersRaw.length > 0) {
|
|
631
|
+
const disclaimerTexts = ( disclaimersRaw.map(d => typeof d === "string" ? d : d.value));
|
|
632
|
+
const hasMarkdownDisclaimer = ( disclaimersRaw.some(d => typeof d !== "string"));
|
|
633
|
+
const mdOptions = hasMarkdownDisclaimer ? {
|
|
634
|
+
supportThemeIcons: true,
|
|
635
|
+
isTrusted: {
|
|
636
|
+
enabledCommands: [TerminalChatCommandId.OpenTerminalSettingsLink]
|
|
637
|
+
}
|
|
638
|
+
} : {
|
|
639
|
+
supportThemeIcons: true
|
|
640
|
+
};
|
|
641
|
+
disclaimer = ( new MarkdownString(`$(${Codicon.info.id}) ` + disclaimerTexts.join(" "), mdOptions));
|
|
642
|
+
}
|
|
643
|
+
const analyzersIsAutoApproveAllowed = commandLineAnalyzerResults.every(e => e.isAutoApproveAllowed);
|
|
644
|
+
const customActions = isEligibleForAutoApproval() && analyzersIsAutoApproveAllowed ? ( commandLineAnalyzerResults.map(e => e.customActions ?? [])).flat() : undefined;
|
|
645
|
+
let shellType = basename(shell, ".exe");
|
|
646
|
+
if (shellType === "powershell") {
|
|
647
|
+
shellType = "pwsh";
|
|
648
|
+
}
|
|
649
|
+
const wouldBeAutoApproved =
|
|
650
|
+
(( commandLineAnalyzerResults.some(e => e.isAutoApproved)) &&
|
|
651
|
+
commandLineAnalyzerResults.every(e => e.isAutoApproved !== false) &&
|
|
652
|
+
analyzersIsAutoApproveAllowed);
|
|
653
|
+
const isAutoApprovedByRules =
|
|
654
|
+
(isAutoApproveAllowed &&
|
|
655
|
+
wouldBeAutoApproved);
|
|
656
|
+
const isFinalAutoApproved = isAutoApprovedByRules || ( commandLineAnalyzerResults.some(e => e.forceAutoApproval));
|
|
657
|
+
if (isFinalAutoApproved || (isAutoApproveEnabled && ( commandLineAnalyzerResults.some(e => e.autoApproveInfo)))) {
|
|
658
|
+
toolSpecificData.autoApproveInfo = commandLineAnalyzerResults.find(e => e.autoApproveInfo)?.autoApproveInfo;
|
|
659
|
+
}
|
|
660
|
+
const commandToDisplay = (toolSpecificData.commandLine.forDisplay ?? toolSpecificData.commandLine.userEdited ?? toolSpecificData.commandLine.toolEdited ?? toolSpecificData.commandLine.original).trimStart();
|
|
661
|
+
const extractedCd = extractCdPrefix(commandToDisplay, shell, os);
|
|
662
|
+
let confirmationTitle;
|
|
663
|
+
if (extractedCd && cwd) {
|
|
664
|
+
const isAbsolutePath = os === OperatingSystem.Windows ? win32.isAbsolute(extractedCd.directory) : posix.isAbsolute(extractedCd.directory);
|
|
665
|
+
const directoryUri = isAbsolutePath ? ( URI.from({
|
|
666
|
+
scheme: cwd.scheme,
|
|
667
|
+
authority: cwd.authority,
|
|
668
|
+
path: extractedCd.directory
|
|
669
|
+
})) : URI.joinPath(cwd, extractedCd.directory);
|
|
670
|
+
const directoryLabel = this._labelService.getUriLabel(directoryUri);
|
|
671
|
+
const cdPrefix = commandToDisplay.substring(0, commandToDisplay.length - extractedCd.command.length);
|
|
672
|
+
toolSpecificData.confirmation = {
|
|
673
|
+
commandLine: extractedCd.command,
|
|
674
|
+
cwdLabel: directoryLabel,
|
|
675
|
+
cdPrefix
|
|
676
|
+
};
|
|
677
|
+
confirmationTitle = ( localize(14047, "Run `{0}` command within `{1}`?", shellType, directoryLabel));
|
|
678
|
+
} else {
|
|
679
|
+
toolSpecificData.confirmation = {
|
|
680
|
+
commandLine: commandToDisplay
|
|
681
|
+
};
|
|
682
|
+
confirmationTitle = ( localize(14048, "Run `{0}` command?", shellType));
|
|
683
|
+
}
|
|
684
|
+
const commandForPresenter = extractedCd?.command ?? commandToDisplay;
|
|
685
|
+
let presenterInput = commandForPresenter;
|
|
686
|
+
for (const presenter of this._commandLinePresenters) {
|
|
687
|
+
const presenterResult = await presenter.present({
|
|
688
|
+
commandLine: {
|
|
689
|
+
original: args.command,
|
|
690
|
+
forDisplay: presenterInput
|
|
691
|
+
},
|
|
692
|
+
shell,
|
|
693
|
+
os
|
|
694
|
+
});
|
|
695
|
+
if (presenterResult) {
|
|
696
|
+
toolSpecificData.presentationOverrides = {
|
|
697
|
+
commandLine: presenterResult.commandLine,
|
|
698
|
+
language: presenterResult.language ?? undefined
|
|
699
|
+
};
|
|
700
|
+
if (extractedCd && toolSpecificData.confirmation?.cwdLabel) {
|
|
701
|
+
if (presenterResult.languageDisplayName) {
|
|
702
|
+
confirmationTitle = ( localize(
|
|
703
|
+
14049,
|
|
704
|
+
"Run `{0}` command in `{1}` within `{2}`?",
|
|
705
|
+
presenterResult.languageDisplayName,
|
|
706
|
+
shellType,
|
|
707
|
+
toolSpecificData.confirmation.cwdLabel
|
|
708
|
+
));
|
|
709
|
+
} else {
|
|
710
|
+
confirmationTitle = ( localize(
|
|
711
|
+
14050,
|
|
712
|
+
"Run command in `{0}` within `{1}`?",
|
|
713
|
+
shellType,
|
|
714
|
+
toolSpecificData.confirmation.cwdLabel
|
|
715
|
+
));
|
|
716
|
+
}
|
|
717
|
+
} else {
|
|
718
|
+
if (presenterResult.languageDisplayName) {
|
|
719
|
+
confirmationTitle = ( localize(
|
|
720
|
+
14051,
|
|
721
|
+
"Run `{0}` command in `{1}`?",
|
|
722
|
+
presenterResult.languageDisplayName,
|
|
723
|
+
shellType
|
|
724
|
+
));
|
|
725
|
+
} else {
|
|
726
|
+
confirmationTitle = ( localize(14052, "Run command in `{0}`?", shellType));
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (!presenterResult.processOtherPresenters) {
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
presenterInput = presenterResult.commandLine;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (requiresUnsandboxConfirmation) {
|
|
736
|
+
confirmationTitle = blockedDomains?.length ? ( localize(
|
|
737
|
+
14053,
|
|
738
|
+
"Run `{0}` command outside the [sandbox]({1}) to access {2}?",
|
|
739
|
+
shellType,
|
|
740
|
+
TERMINAL_SANDBOX_DOCUMENTATION_URL,
|
|
741
|
+
this._formatBlockedDomainsForTitle(blockedDomains)
|
|
742
|
+
)) : ( localize(
|
|
743
|
+
14054,
|
|
744
|
+
"Run `{0}` command outside the [sandbox]({1})?",
|
|
745
|
+
shellType,
|
|
746
|
+
TERMINAL_SANDBOX_DOCUMENTATION_URL
|
|
747
|
+
));
|
|
748
|
+
}
|
|
749
|
+
const shouldShowConfirmation = (!isFinalAutoApproved && !isSessionAutoApproved) || context.forceConfirmationReason !== undefined;
|
|
750
|
+
toolSpecificData.requiresConfirmationForRetry = (!isAutoApprovedByRules && !isSessionAutoApproved) || context.forceConfirmationReason !== undefined;
|
|
751
|
+
const explanation = args.explanation || ( localize(14055, "No explanation provided"));
|
|
752
|
+
const goal = args.goal || ( localize(14056, "No goal provided"));
|
|
753
|
+
const confirmationMessage = requiresUnsandboxConfirmation ? ( new MarkdownString(( localize(
|
|
754
|
+
14057,
|
|
755
|
+
"Explanation: {0}\n\nGoal: {1}\n\nReason for leaving the sandbox: {2}",
|
|
756
|
+
explanation,
|
|
757
|
+
goal,
|
|
758
|
+
requestUnsandboxedExecutionReason || ( localize(14058, "The model indicated that this command needs unsandboxed access."))
|
|
759
|
+
)))) : ( new MarkdownString(( localize(14059, "Explanation: {0}\n\nGoal: {1}", explanation, goal))));
|
|
760
|
+
const confirmationMessages = shouldShowConfirmation ? {
|
|
761
|
+
title: confirmationTitle,
|
|
762
|
+
message: confirmationMessage,
|
|
763
|
+
disclaimer,
|
|
764
|
+
allowAutoConfirm: undefined,
|
|
765
|
+
terminalCustomActions: customActions
|
|
766
|
+
} : undefined;
|
|
767
|
+
const rawDisplayCommand = toolSpecificData.commandLine.forDisplay ?? toolSpecificData.commandLine.toolEdited ?? toolSpecificData.commandLine.original;
|
|
768
|
+
const displayCommand = rawDisplayCommand.length > 80 ? rawDisplayCommand.substring(0, 77) + "..." : rawDisplayCommand;
|
|
769
|
+
const invocationMessage = toolSpecificData.commandLine.isSandboxWrapped ? ( new MarkdownString(( localize(
|
|
770
|
+
14060,
|
|
771
|
+
"Running `{0}` in sandbox",
|
|
772
|
+
escapeMarkdownSyntaxTokens(displayCommand)
|
|
773
|
+
)))) : ( new MarkdownString(( localize(14061, "Running `{0}`", escapeMarkdownSyntaxTokens(displayCommand)))));
|
|
774
|
+
return {
|
|
775
|
+
invocationMessage,
|
|
776
|
+
icon: toolSpecificData.commandLine.isSandboxWrapped ? Codicon.terminalSecure : Codicon.terminal,
|
|
777
|
+
confirmationMessages: sandboxConfirmationMessageForMissingDeps ?? confirmationMessages,
|
|
778
|
+
toolSpecificData
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
_formatBlockedDomainsForTitle(blockedDomains) {
|
|
782
|
+
if (blockedDomains.length === 1) {
|
|
783
|
+
return `\`${blockedDomains[0]}\``;
|
|
784
|
+
}
|
|
785
|
+
return localize(
|
|
786
|
+
14062,
|
|
787
|
+
"`{0}` and {1} more domains",
|
|
788
|
+
blockedDomains[0],
|
|
789
|
+
blockedDomains.length - 1
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
_getBlockedDomainReason(blockedDomains, deniedDomains = []) {
|
|
793
|
+
if (deniedDomains.length === blockedDomains.length && deniedDomains.length > 0) {
|
|
794
|
+
if (blockedDomains.length === 1) {
|
|
795
|
+
return localize(
|
|
796
|
+
14063,
|
|
797
|
+
"This command accesses {0}, which is blocked by chat.agent.deniedNetworkDomains.",
|
|
798
|
+
blockedDomains[0]
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
return localize(
|
|
802
|
+
14064,
|
|
803
|
+
"This command accesses {0} and {1} more domains that are blocked by chat.agent.deniedNetworkDomains.",
|
|
804
|
+
blockedDomains[0],
|
|
805
|
+
blockedDomains.length - 1
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
if (deniedDomains.length > 0) {
|
|
809
|
+
if (blockedDomains.length === 1) {
|
|
810
|
+
return localize(
|
|
811
|
+
14065,
|
|
812
|
+
"This command accesses {0}, which is blocked by chat.agent.deniedNetworkDomains or not added to chat.agent.allowedNetworkDomains.",
|
|
813
|
+
blockedDomains[0]
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
return localize(
|
|
817
|
+
14066,
|
|
818
|
+
"This command accesses {0} and {1} more domains that are blocked by chat.agent.deniedNetworkDomains or not added to chat.agent.allowedNetworkDomains.",
|
|
819
|
+
blockedDomains[0],
|
|
820
|
+
blockedDomains.length - 1
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
if (blockedDomains.length === 1) {
|
|
824
|
+
return localize(
|
|
825
|
+
14067,
|
|
826
|
+
"This command accesses {0}, which is not permitted by the current chat.agent.sandbox configuration.",
|
|
827
|
+
blockedDomains[0]
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
return localize(
|
|
831
|
+
14068,
|
|
832
|
+
"This command accesses {0} and {1} more domains that are not permitted by the current chat.agent.sandbox configuration.",
|
|
833
|
+
blockedDomains[0],
|
|
834
|
+
blockedDomains.length - 1
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
async _rewriteCommandLine(commandLine, options) {
|
|
838
|
+
let rewrittenCommand = commandLine;
|
|
839
|
+
let forDisplayCommand = undefined;
|
|
840
|
+
let isSandboxWrapped = false;
|
|
841
|
+
let requiresUnsandboxConfirmation = options.requestUnsandboxedExecution;
|
|
842
|
+
let requestUnsandboxedExecutionReason = options.requestUnsandboxedExecution ? options.requestUnsandboxedExecutionReason : undefined;
|
|
843
|
+
let blockedDomains;
|
|
844
|
+
for (const rewriter of this._commandLineRewriters) {
|
|
845
|
+
const rewriteResult = await rewriter.rewrite({
|
|
846
|
+
commandLine: rewrittenCommand,
|
|
847
|
+
cwd: options.cwd,
|
|
848
|
+
shell: options.shell,
|
|
849
|
+
os: options.os,
|
|
850
|
+
isBackground: options.isBackground,
|
|
851
|
+
requestUnsandboxedExecution: requiresUnsandboxConfirmation
|
|
852
|
+
});
|
|
853
|
+
if (rewriteResult) {
|
|
854
|
+
rewrittenCommand = rewriteResult.rewritten;
|
|
855
|
+
forDisplayCommand = forDisplayCommand ?? rewriteResult.forDisplay;
|
|
856
|
+
if (rewriteResult.isSandboxWrapped) {
|
|
857
|
+
isSandboxWrapped = true;
|
|
858
|
+
} else if (rewriteResult.isSandboxWrapped === false) {
|
|
859
|
+
isSandboxWrapped = false;
|
|
860
|
+
}
|
|
861
|
+
if (rewriteResult.requiresUnsandboxConfirmation) {
|
|
862
|
+
requiresUnsandboxConfirmation = true;
|
|
863
|
+
}
|
|
864
|
+
if (rewriteResult.blockedDomains?.length) {
|
|
865
|
+
blockedDomains = rewriteResult.blockedDomains;
|
|
866
|
+
requestUnsandboxedExecutionReason = this._getBlockedDomainReason(rewriteResult.blockedDomains, rewriteResult.deniedDomains);
|
|
867
|
+
}
|
|
868
|
+
this._logService.info(
|
|
869
|
+
`RunInTerminalTool: Command rewritten by ${rewriter.constructor.name}: ${rewriteResult.reasoning}`
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return {
|
|
874
|
+
rewrittenCommand,
|
|
875
|
+
forDisplayCommand,
|
|
876
|
+
isSandboxWrapped,
|
|
877
|
+
requiresUnsandboxConfirmation,
|
|
878
|
+
requestUnsandboxedExecutionReason,
|
|
879
|
+
blockedDomains
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
async _confirmAutomaticUnsandboxRetry(
|
|
883
|
+
sessionResource,
|
|
884
|
+
command,
|
|
885
|
+
shell,
|
|
886
|
+
blockedDomains,
|
|
887
|
+
requiresConfirmationForRetry,
|
|
888
|
+
token
|
|
889
|
+
) {
|
|
890
|
+
if (requiresConfirmationForRetry === false) {
|
|
891
|
+
return true;
|
|
892
|
+
}
|
|
893
|
+
const chatModel = sessionResource && this._chatService.getSession(sessionResource);
|
|
894
|
+
if (!(chatModel instanceof ChatModel)) {
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
const request = chatModel.getRequests().at(-1);
|
|
898
|
+
if (!request) {
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
901
|
+
let shellType = basename(shell, ".exe");
|
|
902
|
+
if (shellType === "powershell") {
|
|
903
|
+
shellType = "pwsh";
|
|
904
|
+
}
|
|
905
|
+
const store = ( new DisposableStore());
|
|
906
|
+
return (new Promise(resolve => {
|
|
907
|
+
let resolved = false;
|
|
908
|
+
const resolveOnce = value => {
|
|
909
|
+
if (resolved) {
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
resolved = true;
|
|
913
|
+
store.dispose();
|
|
914
|
+
resolve(value);
|
|
915
|
+
};
|
|
916
|
+
const part = ( new ChatElicitationRequestPart(
|
|
917
|
+
this._getAutomaticUnsandboxRetryTitle(shellType, blockedDomains),
|
|
918
|
+
( new MarkdownString(( localize(
|
|
919
|
+
14069,
|
|
920
|
+
"`{0}`",
|
|
921
|
+
escapeMarkdownSyntaxTokens(buildCommandDisplayText(command))
|
|
922
|
+
)))),
|
|
923
|
+
"",
|
|
924
|
+
( localize(14070, "Allow")),
|
|
925
|
+
( localize(14071, "Skip")),
|
|
926
|
+
async () => {
|
|
927
|
+
resolveOnce(true);
|
|
928
|
+
part.hide();
|
|
929
|
+
return ElicitationState.Accepted;
|
|
930
|
+
},
|
|
931
|
+
async () => {
|
|
932
|
+
resolveOnce(false);
|
|
933
|
+
part.hide();
|
|
934
|
+
return ElicitationState.Rejected;
|
|
935
|
+
},
|
|
936
|
+
undefined,
|
|
937
|
+
undefined,
|
|
938
|
+
() => resolveOnce(false)
|
|
939
|
+
));
|
|
940
|
+
chatModel.acceptResponseProgress(request, part);
|
|
941
|
+
store.add(token.onCancellationRequested(() => resolveOnce(false)));
|
|
942
|
+
store.add({
|
|
943
|
+
dispose: () => part.hide()
|
|
944
|
+
});
|
|
945
|
+
}));
|
|
946
|
+
}
|
|
947
|
+
_getAutomaticUnsandboxRetryTitle(shellType, blockedDomains) {
|
|
948
|
+
return blockedDomains?.length ? ( new MarkdownString(( localize(
|
|
949
|
+
14072,
|
|
950
|
+
"Run `{0}` command outside the sandbox to access {1}?",
|
|
951
|
+
shellType,
|
|
952
|
+
this._formatBlockedDomainsForTitle(blockedDomains)
|
|
953
|
+
)))) : ( new MarkdownString(( localize(14073, "Run `{0}` command outside the sandbox?", shellType))));
|
|
954
|
+
}
|
|
955
|
+
_acceptAutomaticUnsandboxRetryToolInvocationUpdate(
|
|
956
|
+
sessionResource,
|
|
957
|
+
toolCallId,
|
|
958
|
+
toolSpecificData,
|
|
959
|
+
isComplete,
|
|
960
|
+
toolResultMessage
|
|
961
|
+
) {
|
|
962
|
+
const chatModel = sessionResource && this._chatService.getSession(sessionResource);
|
|
963
|
+
if (!(chatModel instanceof ChatModel)) {
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const request = chatModel.getRequests().at(-1);
|
|
967
|
+
if (!request) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const displayCommand = buildCommandDisplayText(
|
|
971
|
+
toolSpecificData.commandLine.forDisplay ?? toolSpecificData.commandLine.toolEdited ?? toolSpecificData.commandLine.original
|
|
972
|
+
);
|
|
973
|
+
const progress = {
|
|
974
|
+
kind: "externalToolInvocationUpdate",
|
|
975
|
+
toolCallId,
|
|
976
|
+
toolName: ( localize(14038, "Run in Terminal")),
|
|
977
|
+
isComplete,
|
|
978
|
+
invocationMessage: ( new MarkdownString(( localize(
|
|
979
|
+
14074,
|
|
980
|
+
"Running `{0}` outside the sandbox",
|
|
981
|
+
escapeMarkdownSyntaxTokens(displayCommand)
|
|
982
|
+
)))),
|
|
983
|
+
pastTenseMessage: toolResultMessage,
|
|
984
|
+
toolSpecificData
|
|
985
|
+
};
|
|
986
|
+
chatModel.acceptResponseProgress(request, progress);
|
|
987
|
+
}
|
|
988
|
+
async invoke(invocation, _countTokens, _progress, token) {
|
|
989
|
+
const toolSpecificData = invocation.toolSpecificData;
|
|
990
|
+
if (!toolSpecificData) {
|
|
991
|
+
throw ( new Error("toolSpecificData must be provided for this tool"));
|
|
992
|
+
}
|
|
993
|
+
if (!invocation.context) {
|
|
994
|
+
throw ( new Error("Invocation context must be provided for this tool"));
|
|
995
|
+
}
|
|
996
|
+
const commandId = toolSpecificData.terminalCommandId;
|
|
997
|
+
if (toolSpecificData.alternativeRecommendation) {
|
|
998
|
+
return {
|
|
999
|
+
content: [{
|
|
1000
|
+
kind: "text",
|
|
1001
|
+
value: toolSpecificData.alternativeRecommendation
|
|
1002
|
+
}]
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
if (toolSpecificData.missingSandboxDependencies?.length) {
|
|
1006
|
+
const installButton = ( localize(14045, "Install"));
|
|
1007
|
+
if (invocation.selectedCustomButton === installButton) {
|
|
1008
|
+
const sessionResource = invocation.context.sessionResource;
|
|
1009
|
+
const {
|
|
1010
|
+
exitCode
|
|
1011
|
+
} = await this._terminalSandboxService.installMissingSandboxDependencies(toolSpecificData.missingSandboxDependencies, sessionResource, token, {
|
|
1012
|
+
createTerminal: async () => this._terminalService.createTerminal({}),
|
|
1013
|
+
focusTerminal: async terminal => {
|
|
1014
|
+
this._terminalService.setActiveInstance(terminal);
|
|
1015
|
+
await this._terminalService.revealTerminal(terminal, true);
|
|
1016
|
+
terminal.focus();
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
if (exitCode !== undefined && exitCode !== 0) {
|
|
1020
|
+
return {
|
|
1021
|
+
content: [{
|
|
1022
|
+
kind: "text",
|
|
1023
|
+
value: ( localize(
|
|
1024
|
+
14075,
|
|
1025
|
+
"Sandbox dependency installation failed (exit code {0}). The command was not executed.",
|
|
1026
|
+
exitCode
|
|
1027
|
+
))
|
|
1028
|
+
}]
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
if (exitCode === undefined) {
|
|
1032
|
+
return {
|
|
1033
|
+
content: [{
|
|
1034
|
+
kind: "text",
|
|
1035
|
+
value: ( localize(
|
|
1036
|
+
14076,
|
|
1037
|
+
"Could not determine whether sandbox dependency installation succeeded. The command was not executed."
|
|
1038
|
+
))
|
|
1039
|
+
}]
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
this._logService.info(
|
|
1043
|
+
"RunInTerminalTool: Sandbox dependency installation succeeded, proceeding with command execution"
|
|
1044
|
+
);
|
|
1045
|
+
} else {
|
|
1046
|
+
this._logService.info("RunInTerminalTool: User cancelled sandbox dependency installation");
|
|
1047
|
+
return {
|
|
1048
|
+
content: [{
|
|
1049
|
+
kind: "text",
|
|
1050
|
+
value: ( localize(14077, "Sandbox dependency installation was cancelled by the user."))
|
|
1051
|
+
}]
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
const args = invocation.parameters;
|
|
1056
|
+
const executionOptions = this._resolveExecutionOptions(args);
|
|
1057
|
+
this._logService.debug(`RunInTerminalTool: Invoking with options ${JSON.stringify(args)}`);
|
|
1058
|
+
let toolResultMessage;
|
|
1059
|
+
if (args.timeout !== undefined && (Number.isNaN(args.timeout) || args.timeout < 0)) {
|
|
1060
|
+
return {
|
|
1061
|
+
content: [{
|
|
1062
|
+
kind: "text",
|
|
1063
|
+
value: "Error: timeout must be a non-negative number of milliseconds (use 0 for no timeout)."
|
|
1064
|
+
}]
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
if (executionOptions.mode === "sync" && args.timeout === undefined) {
|
|
1068
|
+
if (args.isBackground === false) {
|
|
1069
|
+
args.timeout = 0;
|
|
1070
|
+
} else {
|
|
1071
|
+
return {
|
|
1072
|
+
content: [{
|
|
1073
|
+
kind: "text",
|
|
1074
|
+
value: "Error: timeout is required for mode=sync and must be provided in milliseconds (use 0 for no timeout)."
|
|
1075
|
+
}]
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
const chatSessionResource = invocation.context.sessionResource;
|
|
1080
|
+
const shouldSendNotifications = !invocation.subAgentInvocationId;
|
|
1081
|
+
const command = toolSpecificData.commandLine.userEdited ?? toolSpecificData.commandLine.toolEdited ?? toolSpecificData.commandLine.original;
|
|
1082
|
+
const didUserEditCommand = (toolSpecificData.commandLine.userEdited !== undefined && toolSpecificData.commandLine.userEdited !== toolSpecificData.commandLine.original);
|
|
1083
|
+
const didToolEditCommand = (!didUserEditCommand && toolSpecificData.commandLine.toolEdited !== undefined && toolSpecificData.commandLine.toolEdited !== toolSpecificData.commandLine.original &&
|
|
1084
|
+
normalizeTerminalCommandForDisplay(toolSpecificData.commandLine.toolEdited).trim() !== normalizeTerminalCommandForDisplay(toolSpecificData.commandLine.original).trim());
|
|
1085
|
+
const didSandboxWrapCommand = toolSpecificData.commandLine.isSandboxWrapped === true;
|
|
1086
|
+
const isSandboxEnabled = await this._terminalSandboxService.isEnabled();
|
|
1087
|
+
const commandLineForMetadata = isSandboxEnabled ? toolSpecificData.commandLine.forDisplay ?? toolSpecificData.commandLine.original : undefined;
|
|
1088
|
+
if (token.isCancellationRequested) {
|
|
1089
|
+
throw ( new CancellationError());
|
|
1090
|
+
}
|
|
1091
|
+
let error;
|
|
1092
|
+
const automaticUnsandboxRetryReason = ( localize(
|
|
1093
|
+
14078,
|
|
1094
|
+
"The sandboxed execution output indicated the sandbox blocked the command."
|
|
1095
|
+
));
|
|
1096
|
+
const isNewSession = !executionOptions.persistentSession && !( this._sessionTerminalAssociations.has(chatSessionResource));
|
|
1097
|
+
const timingStart = Date.now();
|
|
1098
|
+
const termId = generateUuid();
|
|
1099
|
+
const terminalToolSessionId = toolSpecificData.terminalToolSessionId;
|
|
1100
|
+
const store = ( new DisposableStore());
|
|
1101
|
+
this._logService.debug(
|
|
1102
|
+
`RunInTerminalTool: Creating ${executionOptions.persistentSession ? "background" : "foreground"} terminal. termId=${termId}, chatSessionResource=${chatSessionResource}`
|
|
1103
|
+
);
|
|
1104
|
+
const toolTerminal = await this._initTerminal(
|
|
1105
|
+
chatSessionResource,
|
|
1106
|
+
termId,
|
|
1107
|
+
terminalToolSessionId,
|
|
1108
|
+
executionOptions.persistentSession,
|
|
1109
|
+
token
|
|
1110
|
+
);
|
|
1111
|
+
this._handleTerminalVisibility(toolTerminal, chatSessionResource);
|
|
1112
|
+
const timingConnectMs = Date.now() - timingStart;
|
|
1113
|
+
const xterm = await toolTerminal.instance.xtermReadyPromise;
|
|
1114
|
+
if (!xterm) {
|
|
1115
|
+
throw ( new Error("Instance was disposed before xterm.js was ready"));
|
|
1116
|
+
}
|
|
1117
|
+
const commandDetection = toolTerminal.instance.capabilities.get(TerminalCapability.CommandDetection);
|
|
1118
|
+
let inputUserChars = 0;
|
|
1119
|
+
let inputUserSigint = false;
|
|
1120
|
+
store.add(xterm.raw.onData(data => {
|
|
1121
|
+
if (!telemetryIgnoredSequences.includes(data)) {
|
|
1122
|
+
inputUserChars += data.length;
|
|
1123
|
+
}
|
|
1124
|
+
inputUserSigint ||= data === "\u0003";
|
|
1125
|
+
}));
|
|
1126
|
+
let terminalResult = "";
|
|
1127
|
+
let outputLineCount = -1;
|
|
1128
|
+
let exitCode;
|
|
1129
|
+
let altBufferResult;
|
|
1130
|
+
let didTimeout = false;
|
|
1131
|
+
let didInputNeeded = false;
|
|
1132
|
+
let isBackgroundExecution = executionOptions.persistentSession;
|
|
1133
|
+
let timeoutPromise;
|
|
1134
|
+
let timeoutRacePromise;
|
|
1135
|
+
let outputMonitor;
|
|
1136
|
+
let pollingResult;
|
|
1137
|
+
const executeCancellation = store.add(( new CancellationTokenSource(token)));
|
|
1138
|
+
const timeoutValue = args.timeout !== undefined ? clamp(args.timeout, 0, Number.MAX_SAFE_INTEGER) : undefined;
|
|
1139
|
+
if (timeoutValue !== undefined && timeoutValue > 0) {
|
|
1140
|
+
const shouldEnforceTimeout = executionOptions.waitStrategy === "idle" || this._configurationService.getValue(TerminalChatAgentToolsSettingId.EnforceTimeoutFromModel) === true;
|
|
1141
|
+
if (shouldEnforceTimeout) {
|
|
1142
|
+
timeoutPromise = timeout(timeoutValue);
|
|
1143
|
+
timeoutRacePromise = timeoutPromise.then(() => ({
|
|
1144
|
+
type: "timeout"
|
|
1145
|
+
})).catch(() => ({
|
|
1146
|
+
type: "timeout"
|
|
1147
|
+
}));
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
let continueInBackgroundResolve;
|
|
1151
|
+
const continueInBackgroundPromise = ( new Promise(resolve => {
|
|
1152
|
+
continueInBackgroundResolve = resolve;
|
|
1153
|
+
}));
|
|
1154
|
+
if (terminalToolSessionId) {
|
|
1155
|
+
store.add(this._terminalChatService.onDidContinueInBackground(sessionId => {
|
|
1156
|
+
if (sessionId === terminalToolSessionId) {
|
|
1157
|
+
const execution = RunInTerminalTool_1._activeExecutions.get(termId);
|
|
1158
|
+
execution?.setBackground?.();
|
|
1159
|
+
isBackgroundExecution = true;
|
|
1160
|
+
continueInBackgroundResolve?.();
|
|
1161
|
+
}
|
|
1162
|
+
}));
|
|
1163
|
+
}
|
|
1164
|
+
let executionPromise;
|
|
1165
|
+
try {
|
|
1166
|
+
const execution = this._instantiationService.createInstance(
|
|
1167
|
+
ActiveTerminalExecution,
|
|
1168
|
+
chatSessionResource,
|
|
1169
|
+
termId,
|
|
1170
|
+
toolTerminal,
|
|
1171
|
+
commandDetection,
|
|
1172
|
+
executionOptions.persistentSession
|
|
1173
|
+
);
|
|
1174
|
+
this._logService.info(
|
|
1175
|
+
`RunInTerminalTool: Using \`${execution.strategy.type}\` execute strategy for command \`${command}\``
|
|
1176
|
+
);
|
|
1177
|
+
store.add(execution);
|
|
1178
|
+
RunInTerminalTool_1._activeExecutions.set(termId, execution);
|
|
1179
|
+
const startMarkerPromise = Event.toPromise(execution.strategy.onDidCreateStartMarker);
|
|
1180
|
+
const outputMonitorPollFn = executionOptions.persistentSession ? async executionForPoll => ({
|
|
1181
|
+
output: executionForPoll.getOutput(),
|
|
1182
|
+
state: OutputMonitorState.Idle
|
|
1183
|
+
}) : undefined;
|
|
1184
|
+
store.add(execution.strategy.onDidCreateStartMarker(startMarker => {
|
|
1185
|
+
if (!outputMonitor) {
|
|
1186
|
+
outputMonitor = this._instantiationService.createInstance(OutputMonitor, {
|
|
1187
|
+
instance: toolTerminal.instance,
|
|
1188
|
+
sessionResource: chatSessionResource,
|
|
1189
|
+
getOutput: marker => execution.getOutput(marker ?? startMarker)
|
|
1190
|
+
}, outputMonitorPollFn, invocation.context, token, command);
|
|
1191
|
+
}
|
|
1192
|
+
}));
|
|
1193
|
+
executionPromise = execution.start(command, executeCancellation.token, commandId, commandLineForMetadata);
|
|
1194
|
+
if (executionOptions.waitStrategy === "idle") {
|
|
1195
|
+
this._logService.debug(
|
|
1196
|
+
`RunInTerminalTool: Starting persistent execution with idle wait strategy \`${command}\``
|
|
1197
|
+
);
|
|
1198
|
+
await startMarkerPromise;
|
|
1199
|
+
let idleTimedOut = false;
|
|
1200
|
+
if (outputMonitor) {
|
|
1201
|
+
if (timeoutRacePromise) {
|
|
1202
|
+
const idleRace = await Promise.race([Event.toPromise(outputMonitor.onDidFinishCommand).then(() => ({
|
|
1203
|
+
type: "idle"
|
|
1204
|
+
})), timeoutRacePromise]);
|
|
1205
|
+
if (idleRace.type === "timeout") {
|
|
1206
|
+
idleTimedOut = true;
|
|
1207
|
+
this._logService.debug(
|
|
1208
|
+
`RunInTerminalTool: Timeout reached waiting for idle signal, returning output collected so far`
|
|
1209
|
+
);
|
|
1210
|
+
} else {
|
|
1211
|
+
pollingResult = outputMonitor.pollingResult;
|
|
1212
|
+
}
|
|
1213
|
+
} else {
|
|
1214
|
+
await Event.toPromise(outputMonitor.onDidFinishCommand);
|
|
1215
|
+
pollingResult = outputMonitor.pollingResult;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
await this._commandArtifactCollector.capture(toolSpecificData, toolTerminal.instance, commandId);
|
|
1219
|
+
if (token.isCancellationRequested) {
|
|
1220
|
+
throw ( new CancellationError());
|
|
1221
|
+
}
|
|
1222
|
+
const state = toolSpecificData.terminalCommandState ?? {};
|
|
1223
|
+
state.timestamp = state.timestamp ?? timingStart;
|
|
1224
|
+
toolSpecificData.terminalCommandState = state;
|
|
1225
|
+
let resultText = (didSandboxWrapCommand ? `Command is now running in terminal with ID=${termId}` : didUserEditCommand ? `Note: The user manually edited the command to \`${command}\`, and that command is now running in terminal with ID=${termId}` : didToolEditCommand ? `Note: The tool simplified the command to \`${command}\`, and that command is now running in terminal with ID=${termId}` : `Command is running in terminal with ID=${termId}`);
|
|
1226
|
+
const backgroundOutput = pollingResult?.output ?? (idleTimedOut ? execution.getOutput() : undefined);
|
|
1227
|
+
const outputAnalyzerMessage = backgroundOutput ? await this._getOutputAnalyzerMessage(undefined, backgroundOutput, command, didSandboxWrapCommand) : undefined;
|
|
1228
|
+
if (idleTimedOut) {
|
|
1229
|
+
resultText += `\n Timed out waiting for the command to become idle. The command is still running, with output:\n`;
|
|
1230
|
+
if (outputAnalyzerMessage) {
|
|
1231
|
+
resultText += `${outputAnalyzerMessage}\n`;
|
|
1232
|
+
}
|
|
1233
|
+
resultText += backgroundOutput ?? "";
|
|
1234
|
+
} else if (pollingResult && pollingResult.state === OutputMonitorState.Idle) {
|
|
1235
|
+
resultText += `\n The command became idle with output:\n`;
|
|
1236
|
+
if (outputAnalyzerMessage) {
|
|
1237
|
+
resultText += `${outputAnalyzerMessage}\n`;
|
|
1238
|
+
}
|
|
1239
|
+
resultText += pollingResult.output;
|
|
1240
|
+
if (isSessionAutoApproveLevel(
|
|
1241
|
+
chatSessionResource,
|
|
1242
|
+
this._configurationService,
|
|
1243
|
+
this._chatWidgetService,
|
|
1244
|
+
this._chatService
|
|
1245
|
+
)) {
|
|
1246
|
+
resultText += `\nIf the command is waiting for input (not a normal shell prompt), determine the answer and call ${TerminalToolId.SendToTerminal}. Then call ${TerminalToolId.GetTerminalOutput} to read the next prompt. Repeat one prompt at a time.`;
|
|
1247
|
+
} else {
|
|
1248
|
+
resultText += `\nIf the command is waiting for input (not a normal shell prompt), call the vscode_askQuestions tool to ask the user. Then send each answer using ${TerminalToolId.SendToTerminal}, calling ${TerminalToolId.GetTerminalOutput} between each.`;
|
|
1249
|
+
}
|
|
1250
|
+
} else if (pollingResult) {
|
|
1251
|
+
resultText += `\n The command is still running, with output:\n`;
|
|
1252
|
+
if (outputAnalyzerMessage) {
|
|
1253
|
+
resultText += `${outputAnalyzerMessage}\n`;
|
|
1254
|
+
}
|
|
1255
|
+
resultText += pollingResult.output;
|
|
1256
|
+
}
|
|
1257
|
+
const endCwd = await toolTerminal.instance.getCwdResource();
|
|
1258
|
+
return {
|
|
1259
|
+
toolMetadata: {
|
|
1260
|
+
exitCode: undefined,
|
|
1261
|
+
id: termId,
|
|
1262
|
+
terminalId: toolTerminal.instance.instanceId,
|
|
1263
|
+
cwd: endCwd?.toString()
|
|
1264
|
+
},
|
|
1265
|
+
content: [{
|
|
1266
|
+
kind: "text",
|
|
1267
|
+
value: resultText
|
|
1268
|
+
}]
|
|
1269
|
+
};
|
|
1270
|
+
} else {
|
|
1271
|
+
const raceCleanup = ( new DisposableStore());
|
|
1272
|
+
const raceCandidates = [executionPromise.then(result => ({
|
|
1273
|
+
type: "completed",
|
|
1274
|
+
result
|
|
1275
|
+
})), continueInBackgroundPromise.then(() => ({
|
|
1276
|
+
type: "background"
|
|
1277
|
+
})), ( new Promise(resolve => {
|
|
1278
|
+
startMarkerPromise.then(() => {
|
|
1279
|
+
if (outputMonitor && !raceCleanup.isDisposed) {
|
|
1280
|
+
raceCleanup.add(outputMonitor.onDidDetectInputNeeded(() => resolve({
|
|
1281
|
+
type: "inputNeeded"
|
|
1282
|
+
})));
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
}))];
|
|
1286
|
+
if (timeoutRacePromise) {
|
|
1287
|
+
raceCandidates.push(timeoutRacePromise);
|
|
1288
|
+
}
|
|
1289
|
+
const raceResult = await Promise.race(raceCandidates);
|
|
1290
|
+
raceCleanup.dispose();
|
|
1291
|
+
if (raceResult.type === "inputNeeded") {
|
|
1292
|
+
this._logService.debug(
|
|
1293
|
+
`RunInTerminalTool: Output monitor detected input needed in foreground terminal, returning output to agent`
|
|
1294
|
+
);
|
|
1295
|
+
error = "inputNeeded";
|
|
1296
|
+
didInputNeeded = true;
|
|
1297
|
+
const idleOutput = execution.getOutput();
|
|
1298
|
+
outputLineCount = idleOutput ? count(idleOutput.trim(), "\n") + 1 : 0;
|
|
1299
|
+
terminalResult = idleOutput ?? "";
|
|
1300
|
+
} else if (raceResult.type === "background") {
|
|
1301
|
+
this._logService.debug(
|
|
1302
|
+
`RunInTerminalTool: Continue in background triggered, returning output collected so far`
|
|
1303
|
+
);
|
|
1304
|
+
error = "continueInBackground";
|
|
1305
|
+
const backgroundOutput = execution.getOutput();
|
|
1306
|
+
outputLineCount = backgroundOutput ? count(backgroundOutput.trim(), "\n") + 1 : 0;
|
|
1307
|
+
terminalResult = backgroundOutput;
|
|
1308
|
+
} else if (raceResult.type === "timeout") {
|
|
1309
|
+
this._logService.debug(`RunInTerminalTool: Timeout reached, returning output collected so far`);
|
|
1310
|
+
error = "timeout";
|
|
1311
|
+
didTimeout = true;
|
|
1312
|
+
isBackgroundExecution = true;
|
|
1313
|
+
toolTerminal.isBackground = true;
|
|
1314
|
+
this._sessionTerminalAssociations.delete(chatSessionResource);
|
|
1315
|
+
await this._associateProcessIdWithSession(
|
|
1316
|
+
toolTerminal.instance,
|
|
1317
|
+
chatSessionResource,
|
|
1318
|
+
termId,
|
|
1319
|
+
toolTerminal.shellIntegrationQuality,
|
|
1320
|
+
true
|
|
1321
|
+
);
|
|
1322
|
+
const timeoutOutput = execution.getOutput();
|
|
1323
|
+
outputLineCount = timeoutOutput ? count(timeoutOutput.trim(), "\n") + 1 : 0;
|
|
1324
|
+
terminalResult = timeoutOutput ?? "";
|
|
1325
|
+
} else {
|
|
1326
|
+
const executeResult = raceResult.result;
|
|
1327
|
+
toolTerminal.receivedUserInput = false;
|
|
1328
|
+
if (token.isCancellationRequested) {
|
|
1329
|
+
throw ( new CancellationError());
|
|
1330
|
+
}
|
|
1331
|
+
if (executeResult.didEnterAltBuffer) {
|
|
1332
|
+
const state = toolSpecificData.terminalCommandState ?? {};
|
|
1333
|
+
state.timestamp = state.timestamp ?? timingStart;
|
|
1334
|
+
toolSpecificData.terminalCommandState = state;
|
|
1335
|
+
toolResultMessage = altBufferMessage;
|
|
1336
|
+
outputLineCount = 0;
|
|
1337
|
+
error = executeResult.error ?? "alternateBuffer";
|
|
1338
|
+
const altBufferCwd = await toolTerminal.instance.getCwdResource();
|
|
1339
|
+
altBufferResult = {
|
|
1340
|
+
toolResultMessage,
|
|
1341
|
+
toolMetadata: {
|
|
1342
|
+
exitCode: undefined,
|
|
1343
|
+
id: termId,
|
|
1344
|
+
terminalId: toolTerminal.instance.instanceId,
|
|
1345
|
+
cwd: altBufferCwd?.toString()
|
|
1346
|
+
},
|
|
1347
|
+
content: [{
|
|
1348
|
+
kind: "text",
|
|
1349
|
+
value: altBufferMessage
|
|
1350
|
+
}]
|
|
1351
|
+
};
|
|
1352
|
+
} else {
|
|
1353
|
+
await this._commandArtifactCollector.capture(toolSpecificData, toolTerminal.instance, commandId);
|
|
1354
|
+
{
|
|
1355
|
+
const state = toolSpecificData.terminalCommandState ?? {};
|
|
1356
|
+
state.timestamp = state.timestamp ?? timingStart;
|
|
1357
|
+
if (executeResult.exitCode !== undefined) {
|
|
1358
|
+
state.exitCode = executeResult.exitCode;
|
|
1359
|
+
if (state.timestamp !== undefined) {
|
|
1360
|
+
state.duration = state.duration ?? Math.max(0, Date.now() - state.timestamp);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
toolSpecificData.terminalCommandState = state;
|
|
1364
|
+
}
|
|
1365
|
+
this._logService.info(
|
|
1366
|
+
`RunInTerminalTool: Finished \`${execution.strategy.type}\` execute strategy with exitCode \`${executeResult.exitCode}\`, result.length \`${executeResult.output?.length}\`, error \`${executeResult.error}\``
|
|
1367
|
+
);
|
|
1368
|
+
outputLineCount = executeResult.output === undefined ? 0 : count(executeResult.output.trim(), "\n") + 1;
|
|
1369
|
+
exitCode = executeResult.exitCode;
|
|
1370
|
+
error = executeResult.error;
|
|
1371
|
+
const resultArr = [];
|
|
1372
|
+
if (executeResult.output !== undefined) {
|
|
1373
|
+
resultArr.push(executeResult.output);
|
|
1374
|
+
}
|
|
1375
|
+
if (executeResult.additionalInformation) {
|
|
1376
|
+
resultArr.push(executeResult.additionalInformation);
|
|
1377
|
+
}
|
|
1378
|
+
terminalResult = resultArr.join("\n\n");
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
} catch (e) {
|
|
1383
|
+
if (didTimeout && e instanceof CancellationError) {
|
|
1384
|
+
this._logService.debug(`RunInTerminalTool: Timeout reached, returning output collected so far`);
|
|
1385
|
+
error = "timeout";
|
|
1386
|
+
isBackgroundExecution = true;
|
|
1387
|
+
toolTerminal.isBackground = true;
|
|
1388
|
+
this._sessionTerminalAssociations.delete(chatSessionResource);
|
|
1389
|
+
const timeoutOutput = getOutput(toolTerminal.instance, undefined);
|
|
1390
|
+
outputLineCount = timeoutOutput ? count(timeoutOutput.trim(), "\n") + 1 : 0;
|
|
1391
|
+
terminalResult = timeoutOutput ?? "";
|
|
1392
|
+
} else {
|
|
1393
|
+
this._logService.debug(`RunInTerminalTool: Threw exception`);
|
|
1394
|
+
if (e instanceof CancellationError) {
|
|
1395
|
+
await this._commandArtifactCollector.capture(toolSpecificData, toolTerminal.instance, commandId);
|
|
1396
|
+
const state = toolSpecificData.terminalCommandState ?? {};
|
|
1397
|
+
if (state.exitCode === undefined) {
|
|
1398
|
+
state.exitCode = -1;
|
|
1399
|
+
state.timestamp = state.timestamp ?? timingStart;
|
|
1400
|
+
state.duration = state.duration ?? Math.max(0, Date.now() - state.timestamp);
|
|
1401
|
+
}
|
|
1402
|
+
toolSpecificData.terminalCommandState = state;
|
|
1403
|
+
}
|
|
1404
|
+
RunInTerminalTool_1._activeExecutions.get(termId)?.dispose();
|
|
1405
|
+
RunInTerminalTool_1._activeExecutions.delete(termId);
|
|
1406
|
+
toolTerminal.instance.dispose();
|
|
1407
|
+
error = e instanceof CancellationError ? "canceled" : "unexpectedException";
|
|
1408
|
+
throw e;
|
|
1409
|
+
}
|
|
1410
|
+
} finally {
|
|
1411
|
+
timeoutPromise?.cancel();
|
|
1412
|
+
if ((isBackgroundExecution || didInputNeeded) && executionPromise) {
|
|
1413
|
+
executionPromise.catch(e => {
|
|
1414
|
+
if (!(e instanceof CancellationError)) {
|
|
1415
|
+
this._logService.error(`RunInTerminalTool: Background execution error`, e);
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
if (shouldSendNotifications) {
|
|
1419
|
+
this._registerCompletionNotification(toolTerminal.instance, termId, chatSessionResource, command, outputMonitor);
|
|
1420
|
+
} else {
|
|
1421
|
+
outputMonitor?.dispose();
|
|
1422
|
+
}
|
|
1423
|
+
} else {
|
|
1424
|
+
RunInTerminalTool_1._activeExecutions.get(termId)?.dispose();
|
|
1425
|
+
RunInTerminalTool_1._activeExecutions.delete(termId);
|
|
1426
|
+
outputMonitor?.dispose();
|
|
1427
|
+
}
|
|
1428
|
+
store.dispose();
|
|
1429
|
+
const timingExecuteMs = Date.now() - timingStart;
|
|
1430
|
+
this._telemetry.logInvoke(toolTerminal.instance, {
|
|
1431
|
+
terminalToolSessionId: toolSpecificData.terminalToolSessionId,
|
|
1432
|
+
didUserEditCommand,
|
|
1433
|
+
didToolEditCommand,
|
|
1434
|
+
isBackground: executionOptions.persistentSession,
|
|
1435
|
+
isSandboxWrapped: toolSpecificData.commandLine.isSandboxWrapped === true,
|
|
1436
|
+
requestUnsandboxedExecutionReason: args.requestUnsandboxedExecutionReason,
|
|
1437
|
+
shellIntegrationQuality: toolTerminal.shellIntegrationQuality,
|
|
1438
|
+
error,
|
|
1439
|
+
isNewSession,
|
|
1440
|
+
outputLineCount,
|
|
1441
|
+
exitCode,
|
|
1442
|
+
timingExecuteMs,
|
|
1443
|
+
timingConnectMs,
|
|
1444
|
+
inputUserChars,
|
|
1445
|
+
inputUserSigint,
|
|
1446
|
+
terminalExecutionIdleBeforeTimeout: pollingResult?.state === OutputMonitorState.Idle,
|
|
1447
|
+
pollDurationMs: pollingResult?.pollDurationMs,
|
|
1448
|
+
inputToolManualAcceptCount: outputMonitor?.outputMonitorTelemetryCounters?.inputToolManualAcceptCount,
|
|
1449
|
+
inputToolManualRejectCount: outputMonitor?.outputMonitorTelemetryCounters?.inputToolManualRejectCount,
|
|
1450
|
+
inputToolManualChars: outputMonitor?.outputMonitorTelemetryCounters?.inputToolManualChars,
|
|
1451
|
+
inputToolAutoAcceptCount: outputMonitor?.outputMonitorTelemetryCounters?.inputToolAutoAcceptCount,
|
|
1452
|
+
inputToolAutoChars: outputMonitor?.outputMonitorTelemetryCounters?.inputToolAutoChars,
|
|
1453
|
+
inputToolManualShownCount: outputMonitor?.outputMonitorTelemetryCounters?.inputToolManualShownCount,
|
|
1454
|
+
inputToolFreeFormInputCount: outputMonitor?.outputMonitorTelemetryCounters?.inputToolFreeFormInputCount,
|
|
1455
|
+
inputToolFreeFormInputShownCount: outputMonitor?.outputMonitorTelemetryCounters?.inputToolFreeFormInputShownCount
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
if (altBufferResult) {
|
|
1459
|
+
return altBufferResult;
|
|
1460
|
+
}
|
|
1461
|
+
const shouldAutoRetryUnsandboxed = shouldAutomaticallyRetryUnsandboxed({
|
|
1462
|
+
didSandboxWrapCommand,
|
|
1463
|
+
requestUnsandboxedExecution: args.requestUnsandboxedExecution === true,
|
|
1464
|
+
isPersistentSession: executionOptions.persistentSession,
|
|
1465
|
+
isBackgroundExecution: isBackgroundExecution || didInputNeeded,
|
|
1466
|
+
didTimeout,
|
|
1467
|
+
exitCode,
|
|
1468
|
+
output: terminalResult
|
|
1469
|
+
});
|
|
1470
|
+
if (shouldAutoRetryUnsandboxed) {
|
|
1471
|
+
const [os, shell] = await Promise.all([this._osBackend, this._profileFetcher.getCopilotShell()]);
|
|
1472
|
+
const retryReason = automaticUnsandboxRetryReason;
|
|
1473
|
+
const retryRewriteResult = await this._rewriteCommandLine(args.command, {
|
|
1474
|
+
cwd: toolSpecificData.cwd ? URI.revive(toolSpecificData.cwd) : undefined,
|
|
1475
|
+
shell,
|
|
1476
|
+
os,
|
|
1477
|
+
isBackground: executionOptions.persistentSession,
|
|
1478
|
+
requestUnsandboxedExecution: true,
|
|
1479
|
+
requestUnsandboxedExecutionReason: retryReason
|
|
1480
|
+
});
|
|
1481
|
+
const rewrittenRetryReason = retryRewriteResult.requestUnsandboxedExecutionReason ?? retryReason;
|
|
1482
|
+
const retryConfirmationCommand = toolSpecificData.presentationOverrides?.commandLine ?? command;
|
|
1483
|
+
const shouldRetry = await this._confirmAutomaticUnsandboxRetry(
|
|
1484
|
+
invocation.context.sessionResource,
|
|
1485
|
+
retryConfirmationCommand,
|
|
1486
|
+
shell,
|
|
1487
|
+
retryRewriteResult.blockedDomains,
|
|
1488
|
+
toolSpecificData.requiresConfirmationForRetry,
|
|
1489
|
+
token
|
|
1490
|
+
);
|
|
1491
|
+
if (shouldRetry) {
|
|
1492
|
+
const retryToolSpecificData = {
|
|
1493
|
+
...toolSpecificData,
|
|
1494
|
+
terminalCommandId: `tool-${generateUuid()}`,
|
|
1495
|
+
commandLine: {
|
|
1496
|
+
original: args.command,
|
|
1497
|
+
toolEdited: retryRewriteResult.rewrittenCommand === args.command ? undefined : retryRewriteResult.rewrittenCommand,
|
|
1498
|
+
forDisplay: retryRewriteResult.forDisplayCommand ?? normalizeTerminalCommandForDisplay(retryRewriteResult.rewrittenCommand ?? args.command),
|
|
1499
|
+
isSandboxWrapped: retryRewriteResult.isSandboxWrapped
|
|
1500
|
+
},
|
|
1501
|
+
requestUnsandboxedExecution: true,
|
|
1502
|
+
requestUnsandboxedExecutionReason: rewrittenRetryReason,
|
|
1503
|
+
terminalCommandUri: undefined,
|
|
1504
|
+
terminalCommandOutput: undefined,
|
|
1505
|
+
terminalTheme: undefined,
|
|
1506
|
+
terminalCommandState: undefined,
|
|
1507
|
+
didContinueInBackground: undefined
|
|
1508
|
+
};
|
|
1509
|
+
const retryToolCallId = `automatic-unsandbox-retry-${generateUuid()}`;
|
|
1510
|
+
this._acceptAutomaticUnsandboxRetryToolInvocationUpdate(
|
|
1511
|
+
invocation.context.sessionResource,
|
|
1512
|
+
retryToolCallId,
|
|
1513
|
+
retryToolSpecificData,
|
|
1514
|
+
false
|
|
1515
|
+
);
|
|
1516
|
+
return await this.invoke({
|
|
1517
|
+
...invocation,
|
|
1518
|
+
parameters: {
|
|
1519
|
+
...args,
|
|
1520
|
+
command: args.command,
|
|
1521
|
+
requestUnsandboxedExecution: true,
|
|
1522
|
+
requestUnsandboxedExecutionReason: rewrittenRetryReason
|
|
1523
|
+
},
|
|
1524
|
+
toolSpecificData: retryToolSpecificData
|
|
1525
|
+
}, _countTokens, _progress, token);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
this._terminalToolCreator.refreshShellIntegrationQuality(toolTerminal);
|
|
1529
|
+
this._logService.info(
|
|
1530
|
+
`RunInTerminalTool: shellIntegrationQuality=${toolTerminal.shellIntegrationQuality} at banner decision time`
|
|
1531
|
+
);
|
|
1532
|
+
if (!toolResultMessage && toolTerminal.shellIntegrationQuality === ShellIntegrationQuality.None) {
|
|
1533
|
+
toolResultMessage = "$(info) Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) to improve command detection";
|
|
1534
|
+
}
|
|
1535
|
+
const resultText = [];
|
|
1536
|
+
if (!didSandboxWrapCommand) {
|
|
1537
|
+
if (didUserEditCommand) {
|
|
1538
|
+
resultText.push(
|
|
1539
|
+
`Note: The user manually edited the command to \`${command}\`, and this is the output of running that command instead:\n`
|
|
1540
|
+
);
|
|
1541
|
+
} else if (didToolEditCommand) {
|
|
1542
|
+
resultText.push(
|
|
1543
|
+
`Note: The tool simplified the command to \`${command}\`, and this is the output of running that command instead:\n`
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
if (isBackgroundExecution && !executionOptions.persistentSession) {
|
|
1547
|
+
resultText.push(
|
|
1548
|
+
`Note: This terminal execution was moved to the background using the ID ${termId}\n`
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
const isAutoApproved = isSessionAutoApproveLevel(
|
|
1553
|
+
chatSessionResource,
|
|
1554
|
+
this._configurationService,
|
|
1555
|
+
this._chatWidgetService,
|
|
1556
|
+
this._chatService
|
|
1557
|
+
);
|
|
1558
|
+
if (didInputNeeded) {
|
|
1559
|
+
if (isAutoApproved) {
|
|
1560
|
+
resultText.push(
|
|
1561
|
+
`Note: The command is running in terminal ID ${termId} and may be waiting for input. If it IS waiting for input (not a normal shell prompt), determine the answer and call ${TerminalToolId.SendToTerminal}. Then call ${TerminalToolId.GetTerminalOutput} to read the next prompt. Repeat one prompt at a time.\n\n`
|
|
1562
|
+
);
|
|
1563
|
+
} else {
|
|
1564
|
+
resultText.push(
|
|
1565
|
+
`Note: The command is running in terminal ID ${termId} and may be waiting for input. If it IS waiting for input (not a normal shell prompt), call the vscode_askQuestions tool to ask the user. Then send each answer using ${TerminalToolId.SendToTerminal}, calling ${TerminalToolId.GetTerminalOutput} between each.\n\n`
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
} else if (didTimeout && timeoutValue !== undefined && timeoutValue > 0) {
|
|
1569
|
+
const notificationHint = shouldSendNotifications ? " You will be automatically notified on your next turn when it completes." : "";
|
|
1570
|
+
const inputAction = isAutoApproved ? `If it IS waiting for input (not a normal shell prompt), determine the answer and call ${TerminalToolId.SendToTerminal}. Then call ${TerminalToolId.GetTerminalOutput} to read the next prompt. Repeat one prompt at a time.` : `If it IS waiting for input (not a normal shell prompt), call the vscode_askQuestions tool to ask the user. Then send each answer using ${TerminalToolId.SendToTerminal}, calling ${TerminalToolId.GetTerminalOutput} between each.`;
|
|
1571
|
+
resultText.push(
|
|
1572
|
+
`Note: Command timed out after ${timeoutValue}ms. The command may still be running in terminal ID ${termId}.${notificationHint} Use ${TerminalToolId.GetTerminalOutput} to check output, ${TerminalToolId.SendToTerminal} to send input, or ${TerminalToolId.KillTerminal} to stop it. ${inputAction}\n\n`
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
const outputAnalyzerMessage = await this._getOutputAnalyzerMessage(exitCode, terminalResult, command, didSandboxWrapCommand);
|
|
1576
|
+
if (outputAnalyzerMessage) {
|
|
1577
|
+
resultText.push(`${outputAnalyzerMessage}\n`);
|
|
1578
|
+
}
|
|
1579
|
+
resultText.push(terminalResult);
|
|
1580
|
+
const isError = exitCode !== undefined && exitCode !== 0;
|
|
1581
|
+
const endCwd = await toolTerminal.instance.getCwdResource();
|
|
1582
|
+
const imageContent = await this._extractImagesFromOutput(terminalResult, endCwd);
|
|
1583
|
+
return {
|
|
1584
|
+
toolResultMessage,
|
|
1585
|
+
toolMetadata: {
|
|
1586
|
+
exitCode: exitCode,
|
|
1587
|
+
id: termId,
|
|
1588
|
+
terminalId: toolTerminal.instance.instanceId,
|
|
1589
|
+
cwd: endCwd?.toString(),
|
|
1590
|
+
timedOut: didTimeout || undefined,
|
|
1591
|
+
timeoutMs: didTimeout ? timeoutValue : undefined
|
|
1592
|
+
},
|
|
1593
|
+
toolResultDetails: isError ? {
|
|
1594
|
+
input: command,
|
|
1595
|
+
output: [{
|
|
1596
|
+
type: "embed",
|
|
1597
|
+
isText: true,
|
|
1598
|
+
value: terminalResult
|
|
1599
|
+
}],
|
|
1600
|
+
isError: true
|
|
1601
|
+
} : undefined,
|
|
1602
|
+
content: [{
|
|
1603
|
+
kind: "text",
|
|
1604
|
+
value: resultText.join("")
|
|
1605
|
+
}, ...imageContent]
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
async _getOutputAnalyzerMessage(exitCode, exitResult, commandLine, isSandboxWrapped) {
|
|
1609
|
+
for (const analyzer of this._outputAnalyzers) {
|
|
1610
|
+
const message = await analyzer.analyze({
|
|
1611
|
+
exitCode,
|
|
1612
|
+
exitResult,
|
|
1613
|
+
commandLine,
|
|
1614
|
+
isSandboxWrapped
|
|
1615
|
+
});
|
|
1616
|
+
if (message) {
|
|
1617
|
+
return message;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
return undefined;
|
|
1621
|
+
}
|
|
1622
|
+
static {
|
|
1623
|
+
this._maxImageFileSize = 5 * 1024 * 1024;
|
|
1624
|
+
}
|
|
1625
|
+
async _extractImagesFromOutput(output, cwd) {
|
|
1626
|
+
const pathPattern = /[^\s/\\]*(?:[/\\][^\s/\\]*)+\.(?:png|jpe?g|gif|webp|bmp)/gi;
|
|
1627
|
+
const matches = ( new Set());
|
|
1628
|
+
for (const line of output.split(/\r?\n/)) {
|
|
1629
|
+
if (line.length > 10_000) {
|
|
1630
|
+
continue;
|
|
1631
|
+
}
|
|
1632
|
+
for (const match of line.matchAll(pathPattern)) {
|
|
1633
|
+
matches.add(match[0]);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
if (matches.size === 0) {
|
|
1637
|
+
return [];
|
|
1638
|
+
}
|
|
1639
|
+
const results = [];
|
|
1640
|
+
for (const filePath of matches) {
|
|
1641
|
+
try {
|
|
1642
|
+
const mimeType = getMediaMime(filePath);
|
|
1643
|
+
if (!mimeType || !mimeType.startsWith("image/")) {
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
let fileUri;
|
|
1647
|
+
if (/^\/|^[A-Za-z]:[\\\/]/.test(filePath)) {
|
|
1648
|
+
fileUri = URI.file(filePath);
|
|
1649
|
+
} else if (cwd) {
|
|
1650
|
+
fileUri = URI.joinPath(cwd, filePath);
|
|
1651
|
+
} else {
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
const stat = await this._fileService.stat(fileUri).catch(() => undefined);
|
|
1655
|
+
if (!stat || stat.isDirectory || stat.size > RunInTerminalTool_1._maxImageFileSize) {
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
const fileContent = await this._fileService.readFile(fileUri);
|
|
1659
|
+
results.push({
|
|
1660
|
+
kind: "data",
|
|
1661
|
+
value: {
|
|
1662
|
+
mimeType,
|
|
1663
|
+
data: fileContent.value
|
|
1664
|
+
},
|
|
1665
|
+
audience: [LanguageModelPartAudience.User]
|
|
1666
|
+
});
|
|
1667
|
+
} catch {}
|
|
1668
|
+
}
|
|
1669
|
+
return results;
|
|
1670
|
+
}
|
|
1671
|
+
_handleTerminalVisibility(toolTerminal, chatSessionResource) {
|
|
1672
|
+
const chatSessionOpenInWidget = !!this._chatWidgetService.getWidgetBySessionResource(chatSessionResource);
|
|
1673
|
+
if (this._configurationService.getValue(TerminalChatAgentToolsSettingId.OutputLocation) === "terminal" && chatSessionOpenInWidget) {
|
|
1674
|
+
this._terminalService.setActiveInstance(toolTerminal.instance);
|
|
1675
|
+
this._terminalService.revealTerminal(toolTerminal.instance, true);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
async _initTerminal(chatSessionResource, termId, terminalToolSessionId, isBackground, token) {
|
|
1679
|
+
if (!isBackground) {
|
|
1680
|
+
const cachedTerminal = this._sessionTerminalAssociations.get(chatSessionResource);
|
|
1681
|
+
if (cachedTerminal && !cachedTerminal.isBackground && !cachedTerminal.instance.isDisposed) {
|
|
1682
|
+
this._logService.debug(
|
|
1683
|
+
`RunInTerminalTool: Using cached terminal with session resource \`${chatSessionResource}\``
|
|
1684
|
+
);
|
|
1685
|
+
this._terminalToolCreator.refreshShellIntegrationQuality(cachedTerminal);
|
|
1686
|
+
this._terminalChatService.registerTerminalInstanceWithToolSession(terminalToolSessionId, cachedTerminal.instance);
|
|
1687
|
+
return cachedTerminal;
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
this._logService.debug(
|
|
1691
|
+
`RunInTerminalTool: Creating ${isBackground ? "background" : "foreground"} terminal with ID=${termId}`
|
|
1692
|
+
);
|
|
1693
|
+
const profile = await this._profileFetcher.getCopilotProfile();
|
|
1694
|
+
const os = await this._osBackend;
|
|
1695
|
+
const toolTerminal = await this._terminalToolCreator.createTerminal(profile, os, token);
|
|
1696
|
+
toolTerminal.isBackground = isBackground;
|
|
1697
|
+
this._terminalChatService.registerTerminalInstanceWithToolSession(terminalToolSessionId, toolTerminal.instance);
|
|
1698
|
+
this._terminalChatService.registerTerminalInstanceWithChatSession(chatSessionResource, toolTerminal.instance);
|
|
1699
|
+
this._registerInputListener(toolTerminal);
|
|
1700
|
+
this._addSessionTerminalAssociation(chatSessionResource, toolTerminal);
|
|
1701
|
+
if (token.isCancellationRequested) {
|
|
1702
|
+
toolTerminal.instance.dispose();
|
|
1703
|
+
throw ( new CancellationError());
|
|
1704
|
+
}
|
|
1705
|
+
await this._setupProcessIdAssociation(toolTerminal, chatSessionResource, termId, isBackground);
|
|
1706
|
+
return toolTerminal;
|
|
1707
|
+
}
|
|
1708
|
+
_registerInputListener(toolTerminal) {
|
|
1709
|
+
const disposable = toolTerminal.instance.onData(data => {
|
|
1710
|
+
if (!telemetryIgnoredSequences.includes(data)) {
|
|
1711
|
+
toolTerminal.receivedUserInput = data.length > 0;
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
Event.once(toolTerminal.instance.onDisposed)(() => disposable.dispose());
|
|
1715
|
+
}
|
|
1716
|
+
_restoreTerminalAssociations() {
|
|
1717
|
+
const storedAssociations = this._storageService.get(
|
|
1718
|
+
TerminalToolStorageKeysInternal.TerminalSession,
|
|
1719
|
+
StorageScope.WORKSPACE,
|
|
1720
|
+
"{}"
|
|
1721
|
+
);
|
|
1722
|
+
try {
|
|
1723
|
+
const associations = JSON.parse(storedAssociations);
|
|
1724
|
+
for (const instance of this._terminalService.instances) {
|
|
1725
|
+
if (instance.processId) {
|
|
1726
|
+
const association = associations[instance.processId];
|
|
1727
|
+
if (association) {
|
|
1728
|
+
const chatSessionResource = LocalChatSessionUri.forSession(association.sessionId);
|
|
1729
|
+
this._logService.debug(
|
|
1730
|
+
`RunInTerminalTool: Restored terminal association for PID ${instance.processId}, session ${association.sessionId}`
|
|
1731
|
+
);
|
|
1732
|
+
const toolTerminal = {
|
|
1733
|
+
instance,
|
|
1734
|
+
shellIntegrationQuality: association.shellIntegrationQuality,
|
|
1735
|
+
isBackground: association.isBackground
|
|
1736
|
+
};
|
|
1737
|
+
this._addSessionTerminalAssociation(chatSessionResource, toolTerminal);
|
|
1738
|
+
this._terminalChatService.registerTerminalInstanceWithChatSession(chatSessionResource, instance);
|
|
1739
|
+
if (association.id) {
|
|
1740
|
+
RunInTerminalTool_1._activeExecutions.set(association.id, this._register(( new RestoredTerminalExecution(instance))));
|
|
1741
|
+
}
|
|
1742
|
+
Event.once(instance.onDisposed)(() => {
|
|
1743
|
+
this._removeProcessIdAssociation(instance.processId);
|
|
1744
|
+
this._removeExecutionAssociations(instance);
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
} catch (error) {
|
|
1750
|
+
this._logService.debug(`RunInTerminalTool: Failed to restore terminal associations: ${error}`);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
async _setupProcessIdAssociation(toolTerminal, chatSessionResource, termId, isBackground) {
|
|
1754
|
+
await this._associateProcessIdWithSession(
|
|
1755
|
+
toolTerminal.instance,
|
|
1756
|
+
chatSessionResource,
|
|
1757
|
+
termId,
|
|
1758
|
+
toolTerminal.shellIntegrationQuality,
|
|
1759
|
+
isBackground
|
|
1760
|
+
);
|
|
1761
|
+
Event.once(toolTerminal.instance.onDisposed)(() => {
|
|
1762
|
+
if (toolTerminal.instance.processId) {
|
|
1763
|
+
this._removeProcessIdAssociation(toolTerminal.instance.processId);
|
|
1764
|
+
}
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
async _associateProcessIdWithSession(terminal, chatSessionResource, id, shellIntegrationQuality, isBackground) {
|
|
1768
|
+
try {
|
|
1769
|
+
const pid = await Promise.race([
|
|
1770
|
+
terminal.processReady.then(() => terminal.processId),
|
|
1771
|
+
timeout(5000).then(() => {
|
|
1772
|
+
throw ( new Error("Timeout"));
|
|
1773
|
+
})
|
|
1774
|
+
]);
|
|
1775
|
+
if (isNumber(pid)) {
|
|
1776
|
+
const storedAssociations = this._storageService.get(
|
|
1777
|
+
TerminalToolStorageKeysInternal.TerminalSession,
|
|
1778
|
+
StorageScope.WORKSPACE,
|
|
1779
|
+
"{}"
|
|
1780
|
+
);
|
|
1781
|
+
const associations = JSON.parse(storedAssociations);
|
|
1782
|
+
const sessionId = chatSessionResourceToId(chatSessionResource);
|
|
1783
|
+
const existingAssociation = associations[pid] || {};
|
|
1784
|
+
associations[pid] = {
|
|
1785
|
+
...existingAssociation,
|
|
1786
|
+
sessionId,
|
|
1787
|
+
shellIntegrationQuality,
|
|
1788
|
+
id,
|
|
1789
|
+
isBackground
|
|
1790
|
+
};
|
|
1791
|
+
this._storageService.store(
|
|
1792
|
+
TerminalToolStorageKeysInternal.TerminalSession,
|
|
1793
|
+
JSON.stringify(associations),
|
|
1794
|
+
StorageScope.WORKSPACE,
|
|
1795
|
+
StorageTarget.USER
|
|
1796
|
+
);
|
|
1797
|
+
this._logService.debug(
|
|
1798
|
+
`RunInTerminalTool: Associated terminal PID ${pid} with session ${sessionId}`
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
} catch (error) {
|
|
1802
|
+
this._logService.debug(`RunInTerminalTool: Failed to associate terminal with session: ${error}`);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
async _removeProcessIdAssociation(pid) {
|
|
1806
|
+
try {
|
|
1807
|
+
const storedAssociations = this._storageService.get(
|
|
1808
|
+
TerminalToolStorageKeysInternal.TerminalSession,
|
|
1809
|
+
StorageScope.WORKSPACE,
|
|
1810
|
+
"{}"
|
|
1811
|
+
);
|
|
1812
|
+
const associations = JSON.parse(storedAssociations);
|
|
1813
|
+
if (associations[pid]) {
|
|
1814
|
+
delete associations[pid];
|
|
1815
|
+
this._storageService.store(
|
|
1816
|
+
TerminalToolStorageKeysInternal.TerminalSession,
|
|
1817
|
+
JSON.stringify(associations),
|
|
1818
|
+
StorageScope.WORKSPACE,
|
|
1819
|
+
StorageTarget.USER
|
|
1820
|
+
);
|
|
1821
|
+
this._logService.debug(`RunInTerminalTool: Removed terminal association for PID ${pid}`);
|
|
1822
|
+
}
|
|
1823
|
+
} catch (error) {
|
|
1824
|
+
this._logService.debug(`RunInTerminalTool: Failed to remove terminal association: ${error}`);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
_cleanupSessionTerminals(chatSessionResource) {
|
|
1828
|
+
const sessionTerminals = this._sessionTerminalInstances.get(chatSessionResource);
|
|
1829
|
+
const toolTerminal = this._sessionTerminalAssociations.get(chatSessionResource);
|
|
1830
|
+
const terminalsToDispose = sessionTerminals ?? (toolTerminal ? ( new Set([toolTerminal.instance])) : undefined);
|
|
1831
|
+
if (!terminalsToDispose || terminalsToDispose.size === 0) {
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
this._logService.debug(
|
|
1835
|
+
`RunInTerminalTool: Cleaning up ${terminalsToDispose.size} terminal(s) for ended chat session ${chatSessionResource}`
|
|
1836
|
+
);
|
|
1837
|
+
this._sessionTerminalAssociations.delete(chatSessionResource);
|
|
1838
|
+
this._sessionTerminalInstances.delete(chatSessionResource);
|
|
1839
|
+
for (const terminal of terminalsToDispose) {
|
|
1840
|
+
this._terminalsBeingDisposedBySessionCleanup.add(terminal);
|
|
1841
|
+
terminal.dispose();
|
|
1842
|
+
}
|
|
1843
|
+
const terminalToRemove = [];
|
|
1844
|
+
for (const [termId, execution] of RunInTerminalTool_1._activeExecutions.entries()) {
|
|
1845
|
+
if (( terminalsToDispose.has(execution.instance))) {
|
|
1846
|
+
execution.dispose();
|
|
1847
|
+
terminalToRemove.push(termId);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
for (const termId of terminalToRemove) {
|
|
1851
|
+
RunInTerminalTool_1._activeExecutions.delete(termId);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
_addSessionTerminalAssociation(chatSessionResource, toolTerminal) {
|
|
1855
|
+
this._ensureArchivedSessionListener();
|
|
1856
|
+
let sessionTerminals = this._sessionTerminalInstances.get(chatSessionResource);
|
|
1857
|
+
if (!sessionTerminals) {
|
|
1858
|
+
sessionTerminals = ( new Set());
|
|
1859
|
+
this._sessionTerminalInstances.set(chatSessionResource, sessionTerminals);
|
|
1860
|
+
}
|
|
1861
|
+
sessionTerminals.add(toolTerminal.instance);
|
|
1862
|
+
if (!toolTerminal.isBackground) {
|
|
1863
|
+
this._sessionTerminalAssociations.set(chatSessionResource, toolTerminal);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
_ensureArchivedSessionListener() {
|
|
1867
|
+
if (this._archivedSessionListener.value) {
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
this._archivedSessionListener.value = this._agentSessionsService.onDidChangeSessionArchivedState(session => {
|
|
1871
|
+
if (session.isArchived()) {
|
|
1872
|
+
this._cleanupSessionTerminals(session.resource);
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
_removeTerminalAssociations(terminal) {
|
|
1877
|
+
if (this._terminalsBeingDisposedBySessionCleanup.delete(terminal)) {
|
|
1878
|
+
this._removeExecutionAssociations(terminal);
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
for (const [sessionResource, toolTerminal] of this._sessionTerminalAssociations.entries()) {
|
|
1882
|
+
if (terminal === toolTerminal.instance) {
|
|
1883
|
+
this._sessionTerminalAssociations.delete(sessionResource);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
for (const [sessionResource, sessionTerminals] of this._sessionTerminalInstances.entries()) {
|
|
1887
|
+
if (!sessionTerminals.delete(terminal)) {
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1890
|
+
if (sessionTerminals.size === 0) {
|
|
1891
|
+
this._sessionTerminalInstances.delete(sessionResource);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
this._removeExecutionAssociations(terminal);
|
|
1895
|
+
}
|
|
1896
|
+
_removeExecutionAssociations(terminal) {
|
|
1897
|
+
const executionIdsToRemove = [];
|
|
1898
|
+
for (const [termId, execution] of RunInTerminalTool_1._activeExecutions.entries()) {
|
|
1899
|
+
if (execution.instance === terminal) {
|
|
1900
|
+
execution.dispose();
|
|
1901
|
+
executionIdsToRemove.push(termId);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
for (const termId of executionIdsToRemove) {
|
|
1905
|
+
RunInTerminalTool_1._activeExecutions.delete(termId);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
_registerCompletionNotification(terminalInstance, termId, chatSessionResource, commandName, outputMonitor) {
|
|
1909
|
+
this._backgroundNotifications.deleteAndDispose(termId);
|
|
1910
|
+
const commandDetection = terminalInstance.capabilities.get(TerminalCapability.CommandDetection);
|
|
1911
|
+
if (!commandDetection) {
|
|
1912
|
+
outputMonitor?.dispose();
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
const sessionRef = this._chatService.acquireExistingSession(chatSessionResource, "RunInTerminalTool#completionNotification");
|
|
1916
|
+
if (!sessionRef) {
|
|
1917
|
+
this._logService.warn(
|
|
1918
|
+
`RunInTerminalTool: Cannot register completion notification for terminal ${termId} - session already disposed`
|
|
1919
|
+
);
|
|
1920
|
+
outputMonitor?.dispose();
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const lastRequest = sessionRef.object.lastRequest;
|
|
1924
|
+
const sendOptions = {};
|
|
1925
|
+
if (lastRequest) {
|
|
1926
|
+
sendOptions.userSelectedModelId = lastRequest.modelId;
|
|
1927
|
+
sendOptions.modeInfo = lastRequest.modeInfo;
|
|
1928
|
+
if (lastRequest.userSelectedTools) {
|
|
1929
|
+
sendOptions.userSelectedTools = constObservable(lastRequest.userSelectedTools);
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
const store = ( new DisposableStore());
|
|
1933
|
+
let userIsReplyingDirectly = false;
|
|
1934
|
+
const disposeNotification = () => this._backgroundNotifications.deleteAndDispose(termId);
|
|
1935
|
+
const handleSessionCancelled = () => {
|
|
1936
|
+
if (sessionRef.object.lastRequest?.response?.isCanceled) {
|
|
1937
|
+
disposeNotification();
|
|
1938
|
+
return true;
|
|
1939
|
+
}
|
|
1940
|
+
return false;
|
|
1941
|
+
};
|
|
1942
|
+
store.add(autorun(reader => {
|
|
1943
|
+
const request = sessionRef.object.lastRequestObs.read(reader);
|
|
1944
|
+
if (!request?.response) {
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
reader.store.add(request.response.onDidChange(ev => {
|
|
1948
|
+
if (ev.reason === "completedRequest" && request.response.isCanceled) {
|
|
1949
|
+
disposeNotification();
|
|
1950
|
+
}
|
|
1951
|
+
}));
|
|
1952
|
+
}));
|
|
1953
|
+
if (outputMonitor) {
|
|
1954
|
+
let lastInputNeededOutput = "";
|
|
1955
|
+
let lastInputNeededNotificationTime = 0;
|
|
1956
|
+
const bgCts = ( new CancellationTokenSource());
|
|
1957
|
+
store.add(toDisposable(() => {
|
|
1958
|
+
bgCts.cancel();
|
|
1959
|
+
bgCts.dispose();
|
|
1960
|
+
}));
|
|
1961
|
+
store.add(outputMonitor);
|
|
1962
|
+
outputMonitor.continueMonitoringAsync(bgCts.token);
|
|
1963
|
+
store.add(outputMonitor.onDidDetectInputNeeded(() => {
|
|
1964
|
+
if (userIsReplyingDirectly) {
|
|
1965
|
+
this._logService.debug(
|
|
1966
|
+
`RunInTerminalTool: Suppressing input-needed notification for terminal ${termId} because user is replying directly`
|
|
1967
|
+
);
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
if (handleSessionCancelled()) {
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
const execution = RunInTerminalTool_1._activeExecutions.get(termId);
|
|
1974
|
+
if (!execution) {
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
const currentOutput = execution.getOutput();
|
|
1978
|
+
const now = Date.now();
|
|
1979
|
+
const isDuplicate = currentOutput === lastInputNeededOutput && now - lastInputNeededNotificationTime < INPUT_NEEDED_NOTIFICATION_THROTTLE_MS;
|
|
1980
|
+
if (isDuplicate) {
|
|
1981
|
+
return;
|
|
1982
|
+
}
|
|
1983
|
+
lastInputNeededOutput = currentOutput;
|
|
1984
|
+
lastInputNeededNotificationTime = now;
|
|
1985
|
+
const isAutoApproved = isSessionAutoApproveLevel(
|
|
1986
|
+
chatSessionResource,
|
|
1987
|
+
this._configurationService,
|
|
1988
|
+
this._chatWidgetService,
|
|
1989
|
+
this._chatService
|
|
1990
|
+
);
|
|
1991
|
+
const inputAction = isAutoApproved ? `Determine the answer and call ${TerminalToolId.SendToTerminal}. Then call ${TerminalToolId.GetTerminalOutput} to read the next prompt. Repeat one prompt at a time. A normal shell prompt does NOT count as waiting for input.` : `Call the vscode_askQuestions tool to ask the user. Then send each answer using ${TerminalToolId.SendToTerminal}, calling ${TerminalToolId.GetTerminalOutput} between each. A normal shell prompt does NOT count as waiting for input.`;
|
|
1992
|
+
const message = `[Terminal ${termId} notification: command is waiting for input. ${inputAction}]\nTerminal output:\n${currentOutput}`;
|
|
1993
|
+
this._logService.debug(
|
|
1994
|
+
`RunInTerminalTool: Input needed in background terminal ${termId}, notifying chat session`
|
|
1995
|
+
);
|
|
1996
|
+
this._chatService.sendRequest(chatSessionResource, message, {
|
|
1997
|
+
...sendOptions,
|
|
1998
|
+
queue: ChatRequestQueueKind.Steering,
|
|
1999
|
+
isSystemInitiated: true,
|
|
2000
|
+
systemInitiatedLabel: ( localize(14079, "`{0}` needs input", commandName)),
|
|
2001
|
+
terminalExecutionId: termId
|
|
2002
|
+
}).catch(e => {
|
|
2003
|
+
this._logService.warn(
|
|
2004
|
+
`RunInTerminalTool: Failed to send input-needed notification for terminal ${termId}`,
|
|
2005
|
+
e
|
|
2006
|
+
);
|
|
2007
|
+
});
|
|
2008
|
+
}));
|
|
2009
|
+
}
|
|
2010
|
+
store.add(terminalInstance.onDidInputData(() => {
|
|
2011
|
+
if (userIsReplyingDirectly) {
|
|
2012
|
+
return;
|
|
2013
|
+
}
|
|
2014
|
+
userIsReplyingDirectly = true;
|
|
2015
|
+
this._dismissPendingCarouselsForTerminal(chatSessionResource, termId);
|
|
2016
|
+
}));
|
|
2017
|
+
store.add(sessionRef);
|
|
2018
|
+
store.add(commandDetection.onCommandFinished(command => {
|
|
2019
|
+
const execution = RunInTerminalTool_1._activeExecutions.get(termId);
|
|
2020
|
+
if (!execution) {
|
|
2021
|
+
disposeNotification();
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
if (handleSessionCancelled()) {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
disposeNotification();
|
|
2028
|
+
const exitCode = command.exitCode;
|
|
2029
|
+
const exitCodeText = exitCode !== undefined ? ` with exit code ${exitCode}` : "";
|
|
2030
|
+
const currentOutput = execution.getOutput();
|
|
2031
|
+
const message = `[Terminal ${termId} notification: command completed${exitCodeText}. Use send_to_terminal to send another command or kill_terminal to stop it.]\nTerminal output:\n${currentOutput}`;
|
|
2032
|
+
this._logService.debug(
|
|
2033
|
+
`RunInTerminalTool: Command completed in background terminal ${termId}, notifying chat session`
|
|
2034
|
+
);
|
|
2035
|
+
this._chatService.sendRequest(chatSessionResource, message, {
|
|
2036
|
+
...sendOptions,
|
|
2037
|
+
queue: ChatRequestQueueKind.Steering,
|
|
2038
|
+
isSystemInitiated: true,
|
|
2039
|
+
systemInitiatedLabel: ( localize(14080, "`{0}` completed", commandName)),
|
|
2040
|
+
terminalExecutionId: termId
|
|
2041
|
+
}).catch(e => {
|
|
2042
|
+
this._logService.warn(
|
|
2043
|
+
`RunInTerminalTool: Failed to send completion notification for terminal ${termId}`,
|
|
2044
|
+
e
|
|
2045
|
+
);
|
|
2046
|
+
});
|
|
2047
|
+
}));
|
|
2048
|
+
store.add(terminalInstance.onDisposed(() => {
|
|
2049
|
+
disposeNotification();
|
|
2050
|
+
}));
|
|
2051
|
+
store.add(sessionRef.object.onDidChange(e => {
|
|
2052
|
+
if (e.kind === "removeRequest") {
|
|
2053
|
+
this._logService.debug(
|
|
2054
|
+
`RunInTerminalTool: Request removed from session, cleaning up background terminal ${termId}`
|
|
2055
|
+
);
|
|
2056
|
+
RunInTerminalTool_1._activeExecutions.get(termId)?.dispose();
|
|
2057
|
+
RunInTerminalTool_1._activeExecutions.delete(termId);
|
|
2058
|
+
disposeNotification();
|
|
2059
|
+
terminalInstance.dispose();
|
|
2060
|
+
}
|
|
2061
|
+
}));
|
|
2062
|
+
this._backgroundNotifications.set(termId, store);
|
|
2063
|
+
}
|
|
2064
|
+
_dismissPendingCarouselsForTerminal(chatSessionResource, termId) {
|
|
2065
|
+
const model = this._chatService.getSession(chatSessionResource);
|
|
2066
|
+
if (!model) {
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
const requests = model.getRequests();
|
|
2070
|
+
for (let i = requests.length - 1; i >= 0; i--) {
|
|
2071
|
+
const response = requests[i].response;
|
|
2072
|
+
if (!response) {
|
|
2073
|
+
continue;
|
|
2074
|
+
}
|
|
2075
|
+
const parts = response.response.value;
|
|
2076
|
+
for (let j = parts.length - 1; j >= 0; j--) {
|
|
2077
|
+
const part = parts[j];
|
|
2078
|
+
if (part instanceof ChatQuestionCarouselData && part.terminalId === termId && !part.isUsed) {
|
|
2079
|
+
this._logService.debug(
|
|
2080
|
+
`RunInTerminalTool: Dismissing pending carousel for terminal ${termId} because user typed directly in terminal`
|
|
2081
|
+
);
|
|
2082
|
+
part.data = {};
|
|
2083
|
+
part.isUsed = true;
|
|
2084
|
+
part.dismissedByTerminalInput = true;
|
|
2085
|
+
part.completion.complete({
|
|
2086
|
+
answers: undefined
|
|
2087
|
+
});
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
RunInTerminalTool = RunInTerminalTool_1 = ( __decorate([( __param(0, IChatService)), ( __param(1, IConfigurationService)), ( __param(2, IFileService)), ( __param(3, IHistoryService)), ( __param(4, IInstantiationService)), ( __param(5, ILabelService)), ( __param(6, ILanguageModelToolsService)), ( __param(7, IRemoteAgentService)), ( __param(8, IStorageService)), ( __param(9, ITerminalChatService)), ( __param(10, ITerminalLogService)), ( __param(11, ITerminalService)), ( __param(12, ITerminalSandboxService)), ( __param(13, IWorkspaceContextService)), ( __param(14, IChatWidgetService)), ( __param(15, IAgentSessionsService))], RunInTerminalTool));
|
|
2095
|
+
let ActiveTerminalExecution = class ActiveTerminalExecution extends Disposable {
|
|
2096
|
+
get completionPromise() {
|
|
2097
|
+
return this._completionDeferred.p;
|
|
2098
|
+
}
|
|
2099
|
+
get isBackground() {
|
|
2100
|
+
return this._isBackground;
|
|
2101
|
+
}
|
|
2102
|
+
get startMarker() {
|
|
2103
|
+
return this._startMarker;
|
|
2104
|
+
}
|
|
2105
|
+
get instance() {
|
|
2106
|
+
return this._toolTerminal.instance;
|
|
2107
|
+
}
|
|
2108
|
+
constructor(
|
|
2109
|
+
sessionResource,
|
|
2110
|
+
termId,
|
|
2111
|
+
toolTerminal,
|
|
2112
|
+
commandDetection,
|
|
2113
|
+
isBackground,
|
|
2114
|
+
_instantiationService
|
|
2115
|
+
) {
|
|
2116
|
+
super();
|
|
2117
|
+
this.sessionResource = sessionResource;
|
|
2118
|
+
this.termId = termId;
|
|
2119
|
+
this._instantiationService = _instantiationService;
|
|
2120
|
+
this._toolTerminal = toolTerminal;
|
|
2121
|
+
this._isBackground = isBackground;
|
|
2122
|
+
this._completionDeferred = ( new DeferredPromise());
|
|
2123
|
+
this.strategy = this._register(this._createStrategy(commandDetection));
|
|
2124
|
+
this._register(this.strategy.onDidCreateStartMarker(marker => {
|
|
2125
|
+
if (marker) {
|
|
2126
|
+
this._startMarker = marker;
|
|
2127
|
+
}
|
|
2128
|
+
}));
|
|
2129
|
+
}
|
|
2130
|
+
_createStrategy(commandDetection) {
|
|
2131
|
+
switch (this._toolTerminal.shellIntegrationQuality) {
|
|
2132
|
+
case ShellIntegrationQuality.None:
|
|
2133
|
+
return this._instantiationService.createInstance(
|
|
2134
|
+
NoneExecuteStrategy,
|
|
2135
|
+
this._toolTerminal.instance,
|
|
2136
|
+
() => this._toolTerminal.receivedUserInput ?? false
|
|
2137
|
+
);
|
|
2138
|
+
case ShellIntegrationQuality.Basic:
|
|
2139
|
+
return this._instantiationService.createInstance(
|
|
2140
|
+
BasicExecuteStrategy,
|
|
2141
|
+
this._toolTerminal.instance,
|
|
2142
|
+
() => this._toolTerminal.receivedUserInput ?? false,
|
|
2143
|
+
commandDetection
|
|
2144
|
+
);
|
|
2145
|
+
case ShellIntegrationQuality.Rich:
|
|
2146
|
+
return this._instantiationService.createInstance(RichExecuteStrategy, this._toolTerminal.instance, commandDetection);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
async start(commandLine, token, commandId, commandLineForMetadata) {
|
|
2150
|
+
try {
|
|
2151
|
+
const result = await this.strategy.execute(commandLine, token, commandId, commandLineForMetadata);
|
|
2152
|
+
this._completionDeferred.complete(result);
|
|
2153
|
+
return result;
|
|
2154
|
+
} catch (e) {
|
|
2155
|
+
this._completionDeferred.error(e);
|
|
2156
|
+
throw e;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
setForeground() {
|
|
2160
|
+
this._isBackground = false;
|
|
2161
|
+
}
|
|
2162
|
+
setBackground() {
|
|
2163
|
+
this._isBackground = true;
|
|
2164
|
+
}
|
|
2165
|
+
getOutput(marker) {
|
|
2166
|
+
return getOutput(this.instance, marker ?? this._startMarker);
|
|
2167
|
+
}
|
|
2168
|
+
};
|
|
2169
|
+
ActiveTerminalExecution = ( __decorate([( __param(5, IInstantiationService))], ActiveTerminalExecution));
|
|
2170
|
+
class RestoredTerminalExecution extends Disposable {
|
|
2171
|
+
constructor(instance) {
|
|
2172
|
+
super();
|
|
2173
|
+
this.instance = instance;
|
|
2174
|
+
this.completionPromise = Promise.resolve({
|
|
2175
|
+
output: undefined,
|
|
2176
|
+
error: "restoredTerminalExecutionNotAwaitable"
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
getOutput(marker) {
|
|
2180
|
+
return getOutput(this.instance, marker);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
let TerminalProfileFetcher = class TerminalProfileFetcher {
|
|
2184
|
+
constructor(
|
|
2185
|
+
_configurationService,
|
|
2186
|
+
_terminalProfileResolverService,
|
|
2187
|
+
_remoteAgentService
|
|
2188
|
+
) {
|
|
2189
|
+
this._configurationService = _configurationService;
|
|
2190
|
+
this._terminalProfileResolverService = _terminalProfileResolverService;
|
|
2191
|
+
this._remoteAgentService = _remoteAgentService;
|
|
2192
|
+
this.osBackend = this._remoteAgentService.getEnvironment().then(remoteEnv => remoteEnv?.os ?? OS);
|
|
2193
|
+
}
|
|
2194
|
+
async getCopilotProfile() {
|
|
2195
|
+
const os = await this.osBackend;
|
|
2196
|
+
const customChatAgentProfile = this._getChatTerminalProfile(os);
|
|
2197
|
+
if (customChatAgentProfile) {
|
|
2198
|
+
return customChatAgentProfile;
|
|
2199
|
+
}
|
|
2200
|
+
const defaultProfile = await this._terminalProfileResolverService.getDefaultProfile({
|
|
2201
|
+
os,
|
|
2202
|
+
remoteAuthority: this._remoteAgentService.getConnection()?.remoteAuthority
|
|
2203
|
+
});
|
|
2204
|
+
if (basename(defaultProfile.path) === "cmd.exe") {
|
|
2205
|
+
return {
|
|
2206
|
+
...defaultProfile,
|
|
2207
|
+
path: "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
|
|
2208
|
+
profileName: "PowerShell"
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
if (defaultProfile.path === "/bin/sh") {
|
|
2212
|
+
return {
|
|
2213
|
+
...defaultProfile,
|
|
2214
|
+
path: "/bin/bash",
|
|
2215
|
+
profileName: "bash"
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
return {
|
|
2219
|
+
...defaultProfile,
|
|
2220
|
+
icon: undefined
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
async getCopilotShell() {
|
|
2224
|
+
return (await this.getCopilotProfile()).path;
|
|
2225
|
+
}
|
|
2226
|
+
_getChatTerminalProfile(os) {
|
|
2227
|
+
let profileSetting;
|
|
2228
|
+
switch (os) {
|
|
2229
|
+
case OperatingSystem.Windows:
|
|
2230
|
+
profileSetting = TerminalChatAgentToolsSettingId.TerminalProfileWindows;
|
|
2231
|
+
break;
|
|
2232
|
+
case OperatingSystem.Macintosh:
|
|
2233
|
+
profileSetting = TerminalChatAgentToolsSettingId.TerminalProfileMacOs;
|
|
2234
|
+
break;
|
|
2235
|
+
case OperatingSystem.Linux:
|
|
2236
|
+
default:
|
|
2237
|
+
profileSetting = TerminalChatAgentToolsSettingId.TerminalProfileLinux;
|
|
2238
|
+
break;
|
|
2239
|
+
}
|
|
2240
|
+
const profile = this._configurationService.getValue(profileSetting);
|
|
2241
|
+
if (this._isValidChatAgentTerminalProfile(profile)) {
|
|
2242
|
+
return profile;
|
|
2243
|
+
}
|
|
2244
|
+
return undefined;
|
|
2245
|
+
}
|
|
2246
|
+
_isValidChatAgentTerminalProfile(profile) {
|
|
2247
|
+
if (profile === null || profile === undefined || typeof profile !== "object") {
|
|
2248
|
+
return false;
|
|
2249
|
+
}
|
|
2250
|
+
if ("path" in profile && isString(profile.path)) {
|
|
2251
|
+
return true;
|
|
2252
|
+
}
|
|
2253
|
+
return false;
|
|
2254
|
+
}
|
|
2255
|
+
};
|
|
2256
|
+
TerminalProfileFetcher = ( __decorate([( __param(0, IConfigurationService)), ( __param(1, ITerminalProfileResolverService)), ( __param(2, IRemoteAgentService))], TerminalProfileFetcher));
|
|
2257
|
+
|
|
2258
|
+
export { RunInTerminalTool, TerminalProfileFetcher, createRunInTerminalToolData, shouldAutomaticallyRetryUnsandboxed };
|