Skip to content
This repository was archived by the owner on Aug 1, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bf241e0
feat(context): Display branch name in mention menu help text
ichim-david Jul 7, 2025
a71078a
feat(context): Enhance remote directory search and item retrieval
ichim-david Jul 8, 2025
064ccf8
feat(context): Improve remote directory item retrieval with context s…
ichim-david Jul 20, 2025
7e375b5
fix(context): Improve remote directory search tests and URL generation
ichim-david Jul 20, 2025
76143f9
feat(context): Enhance remote directory search with branch support an…
ichim-david Jul 20, 2025
e164488
feat(context): Enhance OpenCtx with branch mentions and remote file b…
ichim-david Jul 20, 2025
49af345
Fixed tests by using the exported functions and general cleanup
ichim-david Jul 21, 2025
0052d3f
pnpm biome fix
ichim-david Jul 21, 2025
3473b19
fixed remote file filtering once we choose the branch
ichim-david Jul 22, 2025
0314735
feat(context): Improve remote directory search using getDirectoryCont…
ichim-david Jul 27, 2025
4ffcf86
Removed experimental flag from remote directoy mention menu
ichim-david Jul 28, 2025
0f98b3a
WIP implementing repo -> branch -> directory selection for remote dir…
ichim-david Jul 28, 2025
e198229
repository branch searching beyond the first 10 results
ichim-david Jul 29, 2025
56730e2
fix regex for starting directories mentions on searches branches
ichim-david Jul 30, 2025
ca80b62
skip . folders from initial folder listing
ichim-david Jul 30, 2025
f32012f
simplify branch mentions after proper branch searching
ichim-david Jul 30, 2025
8fe7cec
simplify check for remote directories branch or directory listing
ichim-david Jul 30, 2025
1841de6
allow remote file to search for branches
ichim-david Jul 30, 2025
2b43819
test fixes
ichim-david Jul 30, 2025
9be17a4
fix mention menu tooltip height when branch name is long
ichim-david Jul 30, 2025
57bffd7
removed `getFileBranchMentions` fallback to file search
ichim-david Jul 31, 2025
29ce80a
simplify code by getting rid of need for extractBranchAndRepo
ichim-david Jul 31, 2025
c927aaa
simplify and bring mentions in sync between remoteFile and remoteDire…
ichim-david Jul 31, 2025
4d9016f
remove needless try catch and clarify why we have empty description
ichim-david Jul 31, 2025
75ef576
removed `parsedRemoteQuery` logic that ended up not being used
ichim-david Jul 31, 2025
8d5a4cf
parallel fetch of directory items
ichim-david Jul 31, 2025
996e08e
fix tooltips for dirname
ichim-david Jul 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions lib/prompt-editor/src/mentions/mentionMenu/MentionMenu.branch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { ContextItemSource, REMOTE_DIRECTORY_PROVIDER_URI } from '@sourcegraph/cody-shared'
import type { MentionMenuData } from '@sourcegraph/cody-shared'
import { describe, expect, test } from 'vitest'
import { URI } from 'vscode-uri'

// This would be imported from the MentionMenu component if it were exported
// For now, we'll create a test version of the function
function getBranchHelpText(
items: NonNullable<MentionMenuData['items']>,
mentionQuery: { text: string }
): string {
// Check if we have branch information from the current search
const firstItem = items[0]
if (firstItem?.type === 'openctx') {
const openCtxItem = firstItem as any // Simplified for testing
if (openCtxItem.mention?.data?.branch) {
return `* Sourced from the '${openCtxItem.mention.data.branch}' branch`
}
}

// Check if user has specified a branch in the query
if (mentionQuery.text.includes('@')) {
const branchPart = mentionQuery.text.split('@')[1]
if (branchPart) {
// Remove anything after colon (directory path)
const branchName = branchPart.split(':')[0]
return `* Sourced from the '${branchName}' branch`
}
}

return '* Sourced from the remote default branch'
}

describe('MentionMenu branch selection', () => {
test('should show default branch text when no branch is specified', () => {
const items: MentionMenuData['items'] = [
{
type: 'openctx',
provider: 'openctx',
title: 'src/components',
uri: URI.parse('https://example.com/repo/-/tree/src/components'),
providerUri: REMOTE_DIRECTORY_PROVIDER_URI,
source: ContextItemSource.User,
mention: {
uri: 'https://example.com/repo/-/tree/src/components',
data: {
repoName: 'test-repo',
directoryPath: 'src/components',
},
},
},
]

const mentionQuery = { text: 'test-repo:src' }

const result = getBranchHelpText(items!, mentionQuery)
expect(result).toBe('* Sourced from the remote default branch')
})

test('should show branch name when branch is specified in query', () => {
const items: MentionMenuData['items'] = [
{
type: 'openctx',
provider: 'openctx',
title: 'src/components',
uri: URI.parse('https://example.com/repo/-/tree/src/components'),
providerUri: REMOTE_DIRECTORY_PROVIDER_URI,
source: ContextItemSource.User,
mention: {
uri: 'https://example.com/repo/-/tree/src/components',
data: {
repoName: 'test-repo',
directoryPath: 'src/components',
},
},
},
]

const mentionQuery = { text: 'test-repo@feature-branch:src' }

const result = getBranchHelpText(items!, mentionQuery)
expect(result).toBe("* Sourced from the 'feature-branch' branch")
})

test('should show branch name from mention data when available', () => {
const items: MentionMenuData['items'] = [
{
type: 'openctx',
provider: 'openctx',
title: 'src/components',
uri: URI.parse('https://example.com/repo/-/tree/src/components'),
providerUri: REMOTE_DIRECTORY_PROVIDER_URI,
source: ContextItemSource.User,
mention: {
uri: 'https://example.com/repo/-/tree/src/components',
data: {
repoName: 'test-repo',
directoryPath: 'src/components',
branch: 'main',
},
},
},
]

const mentionQuery = { text: 'test-repo:src' }

const result = getBranchHelpText(items!, mentionQuery)
expect(result).toBe("* Sourced from the 'main' branch")
})

test('should prefer mention data branch over query branch', () => {
const items: MentionMenuData['items'] = [
{
type: 'openctx',
provider: 'openctx',
title: 'src/components',
uri: URI.parse('https://example.com/repo/-/tree/src/components'),
providerUri: REMOTE_DIRECTORY_PROVIDER_URI,
source: ContextItemSource.User,
mention: {
uri: 'https://example.com/repo/-/tree/src/components',
data: {
repoName: 'test-repo',
directoryPath: 'src/components',
branch: 'actual-branch',
},
},
},
]

const mentionQuery = { text: 'test-repo@query-branch:src' }

const result = getBranchHelpText(items!, mentionQuery)
expect(result).toBe("* Sourced from the 'actual-branch' branch")
})

test('should handle empty items array', () => {
const items: MentionMenuData['items'] = []
const mentionQuery = { text: 'test-repo@main:src' }

const result = getBranchHelpText(items!, mentionQuery)
expect(result).toBe("* Sourced from the 'main' branch")
})

test('should handle non-openctx items', () => {
const items: MentionMenuData['items'] = [
{
type: 'file',
provider: 'file',
title: 'test.ts',
uri: URI.parse('file:///test.ts'),
source: ContextItemSource.User,
},
]

const mentionQuery = { text: 'test-repo@feature:src' }

const result = getBranchHelpText(items!, mentionQuery)
expect(result).toBe("* Sourced from the 'feature' branch")
})
})
31 changes: 30 additions & 1 deletion lib/prompt-editor/src/mentions/mentionMenu/MentionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export const MentionMenu: FunctionComponent<
'tw-bg-accent'
)}
>
* Sourced from the remote default branch
{getBranchHelpText(data.items, mentionQuery)}
</CommandLoading>
)}

Expand Down Expand Up @@ -341,6 +341,35 @@ function commandRowValue(
return contextItemID(row)
}

function getBranchHelpText(
items: NonNullable<MentionMenuData['items']>,
mentionQuery: MentionQuery
): string {
// Check if we have branch information from the current search
const firstItem = items[0]
if (firstItem?.type === 'openctx') {
const openCtxItem = firstItem as ContextItem & {
type: 'openctx'
mention?: { data?: { branch?: string } }
}
if (openCtxItem.mention?.data?.branch) {
return `* Sourced from the '${openCtxItem.mention.data.branch}' branch`
}
}

// Check if user has specified a branch in the query
if (mentionQuery.text.includes('@')) {
const branchPart = mentionQuery.text.split('@')[1]
if (branchPart) {
// Remove anything after colon (directory path)
const branchName = branchPart.split(':')[0]
return `* Sourced from the '${branchName}' branch`
}
}

return '* Sourced from the remote default branch'
}

function getEmptyLabel(
parentItem: ContextMentionProviderMetadata | null,
mentionQuery: MentionQuery
Expand Down
33 changes: 33 additions & 0 deletions lib/shared/src/sourcegraph-api/graphql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
CURRENT_USER_INFO_QUERY,
CURRENT_USER_ROLE_QUERY,
DELETE_ACCESS_TOKEN_MUTATION,
DIRECTORY_CONTENTS_QUERY,
EVALUATE_FEATURE_FLAGS_QUERY,
EVALUATE_FEATURE_FLAG_QUERY,
FILE_CONTENTS_QUERY,
Expand Down Expand Up @@ -370,6 +371,23 @@ interface FileContentsResponse {
} | null
}

interface DirectoryContentsResponse {
repository: {
commit: {
tree: {
entries: Array<{
name: string
path: string
byteSize?: number
url: string
content?: string
isDirectory?: boolean
}>
} | null
} | null
} | null
}

export interface RepositoryIdResponse {
repository: { id: string } | null
}
Expand Down Expand Up @@ -1049,6 +1067,21 @@ export class SourcegraphGraphQLAPIClient {
}).then(response => extractDataOrError(response, data => data))
}

public async getDirectoryContents(
repoName: string,
path: string,
revision = 'HEAD'
): Promise<DirectoryContentsResponse | Error> {
return this.fetchSourcegraphAPI<APIResponse<DirectoryContentsResponse>>(
DIRECTORY_CONTENTS_QUERY,
{
repoName,
path,
revision,
}
).then(response => extractDataOrError(response, data => data))
}

public async getRepoId(repoName: string): Promise<string | null | Error> {
return this.fetchSourcegraphAPI<APIResponse<RepositoryIdResponse>>(REPOSITORY_ID_QUERY, {
name: repoName,
Expand Down
24 changes: 24 additions & 0 deletions lib/shared/src/sourcegraph-api/graphql/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,27 @@ export const NLS_SEARCH_QUERY = `
}
}
}`

export const DIRECTORY_CONTENTS_QUERY = `
query GetDirectoryContents($repoName: String!, $revision: String!, $path: String!) {
repository(name: $repoName) {
commit(rev: $revision) {
tree(path: $path) {
entries(first: 50) {
... on GitBlob {
name
path
byteSize
url
content
Copy link
Contributor

@peterguy peterguy Jul 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examining the rest of the PR, it looks like you don't need content. content is pretty expensive, so you should use it only when you need the file contents immediately. If you think you may need the file contents, you can use rawURL instead of content and then use that URL to retrieve the content.

Additionally, examine whether you need the blob at all - it looks like this PR is using the directories, but not the files, so you may be able to ditch the file info (GitBlob) completely.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to the blob comment

}
... on GitTree {
name
path
isDirectory
}
}
}
}
}
}`
Loading
Loading