src/vs/workbench/api/common/extHostCommands.ts

507 LOC · 152 covered · 355 uncovered · 21 ranges · 47 concepts · 1 introducers · 42 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/workbench/api/common/extHostTelemetry.ts · 343 LOCcommon/extHostTelemetry.…src/vs/workbench/api/common/extHostTerminalService.ts · 1338 LOCcommon/extHostTerminalSe…src/vs/workbench/api/common/extHostTestItem.ts · 197 LOCcommon/extHostTestItem.t…src/vs/workbench/services/extensions/common/extensionHostProtocol.ts · 163 LOCcommon/extensionHostProt…extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should expose readonly properties|occurrence=1, extHostMcp.test|title=ExtHostMcp createAuthMetadata should create IAuthMetadata with fetched server metadata|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.ts ×1 · 3 introduced LOCextHostMcp.ts ×1extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should handle multiple Bearer challenges and use first scope|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when scopes are the same|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true and update scopes when WWW-Authenticate header contains new scopes|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when scopes are same but in different order|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true when updating from defined scopes to undefined (no scope in header)|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle non-401 status codes in update()|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should ignore non-Bearer schemes|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true when updating from undefined scopes to defined scopes|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.ts ×1 · 1 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×1 · 2 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×1 · 6 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×1 · 4 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×2 · 4 introduced LOCextHostMcp.ts ×2extHostMcp.ts ×1 · 1 introduced LOCextHostMcp.ts ×1extHostMcp.test|title=ExtHostMcp createAuthMetadata should fall back to default metadata when server metadata fetch fails|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.ts ×4 · 6 introduced LOCextHostMcp.ts ×4extHostMcp.test|title=ExtHostMcp createAuthMetadata should use scopes from WWW-Authenticate header when resource metadata has none|occurrence=1, extHostMcp.test|title=ExtHostMcp createAuthMetadata should use scopes from WWW-Authenticate header even when resource metadata has scopes_supported|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.ts ×1 · 2 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×1 · 6 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×4 · 13 introduced LOCextHostMcp.ts ×4extHostMcpNode.ts ×8 · 45 introduced LOCextHostMcpNode.ts ×8extHostMcp.test|title=ExtHostMcp createAuthMetadata should pass launch headers when fetching metadata from same origin|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.ts ×5 · 25 introduced LOCextHostMcp.ts ×5extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle invalid JSON in resource metadata response|occurrence=1 · 0 introduced LOCextHostMcp.test|title=Ex…extHostMcp.ts ×3 · 23 introduced LOCextHostMcp.ts ×3extHostMcp.ts ×1 · 2 introduced LOCextHostMcp.ts ×1extHostMcp.ts ×8 · 60 introduced LOCextHostMcp.ts ×8extHostMcp.ts ×43 · 874 introduced LOCextHostMcp.ts ×43extensionHostMain.ts ×1 · 2 introduced LOCextensionHostMain.ts ×1reset prepareStackTrace-callback|occurrence=1, extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 prevent rewrapping|occurrence=1 · 0 introduced LOCreset prepareStackTrace-…extensionHostMain.ts ×5 · 26 introduced LOCextensionHostMain.ts ×5f0f2e182082072efdaf0f8e1537d2cce Restored, too many uses before restoration|occurrence=1 · 0 introduced LOCf0f2e182082072efdaf0f8e1…extensionHostMain.ts ×1 · 3 introduced LOCextensionHostMain.ts ×1extensionHostMain.ts ×1 · 3 introduced LOCextensionHostMain.ts ×1extensionHostMain.ts ×11 · 164 introduced LOCextensionHostMain.ts ×11extHostExtensionService.ts ×64 · 1246 introduced LOCextHostExtensionService.…extHostTerminalService.ts ×31 · 156 introduced LOCextHostTerminalService.t…extHostTerminalShellIntegration.ts ×3 · 13 introduced LOCextHostTerminalShellInte…extHostTerminalShellIntegration.ts ×6 · 28 introduced LOCextHostTerminalShellInte…extHostTerminalShellIntegration.ts ×13 · 51 introduced LOCextHostTerminalShellInte…extHostTerminalShellIntegration.ts ×1 · 4 introduced LOCextHostTerminalShellInte…extHostTerminalShellIntegration.ts ×1 · 3 introduced LOCextHostTerminalShellInte…extHostTerminalShellIntegration.ts ×1 · 2 introduced LOCextHostTerminalShellInte…extHostTerminalShellIntegration.ts ×29 · 253 introduced LOCextHostTerminalShellInte…extHostTerminalService.ts ×109 · 894 introduced LOCextHostTerminalService.t…extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should allow undefined scopes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should allow undefined scopes|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should expose readonly properties|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata properties should expose readonly properties|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should handle multiple Bearer challenges and use first scope|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should handle multiple Bearer challenges and use first scope|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should ignore non-Bearer schemes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should ignore non-Bearer schemes|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when no WWW-Authenticate header and scopes are already undefined|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when no WWW-Authenticate header and scopes are already undefined|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when scopes are same but in different order|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when scopes are same but in different order|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when scopes are the same|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return false when scopes are the same|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true and update scopes when WWW-Authenticate header contains new scopes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true and update scopes when WWW-Authenticate header contains new scopes|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true when updating from defined scopes to undefined (no scope in header)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true when updating from defined scopes to undefined (no scope in header)|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true when updating from undefined scopes to defined scopes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp IAuthMetadata update() should return true when updating from undefined scopes to defined scopes|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should create IAuthMetadata with fetched server metadata|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should create IAuthMetadata with fetched server metadata|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should fall back to default metadata when server metadata fetch fails|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should fall back to default metadata when server metadata fetch fails|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle empty scope string in WWW-Authenticate header|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle empty scope string in WWW-Authenticate header|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle invalid JSON in resource metadata response|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle invalid JSON in resource metadata response|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle malformed WWW-Authenticate header gracefully|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle malformed WWW-Authenticate header gracefully|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle non-401 status codes in update()|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should handle non-401 status codes in update()|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should pass launch headers when fetching metadata from same origin|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should pass launch headers when fetching metadata from same origin|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should use resource_metadata challenge URL from WWW-Authenticate header|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should use resource_metadata challenge URL from WWW-Authenticate header|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should use scopes from WWW-Authenticate header even when resource metadata has scopes_supported|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should use scopes from WWW-Authenticate header even when resource metadata has scopes_supported|occurrence=1extHostMcp.test|title=Ex…extHostMcp.test|title=ExtHostMcp createAuthMetadata should use scopes from WWW-Authenticate header when resource metadata has none|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostMcp.test|title=ExtHostMcp createAuthMetadata should use scopes from WWW-Authenticate header when resource metadata has none|occurrence=1extHostMcp.test|title=Ex…extHostTerminalService.test|title=ExtHostTerminalService $acceptTerminalClosed cancels in-flight link providers and clears the link cache|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalService.test|title=ExtHostTerminalService $acceptTerminalClosed cancels in-flight link providers and clears the link cache|occurrence=1extHostTerminalService.t…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration different execution unexpectedly ended|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration different execution unexpectedly ended|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand 4 multi-line commands with output|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand 4 multi-line commands with output|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand ^C to clear previous command|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand ^C to clear previous command|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand multi-line command comment followed by long second command|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand multi-line command comment followed by long second command|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand multi-line command line|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand multi-line command line|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand multi-line command with long second command|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration executeCommand multi-line command with long second command|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration no end event|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration no end event|occurrence=1extHostTerminalShellInte…extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration simple execution|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostTerminalShellIntegration.test|title=InternalTerminalShellIntegration simple execution|occurrence=1extHostTerminalShellInte…extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 basics|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 basics|occurrence=1extensionHostMain.test|t…f0f2e182082072efdaf0f8e1537d2cce Never restored, separate operations|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 https://gist.github.com/thecrypticace/f0f2e182082072efdaf0f8e1537d2cce Never restored, separate operations|occurrence=1f0f2e182082072efdaf0f8e1…f0f2e182082072efdaf0f8e1537d2cce Restored, separate operations|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 https://gist.github.com/thecrypticace/f0f2e182082072efdaf0f8e1537d2cce Restored, separate operations|occurrence=1f0f2e182082072efdaf0f8e1…f0f2e182082072efdaf0f8e1537d2cce Restored, too many uses before restoration|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 https://gist.github.com/thecrypticace/f0f2e182082072efdaf0f8e1537d2cce Restored, too many uses before restoration|occurrence=1f0f2e182082072efdaf0f8e1…extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 prevent rewrapping|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 prevent rewrapping|occurrence=1extensionHostMain.test|t…reset prepareStackTrace-callback|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 set/reset prepareStackTrace-callback|occurrence=1reset prepareStackTrace-…extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 wrap prepareStackTrace-callback|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extensionHostMain.test|title=ExtensionHostMain#ErrorHandler - Wrapping prepareStackTrace can cause slowdown and eventual stack overflow #184926 wrap prepareStackTrace-callback|occurrence=1extensionHostMain.test|t…extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg does not add stray ^ to argument values|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg does not add stray ^ to argument values|occurrence=1extHostMcpNode.test|titl…extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg doubles embedded double quotes (cmd.exe convention)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg doubles embedded double quotes (cmd.exe convention)|occurrence=1extHostMcpNode.test|titl…extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg neutralizes cmd.exe metacharacters inside quotes (CVE-2024-27980)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg neutralizes cmd.exe metacharacters inside quotes (CVE-2024-27980)|occurrence=1extHostMcpNode.test|titl…extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg preserves paths with parentheses without injecting ^|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg preserves paths with parentheses without injecting ^|occurrence=1extHostMcpNode.test|titl…extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg preserves paths with spaces|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg preserves paths with spaces|occurrence=1extHostMcpNode.test|titl…extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg wraps simple values in double quotes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostMcpNode.test|title=extHostMcpNode - escapeCmdArg wraps simple values in double quotes|occurrence=1extHostMcpNode.test|titl…Focused file · src/vs/workbench/api/common/extHostCommands.ts · 507 LOCcommon/extHostCommands.t…

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- extHostTerminalService.ts ×109
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { validateConstraint } from '../../../base/common/types.js';
7 > import { ICommandMetadata } from '../../../platform/commands/common/commands.js';
8 > import * as extHostTypes from './extHostTypes.js';
9 > import * as extHostTypeConverter from './extHostTypeConverters.js';
10 > import { cloneAndChange } from '../../../base/common/objects.js';
11 > import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape, ICommandDto, ICommandMetadataDto, MainThreadTelemetryShape } from './extHost.protocol.js';
12 > import { isNonEmptyArray } from '../../../base/common/arrays.js';
13 > import * as languages from '../../../editor/common/languages.js';
14 > import type * as vscode from 'vscode';
15 > import { ILogService } from '../../../platform/log/common/log.js';
16 > import { revive } from '../../../base/common/marshalling.js';
17 > import { IRange, Range } from '../../../editor/common/core/range.js';
18 > import { IPosition, Position } from '../../../editor/common/core/position.js';
19 > import { URI } from '../../../base/common/uri.js';
20 > import { DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
21 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
22 > import { IExtHostRpcService } from './extHostRpcService.js';
23 > import { ISelection } from '../../../editor/common/core/selection.js';
24 > import { TestItemImpl } from './extHostTestItem.js';
25 > import { VSBuffer } from '../../../base/common/buffer.js';
26 > import { SerializableObjectWithBuffers } from '../../services/extensions/common/proxyIdentifier.js';
27 > import { toErrorMessage } from '../../../base/common/errorMessage.js';
28 > import { StopWatch } from '../../../base/common/stopwatch.js';
29 > import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
30 > import { TelemetryTrustedValue } from '../../../platform/telemetry/common/telemetryUtils.js';
31 > import { IExtHostTelemetry } from './extHostTelemetry.js';
32 > import { generateUuid } from '../../../base/common/uuid.js';
33 > import { isCancellationError } from '../../../base/common/errors.js';
34 >
35 > interface CommandHandler {
36 > callback: Function;
37 > thisArg: any;
38 > metadata?: ICommandMetadata;
39 > extension?: IExtensionDescription;
40 > }
41 >
42 > export interface ArgumentProcessor {
43 > processArgument(arg: any, extension: IExtensionDescription | undefined): any;
44 > }
45 >
46 > export class ExtHostCommands implements ExtHostCommandsShape {
47 >
48 > readonly _serviceBrand: undefined;
49 >
50 > #proxy: MainThreadCommandsShape;
51 >
52 > private readonly _commands = new Map<string, CommandHandler>();
53 > private readonly _apiCommands = new Map<string, ApiCommand>();
54 > #telemetry: MainThreadTelemetryShape;
55 >
56 > private readonly _logService: ILogService;
57 > readonly #extHostTelemetry: IExtHostTelemetry;
58 > private readonly _argumentProcessors: ArgumentProcessor[];
59 >
60 > readonly converter: CommandsConverter;
61 >
62 > constructor(
63 @IExtHostRpcService extHostRpc: IExtHostRpcService,
64 @ILogService logService: ILogService,
65 @IExtHostTelemetry extHostTelemetry: IExtHostTelemetry
66 ) {
67 this.#proxy = extHostRpc.getProxy(MainContext.MainThreadCommands);
68 this._logService = logService;
69 this.#extHostTelemetry = extHostTelemetry;
70 this.#telemetry = extHostRpc.getProxy(MainContext.MainThreadTelemetry);
71 this.converter = new CommandsConverter(
72 this,
73 id => {
74 // API commands that have no return type (void) can be
75 // converted to their internal command and don't need
76 // any indirection commands
77 const candidate = this._apiCommands.get(id);
78 return candidate?.result === ApiCommandResult.Void
79 ? candidate : undefined;
80 },
81 logService
82 );
83 this._argumentProcessors = [
84 {
85 processArgument(a) {
86 // URI, Regex
87 return revive(a);
88 }
89 },
90 {
91 processArgument(arg) {
92 return cloneAndChange(arg, function (obj) {
93 // Reverse of https://github.com/microsoft/vscode/blob/1f28c5fc681f4c01226460b6d1c7e91b8acb4a5b/src/vs/workbench/api/node/extHostCommands.ts#L112-L127
94 if (Range.isIRange(obj)) {
95 return extHostTypeConverter.Range.to(obj);
96 }
97 if (Position.isIPosition(obj)) {
98 return extHostTypeConverter.Position.to(obj);
99 }
100 if (Range.isIRange((obj as languages.Location).range) && URI.isUri((obj as languages.Location).uri)) {
101 return extHostTypeConverter.location.to(obj);
102 }
103 if (obj instanceof VSBuffer) {
104 return obj.buffer.buffer;
105 }
106 if (!Array.isArray(obj)) {
107 return obj;
108 }
109 });
110 }
111 }
112 ];
113 }
115 > registerArgumentProcessor(processor: ArgumentProcessor): void {
116 this._argumentProcessors.push(processor);
117 }
119 > registerApiCommand(apiCommand: ApiCommand): extHostTypes.Disposable {
120
121
122 const registration = this.registerCommand(false, apiCommand.id, async (...apiArgs) => {
123
124 const internalArgs = apiCommand.args.map((arg, i) => {
125 if (!arg.validate(apiArgs[i])) {
126 throw new Error(`Invalid argument '${arg.name}' when running '${apiCommand.id}', received: ${typeof apiArgs[i] === 'object' ? JSON.stringify(apiArgs[i], null, '\t') : apiArgs[i]} `);
127 }
128 return arg.convert(apiArgs[i]);
129 });
130
131 const internalResult = await this.executeCommand(apiCommand.internalId, ...internalArgs);
132 return apiCommand.result.convert(internalResult, apiArgs, this.converter);
133 }, undefined, {
134 description: apiCommand.description,
135 args: apiCommand.args,
136 returns: apiCommand.result.description
137 });
138
139 this._apiCommands.set(apiCommand.id, apiCommand);
140
141 return new extHostTypes.Disposable(() => {
142 registration.dispose();
143 this._apiCommands.delete(apiCommand.id);
144 });
145 }
147 > registerCommand(global: boolean, id: string, callback: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any, metadata?: ICommandMetadata, extension?: IExtensionDescription): extHostTypes.Disposable {
148 this._logService.trace('ExtHostCommands#registerCommand', id);
149
150 if (!id.trim().length) {
151 throw new Error('invalid id');
152 }
153
154 if (this._commands.has(id)) {
155 throw new Error(`command '${id}' already exists`);
156 }
157
158 this._commands.set(id, { callback, thisArg, metadata, extension });
159 if (global) {
160 this.#proxy.$registerCommand(id);
161 }
162
163 return new extHostTypes.Disposable(() => {
164 if (this._commands.delete(id)) {
165 if (global) {
166 this.#proxy.$unregisterCommand(id);
167 }
168 }
169 });
170 }
172 > executeCommand<T>(id: string, ...args: unknown[]): Promise<T> {
173 this._logService.trace('ExtHostCommands#executeCommand', id);
174 return this._doExecuteCommand(id, args, true);
175 }
177 > private async _doExecuteCommand<T>(id: string, args: unknown[], retry: boolean): Promise<T> {
178
179 if (this._commands.has(id)) {
180 // - We stay inside the extension host and support
181 // to pass any kind of parameters around.
182 // - We still emit the corresponding activation event
183 // BUT we don't await that event
184 this.#proxy.$fireCommandActivationEvent(id);
185 return this._executeContributedCommand<T>(id, args, false);
186
187 } else {
188 // automagically convert some argument types
189 let hasBuffers = false;
190 const toArgs = cloneAndChange(args, function (value) {
191 if (value instanceof extHostTypes.Position) {
192 return extHostTypeConverter.Position.from(value);
193 } else if (value instanceof extHostTypes.Range) {
194 return extHostTypeConverter.Range.from(value);
195 } else if (value instanceof extHostTypes.Location) {
196 return extHostTypeConverter.location.from(value);
197 } else if (extHostTypes.NotebookRange.isNotebookRange(value)) {
198 return extHostTypeConverter.NotebookRange.from(value);
199 } else if (value instanceof ArrayBuffer) {
200 hasBuffers = true;
201 return VSBuffer.wrap(new Uint8Array(value));
202 } else if (value instanceof Uint8Array) {
203 hasBuffers = true;
204 return VSBuffer.wrap(value);
205 } else if (value instanceof VSBuffer) {
206 hasBuffers = true;
207 return value;
208 }
209 if (!Array.isArray(value)) {
210 return value;
211 }
212 });
213
214 try {
215 const result = await this.#proxy.$executeCommand(id, hasBuffers ? new SerializableObjectWithBuffers(toArgs) : toArgs, retry);
216 return revive<any>(result);
217 } catch (e) {
218 // Rerun the command when it wasn't known, had arguments, and when retry
219 // is enabled. We do this because the command might be registered inside
220 // the extension host now and can therefore accept the arguments as-is.
221 if (e instanceof Error && e.message === '$executeCommand:retry') {
222 return this._doExecuteCommand(id, args, false);
223 } else {
224 throw e;
225 }
226 }
227 }
228 }
230 > private async _executeContributedCommand<T = unknown>(id: string, args: unknown[], annotateError: boolean): Promise<T> {
231 const command = this._commands.get(id);
232 if (!command) {
233 throw new Error('Unknown command');
234 }
235 const { callback, thisArg, metadata } = command;
236 if (metadata?.args) {
237 for (let i = 0; i < metadata.args.length; i++) {
238 try {
239 validateConstraint(args[i], metadata.args[i].constraint);
240 } catch (err) {
241 throw new Error(`Running the contributed command: '${id}' failed. Illegal argument '${metadata.args[i].name}' - ${metadata.args[i].description}`);
242 }
243 }
244 }
245
246 const stopWatch = StopWatch.create();
247 try {
248 return await callback.apply(thisArg, args);
249 } catch (err) {
250 // The indirection-command from the converter can fail when invoking the actual
251 // command and in that case it is better to blame the correct command
252 if (id === this.converter.delegatingCommandId) {
253 const actual = this.converter.getActualCommand(...args);
254 if (actual) {
255 id = actual.command;
256 }
257 }
258 if (!isCancellationError(err)) {
259 this._logService.error(err, id, command.extension?.identifier);
260 }
261
262 if (!annotateError) {
263 throw err;
264 }
265
266 if (command.extension?.identifier) {
267 const reported = this.#extHostTelemetry.onExtensionError(command.extension.identifier, err);
268 this._logService.trace('forwarded error to extension?', reported, command.extension?.identifier);
269 }
270
271 throw new class CommandError extends Error {
272 readonly id = id;
273 readonly source = command!.extension?.displayName ?? command!.extension?.name;
274 constructor() {
275 super(toErrorMessage(err));
276 }
277 };
278 }
279 finally {
280 this._reportTelemetry(command, id, stopWatch.elapsed());
281 }
282 }
284 > private _reportTelemetry(command: CommandHandler, id: string, duration: number) {
285 if (!command.extension) {
286 return;
287 }
288 if (id.startsWith('code.copilot.logStructured')) {
289 // This command is very active. See https://github.com/microsoft/vscode/issues/254153.
290 return;
291 }
292 type ExtensionActionTelemetry = {
293 extensionId: string;
294 id: TelemetryTrustedValue<string>;
295 duration: number;
296 };
297 type ExtensionActionTelemetryMeta = {
298 extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The id of the extension handling the command, informing which extensions provide most-used functionality.' };
299 id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The id of the command, to understand which specific extension features are most popular.' };
300 duration: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The duration of the command execution, to detect performance issues' };
301 owner: 'digitarald';
302 comment: 'Used to gain insight on the most popular commands used from extensions';
303 };
304 this.#telemetry.$publicLog2<ExtensionActionTelemetry, ExtensionActionTelemetryMeta>('Extension:ActionExecuted', {
305 extensionId: command.extension.identifier.value,
306 id: new TelemetryTrustedValue(id),
307 duration: duration,
308 });
309 }
311 > $executeContributedCommand(id: string, ...args: unknown[]): Promise<unknown> {
312 this._logService.trace('ExtHostCommands#$executeContributedCommand', id);
313
314 const cmdHandler = this._commands.get(id);
315 if (!cmdHandler) {
316 return Promise.reject(new Error(`Contributed command '${id}' does not exist.`));
317 } else {
318 args = args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r, cmdHandler.extension), arg));
319 return this._executeContributedCommand(id, args, true);
320 }
321 }
323 > getCommands(filterUnderscoreCommands: boolean = false): Promise<string[]> {
324 this._logService.trace('ExtHostCommands#getCommands', filterUnderscoreCommands);
325
326 return this.#proxy.$getCommands().then(result => {
327 if (filterUnderscoreCommands) {
328 result = result.filter(command => command[0] !== '_');
329 }
330 return result;
331 });
332 }
334 > $getContributedCommandMetadata(): Promise<{ [id: string]: string | ICommandMetadataDto }> {
335 const result: { [id: string]: string | ICommandMetadata } = Object.create(null);
336 for (const [id, command] of this._commands) {
337 const { metadata } = command;
338 if (metadata) {
339 result[id] = metadata;
340 }
341 }
342 return Promise.resolve(result);
343 }
345 >
346 > export interface IExtHostCommands extends ExtHostCommands { }
347 > export const IExtHostCommands = createDecorator<IExtHostCommands>('IExtHostCommands');
348 >
349 > export class CommandsConverter implements extHostTypeConverter.Command.ICommandsConverter {
350 >
351 > readonly delegatingCommandId: string = `__vsc${generateUuid()}`;
352 > private readonly _cache = new Map<string, vscode.Command>();
353 > private _cachIdPool = 0;
354 >
355 > // --- conversion between internal and api commands
356 > constructor(
357 private readonly _commands: ExtHostCommands,
358 private readonly _lookupApiCommand: (id: string) => ApiCommand | undefined,
359 private readonly _logService: ILogService
360 ) {
361 this._commands.registerCommand(true, this.delegatingCommandId, this._executeConvertedCommand, this);
362 }
364 > toInternal(command: vscode.Command, disposables: DisposableStore): ICommandDto;
365 > toInternal(command: vscode.Command | undefined, disposables: DisposableStore): ICommandDto | undefined;
366 > toInternal(command: vscode.Command | undefined, disposables: DisposableStore): ICommandDto | undefined {
367
368 if (!command) {
369 return undefined;
370 }
371
372 const result: ICommandDto = {
373 $ident: undefined,
374 id: command.command,
375 title: command.title,
376 tooltip: command.tooltip
377 };
378
379 if (!command.command) {
380 // falsy command id -> return converted command but don't attempt any
381 // argument or API-command dance since this command won't run anyways
382 return result;
383 }
384
385 const apiCommand = this._lookupApiCommand(command.command);
386 if (apiCommand) {
387 // API command with return-value can be converted inplace
388 result.id = apiCommand.internalId;
389 result.arguments = apiCommand.args.map((arg, i) => arg.convert(command.arguments && command.arguments[i]));
390
391
392 } else if (isNonEmptyArray(command.arguments)) {
393 // we have a contributed command with arguments. that
394 // means we don't want to send the arguments around
395
396 const id = `${command.command} /${++this._cachIdPool}`;
397 this._cache.set(id, command);
398 disposables.add(toDisposable(() => {
399 this._cache.delete(id);
400 this._logService.trace('CommandsConverter#DISPOSE', id);
401 }));
402 result.$ident = id;
403
404 result.id = this.delegatingCommandId;
405 result.arguments = [id];
406
407 this._logService.trace('CommandsConverter#CREATE', command.command, id);
408 }
409
410 return result;
411 }
413 > fromInternal(command: ICommandDto): vscode.Command | undefined {
414
415 if (typeof command.$ident === 'string') {
416 return this._cache.get(command.$ident);
417
418 } else {
419 return {
420 command: command.id,
421 title: command.title,
422 arguments: command.arguments
423 };
424 }
425 }
427 >
428 > getActualCommand(...args: unknown[]): vscode.Command | undefined {
429 return this._cache.get(args[0] as string);
430 }
432 > private _executeConvertedCommand<R>(...args: unknown[]): Promise<R> {
433 const actualCmd = this.getActualCommand(...args);
434 this._logService.trace('CommandsConverter#EXECUTE', args[0], actualCmd ? actualCmd.command : 'MISSING');
435
436 if (!actualCmd) {
437 return Promise.reject(`Actual command not found, wanted to execute ${args[0]}`);
438 }
439 return this._commands.executeCommand(actualCmd.command, ...(actualCmd.arguments || []));
440 }
442 > }
443 >
444 >
445 > export class ApiCommandArgument<V, O = V> {
446 >
447 > static readonly Uri = new ApiCommandArgument<URI>('uri', 'Uri of a text document', v => URI.isUri(v), v => v);
448 > static readonly Position = new ApiCommandArgument<extHostTypes.Position, IPosition>('position', 'A position in a text document', v => extHostTypes.Position.isPosition(v), extHostTypeConverter.Position.from);
449 > static readonly Range = new ApiCommandArgument<extHostTypes.Range, IRange>('range', 'A range in a text document', v => extHostTypes.Range.isRange(v), extHostTypeConverter.Range.from);
450 > static readonly Selection = new ApiCommandArgument<extHostTypes.Selection, ISelection>('selection', 'A selection in a text document', v => extHostTypes.Selection.isSelection(v), extHostTypeConverter.Selection.from);
451 > static readonly Number = new ApiCommandArgument<number>('number', '', v => typeof v === 'number', v => v);
452 > static readonly String = new ApiCommandArgument<string>('string', '', v => typeof v === 'string', v => v);
453 >
454 > static Arr<T, K = T>(element: ApiCommandArgument<T, K>) {
455 return new ApiCommandArgument(
456 `${element.name}_array`,
457 `Array of ${element.name}, ${element.description}`,
458 (v: unknown) => Array.isArray(v) && v.every(e => element.validate(e)),
459 (v: T[]) => v.map(e => element.convert(e))
460 );
461 }
463 > static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof extHostTypes.CallHierarchyItem, extHostTypeConverter.CallHierarchyItem.from);
464 > static readonly TypeHierarchyItem = new ApiCommandArgument('item', 'A type hierarchy item', v => v instanceof extHostTypes.TypeHierarchyItem, extHostTypeConverter.TypeHierarchyItem.from);
465 > static readonly TestItem = new ApiCommandArgument('testItem', 'A VS Code TestItem', v => v instanceof TestItemImpl, extHostTypeConverter.TestItem.from);
466 > static readonly TestProfile = new ApiCommandArgument('testProfile', 'A VS Code test profile', v => v instanceof extHostTypes.TestRunProfileBase, extHostTypeConverter.TestRunProfile.from);
467 >
468 > constructor(
469 > readonly name: string,
470 > readonly description: string,
471 > readonly validate: (v: V) => boolean,
472 > readonly convert: (v: V) => O
473 > ) { }
474 >
475 > optional(): ApiCommandArgument<V | undefined | null, O | undefined | null> {
476 return new ApiCommandArgument(
477 this.name, `(optional) ${this.description}`,
478 value => value === undefined || value === null || this.validate(value),
479 value => value === undefined ? undefined : value === null ? null : this.convert(value)
480 );
481 }
483 > with(name: string | undefined, description: string | undefined): ApiCommandArgument<V, O> {
484 return new ApiCommandArgument(name ?? this.name, description ?? this.description, this.validate, this.convert);
485 }
487 >
488 > export class ApiCommandResult<V, O = V> {
489 >
490 > static readonly Void = new ApiCommandResult<void, void>('no result', v => v);
491 >
492 > constructor(
493 > readonly description: string,
494 > readonly convert: (v: V, apiArgs: any[], cmdConverter: CommandsConverter) => O
495 > ) { }
496 > }
497 >
498 > export class ApiCommand {
499 >
500 > constructor(
501 readonly id: string,
502 readonly internalId: string,
503 readonly description: string,
504 readonly args: ApiCommandArgument<any, any>[],
505 readonly result: ApiCommandResult<any, any>
506 ) { }