Skip to content

Commit b931ca7

Browse files
fix(web): support ports in chat file references (#1565)
* fix(web): support ports in chat file references * chore: add changelog entry for #1565 * test(web): assert port file reference captures
1 parent 427b534 commit b931ca7

9 files changed

Lines changed: 32 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3434
- Upgraded `nanoid` to `^3.3.18`. [#1557](https://github.com/sourcebot-dev/sourcebot/pull/1557)
3535
- Upgraded `dompurify` to `^3.4.13`. [#1556](https://github.com/sourcebot-dev/sourcebot/pull/1556)
3636
- Upgraded `mermaid` to `^11.16.1`. [#1555](https://github.com/sourcebot-dev/sourcebot/pull/1555)
37+
- [EE] Fixed Ask Sourcebot file reference citations for repositories whose code host URL includes a port. [#1565](https://github.com/sourcebot-dev/sourcebot/pull/1565)
3738

3839
## [5.1.5] - 2026-07-31
3940

packages/web/src/ee/features/chat/components/chatThread/markdownRenderer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function remarkReferencesPlugin() {
4949
return function (tree: Nodes) {
5050
findAndReplace(tree, [
5151
FILE_REFERENCE_REGEX,
52-
(_, repo: string, fileName: string, startLine?: string, endLine?: string) => {
52+
(_, repo: string, _port: string | undefined, fileName: string, startLine?: string, endLine?: string) => {
5353
// Create display text
5454
let displayText = fileName.split('/').pop() ?? fileName;
5555

@@ -290,4 +290,4 @@ const MarkdownRendererComponent = forwardRef<HTMLDivElement, MarkdownRendererPro
290290

291291
MarkdownRendererComponent.displayName = 'MarkdownRenderer';
292292

293-
export const MarkdownRenderer = memo(MarkdownRendererComponent, isEqual);
293+
export const MarkdownRenderer = memo(MarkdownRendererComponent, isEqual);

packages/web/src/ee/features/chat/skills/commandResolution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export const getFileSourcesFromText = (text: string): FileSource[] => {
143143
FILE_REFERENCE_REGEX.lastIndex = 0;
144144
let match: RegExpExecArray | null;
145145
while ((match = FILE_REFERENCE_REGEX.exec(text)) !== null) {
146-
const [, repo, path] = match;
146+
const [, repo, , path] = match;
147147
if (!repo || !path) {
148148
continue;
149149
}

packages/web/src/ee/features/chat/skills/components/skillInstructionsEditor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const parseInlineInstructions = (text: string): Descendant[] => {
4444
FILE_REFERENCE_REGEX.lastIndex = 0;
4545
let match: RegExpExecArray | null;
4646
while ((match = FILE_REFERENCE_REGEX.exec(text)) !== null) {
47-
const [rawReference, repo, path] = match;
47+
const [rawReference, repo, , path] = match;
4848
if (!repo || !path) {
4949
continue;
5050
}

packages/web/src/ee/features/chat/useExtractPanelItems.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export const useExtractPanelItems = (
7070
const combined = new RegExp(`${MERMAID_BLOCK_REGEX.source}|${FILE_REFERENCE_REGEX.source}`, 'g');
7171
let match: RegExpExecArray | null;
7272
while ((match = combined.exec(text)) !== null) {
73-
// match[1]: mermaid body. match[2..5]: file reference repo/path/start/end.
73+
// match[1]: mermaid body. match[2..6]: file reference repo/port/path/start/end.
7474
if (match[1] !== undefined) {
7575
const code = match[1].trim();
7676
if (!code) {
@@ -85,8 +85,8 @@ export const useExtractPanelItems = (
8585
const diagramIndex = diagrams.length;
8686
diagrams.push(diagram);
8787
orderedItems.push({ kind: 'diagram', diagram, diagramIndex });
88-
} else if (match[2] !== undefined && match[3] !== undefined) {
89-
const reference = createFileReference({ repo: match[2], path: match[3], startLine: match[4], endLine: match[5] });
88+
} else if (match[2] !== undefined && match[4] !== undefined) {
89+
const reference = createFileReference({ repo: match[2], path: match[4], startLine: match[5], endLine: match[6] });
9090
const source = tryResolveFileReference(reference, referencedFileSources);
9191
if (!source) {
9292
continue;

packages/web/src/ee/features/chat/useExtractReferences.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const useExtractReferences = (part?: TextUIPart) => {
1919

2020
let match;
2121
while ((match = FILE_REFERENCE_REGEX.exec(content ?? '')) !== null && match !== null) {
22-
const [_, repo, fileName, startLine, endLine] = match;
22+
const [, repo, , fileName, startLine, endLine] = match;
2323

2424
const fileReference = createFileReference({
2525
repo: repo,

packages/web/src/features/chat/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export const FILE_REFERENCE_PREFIX = '@file:';
22
export const FILE_REFERENCE_REGEX = new RegExp(
33
// @file:{repoName::fileName:startLine-endLine}
4-
`${FILE_REFERENCE_PREFIX}\\{([^:}]+)::([^:}]+)(?::(\\d+)(?:-(\\d+))?)?\\}`,
4+
`${FILE_REFERENCE_PREFIX}\\{([^:}]+(:\\d+)?[^:}]*)::([^:}]+)(?::(\\d+)(?:-(\\d+))?)?\\}`,
55
'g'
66
);
77

packages/web/src/features/chat/utils.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,27 @@ test('fileReferenceToString matches FILE_REFERENCE_REGEX', () => {
134134
}))).toBe(true);
135135
});
136136

137+
test('fileReferenceToString matches FILE_REFERENCE_REGEX for repos with ports', () => {
138+
const reference = fileReferenceToString({
139+
repo: 'git.example.com:8080/org/repo',
140+
path: 'auth.ts',
141+
range: {
142+
startLine: 45,
143+
endLine: 60,
144+
},
145+
});
146+
147+
FILE_REFERENCE_REGEX.lastIndex = 0;
148+
const match = FILE_REFERENCE_REGEX.exec(reference);
149+
150+
expect(match).not.toBeNull();
151+
expect(match?.[1]).toBe('git.example.com:8080/org/repo');
152+
expect(match?.[2]).toBe(':8080');
153+
expect(match?.[3]).toBe('auth.ts');
154+
expect(match?.[4]).toBe('45');
155+
expect(match?.[5]).toBe('60');
156+
});
157+
137158
test('slateContentToString serializes command mentions as literal slash commands', () => {
138159
const children = [{
139160
type: 'paragraph',

packages/web/src/features/chat/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ export const createFileReference = ({ repo, path, startLine, endLine }: { repo:
284284
export const convertLLMOutputToPortableMarkdown = (text: string, baseUrl: string, sources: FileSource[]): string => {
285285
return text
286286
.replace(ANSWER_TAG, '')
287-
.replace(FILE_REFERENCE_REGEX, (_, repo, fileName, startLine, endLine) => {
287+
.replace(FILE_REFERENCE_REGEX, (_, repo, _port, fileName, startLine, endLine) => {
288288
const reference = createFileReference({
289289
repo,
290290
path: fileName,

0 commit comments

Comments
 (0)