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