From 329b7e3f6af12fd3d28322c53da471d914b54896 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 01:03:40 +0000 Subject: [PATCH 1/2] Initial plan From ab165eb1f1f0325b6b3a08b9d603184ca52eefa2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 01:20:47 +0000 Subject: [PATCH 2/2] Fix terminal commands being incorrectly linkified in chat responses Two changes to prevent false-positive linkification: 1. FilePathLinkifier: Require inline code paths to contain at least one dot or path separator (/ or \) to be considered a file path. This prevents command names like `code-insiders` or `test-byok-ext` from being matched. 2. ModelFilePathLinkifier: Reject "descriptive" link text that contains command-like patterns (=, \, /, --flag) when deciding whether to linkify markdown links with anchors. This prevents commands like `code-insiders --extensionDevelopmentPath=d:\src\test-byok-ext` from being incorrectly linked to workspace files. Agent-Logs-Url: https://github.com/microsoft/vscode-copilot-chat/sessions/85ca9a0f-13b7-4d88-a9f7-bdbeaf84cc1c Co-authored-by: vijayupadya <41652029+vijayupadya@users.noreply.github.com> --- .../linkify/common/filePathLinkifier.ts | 3 +- .../linkify/common/modelFilePathLinkifier.ts | 4 +- .../test/node/filePathLinkifier.spec.ts | 39 +++++++++++++++++++ .../test/node/modelFilePathLinkifier.spec.ts | 18 +++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/extension/linkify/common/filePathLinkifier.ts b/src/extension/linkify/common/filePathLinkifier.ts index 6db383cad9..e913cc41eb 100644 --- a/src/extension/linkify/common/filePathLinkifier.ts +++ b/src/extension/linkify/common/filePathLinkifier.ts @@ -21,7 +21,8 @@ import { IStatCache } from './statCache'; const pathMatchRe = new RegExp( [ // Inline code paths (exclude code-like characters $, {, }, that are common in code but rare in filenames) - /(?[^`\s${}]+)`(?!\])/.source, + // Require at least one dot or path separator to avoid matching command names / other non-path text + /(?(?=[^`\s${}]*[./\\])[^`\s${}]+)`(?!\])/.source, // File paths rendered as plain text (exclude code-like characters) /(?[^\s`*${}()]+\.[^\s`*${}()]+)(?![\]`])/.source diff --git a/src/extension/linkify/common/modelFilePathLinkifier.ts b/src/extension/linkify/common/modelFilePathLinkifier.ts index 2c59c289f1..4b0c564d42 100644 --- a/src/extension/linkify/common/modelFilePathLinkifier.ts +++ b/src/extension/linkify/common/modelFilePathLinkifier.ts @@ -139,7 +139,9 @@ export class ModelFilePathLinkifier implements IContributedLinkifier { descriptiveWithAnchor = textBasename === targetBasename; } else { // Text is truly descriptive (e.g., "widget initialization") - allow it - descriptiveWithAnchor = true; + // But reject text that looks like a command or path rather than a description + const textLooksLikeCommand = /[=\\/]|--\w/.test(text); + descriptiveWithAnchor = !textLooksLikeCommand; } } diff --git a/src/extension/linkify/test/node/filePathLinkifier.spec.ts b/src/extension/linkify/test/node/filePathLinkifier.spec.ts index 51d834486d..1e3ee41f45 100644 --- a/src/extension/linkify/test/node/filePathLinkifier.spec.ts +++ b/src/extension/linkify/test/node/filePathLinkifier.spec.ts @@ -304,4 +304,43 @@ suite('File Path Linkifier', () => { 'config.${TerminalSettingId' // Should remain as plain text ]); }); + + test(`Should NOT linkify inline code that has no dot or path separator`, async () => { + // Command names, directory names, and other non-path text in backticks + // should not be linkified even if a workspace file/dir matches + const linkifier = createTestLinkifierService( + 'code-insiders', + 'test-byok-ext', + ); + + assertPartsEqual( + (await linkify(linkifier, + '`code-insiders` `test-byok-ext` `npm`', + )).parts, + [ + '`code-insiders` `test-byok-ext` `npm`' + ] + ); + }); + + test(`Should still linkify inline code with dots or path separators`, async () => { + const linkifier = createTestLinkifierService( + 'file.ts', + 'src/file.ts', + '.env', + ); + + assertPartsEqual( + (await linkify(linkifier, + '`file.ts` `src/file.ts` `.env`', + )).parts, + [ + new LinkifyLocationAnchor(workspaceFile('file.ts')), + ` `, + new LinkifyLocationAnchor(workspaceFile('src/file.ts')), + ` `, + new LinkifyLocationAnchor(workspaceFile('.env')), + ] + ); + }); }); diff --git a/src/extension/linkify/test/node/modelFilePathLinkifier.spec.ts b/src/extension/linkify/test/node/modelFilePathLinkifier.spec.ts index 3c40e87c53..d770f92b24 100644 --- a/src/extension/linkify/test/node/modelFilePathLinkifier.spec.ts +++ b/src/extension/linkify/test/node/modelFilePathLinkifier.spec.ts @@ -174,6 +174,24 @@ suite('Model File Path Linkifier', () => { expect(anchor.title).toBe('src/file.ts#L1287-L1290'); assertPartsEqual([anchor], [expected]); }); + + test('Should NOT linkify command-like text with anchor containing equals sign', async () => { + const service = createTestLinkifierService('src/common/spawnAsync.ts'); + const result = await linkify(service, '[code-insiders --extensionDevelopmentPath=d:\\src\\test-byok-ext](src/common/spawnAsync.ts#L10)'); + assertPartsEqual(result.parts, ['code-insiders --extensionDevelopmentPath=d:\\src\\test-byok-ext']); + }); + + test('Should NOT linkify command-like text with anchor containing flags', async () => { + const service = createTestLinkifierService('src/file.ts'); + const result = await linkify(service, '[npm install --save-dev typescript](src/file.ts#L5)'); + assertPartsEqual(result.parts, ['npm install --save-dev typescript']); + }); + + test('Should NOT linkify command-like text with anchor containing backslash', async () => { + const service = createTestLinkifierService('src/file.ts'); + const result = await linkify(service, '[d:\\src\\test-byok-ext](src/file.ts#L5)'); + assertPartsEqual(result.parts, ['d:\\src\\test-byok-ext']); + }); }); suite('Model File Path Linkifier Remote Workspace', () => {