Skip to content

Commit 218778a

Browse files
Merge branch 'main' into v5
2 parents 68d8a7c + 42c0a1d commit 218778a

14 files changed

Lines changed: 488 additions & 384 deletions

File tree

.github/workflows/vulnerability-triage.yml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,8 @@ jobs:
546546
STRUCTURED_OUTPUT: ${{ steps.claude.outputs.structured_output }}
547547
REPOSITORY: ${{ github.repository }}
548548
run: |
549-
# Look up the "CVE" label ID and "Triage" state ID for the team
550-
METADATA_QUERY='query($teamId: String!) { team(id: $teamId) { id labels(filter: { name: { eq: "CVE" } }) { nodes { id } } states(filter: { name: { eq: "Triage" } }) { nodes { id } } } }'
549+
# Look up the "CVE" label ID, "Triage" state ID, and the API key owner's user ID
550+
METADATA_QUERY='query($teamId: String!) { team(id: $teamId) { id labels(filter: { name: { eq: "CVE" } }) { nodes { id } } states(filter: { name: { eq: "Triage" } }) { nodes { id } } } viewer { id } }'
551551
METADATA_PAYLOAD=$(jq -n --arg query "$METADATA_QUERY" --arg teamId "$LINEAR_TEAM_ID" \
552552
'{query: $query, variables: {teamId: $teamId}}')
553553
METADATA_RESPONSE=$(curl -s -X POST https://api.linear.app/graphql \
@@ -559,6 +559,7 @@ jobs:
559559
TEAM_UUID=$(echo "$METADATA_RESPONSE" | jq -r '.data.team.id // empty')
560560
LABEL_ID=$(echo "$METADATA_RESPONSE" | jq -r '.data.team.labels.nodes[0].id // empty')
561561
STATE_ID=$(echo "$METADATA_RESPONSE" | jq -r '.data.team.states.nodes[0].id // empty')
562+
VIEWER_ID=$(echo "$METADATA_RESPONSE" | jq -r '.data.viewer.id // empty')
562563
563564
if [ -z "$TEAM_UUID" ]; then
564565
echo "::error::Could not resolve team UUID from LINEAR_TEAM_ID. Check the secret value."
@@ -571,6 +572,9 @@ jobs:
571572
if [ -z "$STATE_ID" ]; then
572573
echo "::warning::Could not find 'Triage' state in Linear team. Using default state."
573574
fi
575+
if [ -z "$VIEWER_ID" ]; then
576+
echo "::warning::Could not resolve Linear API key owner. Issues will be created unassigned."
577+
fi
574578
575579
# Map severity to Linear priority
576580
severity_to_priority() {
@@ -594,7 +598,7 @@ jobs:
594598
# Write CVEs to temp file so the while loop doesn't run in a pipe subshell
595599
echo "$STRUCTURED_OUTPUT" | jq -c '.cves[]' > /tmp/cves.jsonl
596600
597-
MUTATION='mutation CreateIssue($teamId: String!, $title: String!, $description: String, $priority: Int, $labelIds: [String!], $stateId: String) { issueCreate(input: { teamId: $teamId, title: $title, description: $description, priority: $priority, labelIds: $labelIds, stateId: $stateId }) { success issue { id identifier url } } }'
601+
MUTATION='mutation CreateIssue($teamId: String!, $title: String!, $description: String, $priority: Int, $labelIds: [String!], $stateId: String, $assigneeId: String) { issueCreate(input: { teamId: $teamId, title: $title, description: $description, priority: $priority, labelIds: $labelIds, stateId: $stateId, assigneeId: $assigneeId }) { success issue { id identifier url } } }'
598602
599603
while IFS= read -r cve; do
600604
CVE_ID=$(echo "$cve" | jq -r '.cveId')
@@ -624,11 +628,14 @@ jobs:
624628
continue
625629
fi
626630
627-
REOPEN_MUTATION='mutation($issueId: String!, $stateId: String!) { issueUpdate(id: $issueId, input: { stateId: $stateId }) { success issue { id identifier url } } }'
631+
REOPEN_MUTATION='mutation($issueId: String!, $stateId: String!, $assigneeId: String) { issueUpdate(id: $issueId, input: { stateId: $stateId, assigneeId: $assigneeId }) { success issue { id identifier url } } }'
628632
REOPEN_VARIABLES=$(jq -n \
629633
--arg issueId "$LINEAR_ISSUE_ID" \
630634
--arg stateId "$STATE_ID" \
631635
'{issueId: $issueId, stateId: $stateId}')
636+
if [ -n "$VIEWER_ID" ]; then
637+
REOPEN_VARIABLES=$(echo "$REOPEN_VARIABLES" | jq --arg aid "$VIEWER_ID" '. + {assigneeId: $aid}')
638+
fi
632639
REOPEN_PAYLOAD=$(jq -n --arg query "$REOPEN_MUTATION" --argjson vars "$REOPEN_VARIABLES" '{query: $query, variables: $vars}')
633640
634641
REOPEN_RESPONSE=$(curl -s -X POST https://api.linear.app/graphql \
@@ -669,6 +676,9 @@ jobs:
669676
if [ -n "$STATE_ID" ]; then
670677
VARIABLES=$(echo "$VARIABLES" | jq --arg sid "$STATE_ID" '. + {stateId: $sid}')
671678
fi
679+
if [ -n "$VIEWER_ID" ]; then
680+
VARIABLES=$(echo "$VARIABLES" | jq --arg aid "$VIEWER_ID" '. + {assigneeId: $aid}')
681+
fi
672682
673683
PAYLOAD=$(jq -n --arg query "$MUTATION" --argjson vars "$VARIABLES" '{query: $query, variables: $vars}')
674684

CHANGELOG.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- Redesigned the app layout with a new collapsible sidebar navigation, replacing the previous top navigation bar. [#1097](https://github.com/sourcebot-dev/sourcebot/pull/1097)
12+
- Expired offline license keys no longer crash the process. An expired key now degrades to the unlicensed state. [#1109](https://github.com/sourcebot-dev/sourcebot/pull/1109)
13+
14+
## [4.17.2] - 2026-05-16
15+
1016
### Added
1117
- Added warning message that fires on startup when host environment contains env vars that simple-git flags as unsafe. [#1193](https://github.com/sourcebot-dev/sourcebot/pull/1193)
1218
- Added a loading skeleton to the latest commit info bar in the code browser. [#1195](https://github.com/sourcebot-dev/sourcebot/pull/1195)
@@ -20,13 +26,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2026
- Upgraded `hono` to `^4.12.18` to address CVE-2026-44455, CVE-2026-44456, CVE-2026-44457, CVE-2026-44458. [#1186](https://github.com/sourcebot-dev/sourcebot/pull/1186)
2127
- Upgraded `ip-address` to `^10.2.0` to address CVE-2026-42338. [#1189](https://github.com/sourcebot-dev/sourcebot/pull/1189)
2228
- Upgraded `fast-xml-builder` to `^1.2.0` to address CVE-2026-44664, CVE-2026-44665. [#1184](https://github.com/sourcebot-dev/sourcebot/pull/1184)
29+
- Fixed file citations from the `get_diff` tool not being reliably citable in chat answers. [#1205](https://github.com/sourcebot-dev/sourcebot/pull/1205)
30+
- Upgraded `next` to `^16.2.6` to address CVE-2026-45109. [#1203](https://github.com/sourcebot-dev/sourcebot/pull/1203)
2331

2432
### Changed
2533
- Reduced the log verbosity of the worker by changing various log messages from info to debug. [#1179](https://github.com/sourcebot-dev/sourcebot/pull/1179)
2634
- [EE] Switched symbol hover detection to use Lezer highlight tags, broadening identifier coverage. [#1194](https://github.com/sourcebot-dev/sourcebot/pull/1194)
2735
- Improved git history and blame performance on large repositories. [#1198](https://github.com/sourcebot-dev/sourcebot/pull/1198)
28-
- Redesigned the app layout with a new collapsible sidebar navigation, replacing the previous top navigation bar. [#1097](https://github.com/sourcebot-dev/sourcebot/pull/1097)
29-
- Expired offline license keys no longer crash the process. An expired key now degrades to the unlicensed state. [#1109](https://github.com/sourcebot-dev/sourcebot/pull/1109)
36+
- Upgraded `react-email` to `^6.1.4`. [#1206](https://github.com/sourcebot-dev/sourcebot/pull/1206)
37+
- Upgraded `@posthog/ai` to `^7.18.7`. [#1207](https://github.com/sourcebot-dev/sourcebot/pull/1207)
3038

3139
## [4.17.1] - 2026-05-04
3240

CLAUDE.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,7 @@ When fixing a CVE in a transitive dependency, prefer a real top-level upgrade ov
278278
2. **Check whether the existing ranges already allow a patched version.** Often the lockfile is just stale: every `^x.y.z` range in the chain still admits the patched version, but `yarn.lock` was written before that version existed. In that case, refresh the lockfile entry — no `package.json` change, no `resolutions` override:
279279

280280
```bash
281-
yarn up <intermediate-or-vulnerable-pkg>
282-
# or, to refresh many at once:
283-
yarn dedupe
281+
yarn up -R <vulnerable-pkg>
284282
```
285283

286284
This is the lightest-weight fix: it doesn't force a version, it just bumps the lock to the latest version that satisfies the constraints already in the tree. Verify with `yarn why <vulnerable-package>` afterward — if every instance is now patched, you're done.

docs/api-reference/sourcebot-public.openapi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"openapi": "3.0.3",
33
"info": {
44
"title": "Sourcebot Public API",
5-
"version": "v4.17.1",
5+
"version": "v4.17.2",
66
"description": "OpenAPI description for the public Sourcebot REST endpoints used for search, repository listing, and file browsing. Authentication is instance-dependent: API keys are the standard integration mechanism, OAuth bearer tokens are EE-only, and some instances may allow anonymous access."
77
},
88
"tags": [

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
},
3131
"packageManager": "yarn@4.7.0",
3232
"resolutions": {
33+
"@protobufjs/inquire": "1.1.0",
3334
"prettier": "3.5.3",
3435
"@lezer/common": "1.3.0",
3536
"qs": "^6.14.2",
@@ -42,17 +43,15 @@
4243
"path-to-regexp@0.1.12": "0.1.13",
4344
"path-to-regexp@^8": "^8.4.0",
4445
"picomatch@^4": "^4.0.4",
45-
"esbuild": "^0.27.3",
46+
"esbuild": "^0.28.0",
4647
"js-yaml@npm:^4.1.0": "^4.1.1",
4748
"ajv@npm:^8.0.0": "^8.18.0",
4849
"ajv@npm:^8.17.1": "^8.18.0",
4950
"brace-expansion@npm:^2.0.2": "^2.0.3",
5051
"brace-expansion@npm:^5.0.2": "^5.0.5",
5152
"brace-expansion@npm:^1.1.7": "^1.1.13",
52-
"@react-email/preview-server/next": "^16.2.3",
5353
"@modelcontextprotocol/sdk/hono": "^4.12.18",
5454
"@modelcontextprotocol/sdk/@hono/node-server": "^1.19.13",
55-
"langsmith@npm:>=0.5.0 <1.0.0": "^0.5.19",
5655
"markdown-it@npm:^14.1.0": "^14.1.1",
5756
"yaml@npm:^2.3.4": "^2.8.3",
5857
"yaml@npm:^2.8.0": "^2.8.3",

packages/shared/src/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
// This file is auto-generated by .github/workflows/release-sourcebot.yml
2-
export const SOURCEBOT_VERSION = "v4.17.1";
2+
export const SOURCEBOT_VERSION = "v4.17.2";

packages/web/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"@opentelemetry/api-logs": "^0.203.0",
6868
"@opentelemetry/instrumentation": "^0.203.0",
6969
"@opentelemetry/sdk-logs": "^0.203.0",
70-
"@posthog/ai": "^7.15.0",
70+
"@posthog/ai": "^7.18.7",
7171
"@radix-ui/react-accordion": "^1.2.11",
7272
"@radix-ui/react-alert-dialog": "^1.1.5",
7373
"@radix-ui/react-avatar": "^1.1.2",
@@ -90,8 +90,8 @@
9090
"@radix-ui/react-toggle": "^1.1.10",
9191
"@radix-ui/react-toggle-group": "^1.1.11",
9292
"@radix-ui/react-tooltip": "^1.2.8",
93-
"@react-email/components": "^1.0.2",
94-
"@react-email/render": "^2.0.0",
93+
"@react-email/components": "^1.0.12",
94+
"@react-email/render": "^2.0.8",
9595
"@replit/codemirror-lang-csharp": "^6.2.0",
9696
"@replit/codemirror-lang-nix": "^6.0.1",
9797
"@replit/codemirror-lang-solidity": "^6.0.2",
@@ -157,7 +157,7 @@
157157
"lucide-react": "^1.7.0",
158158
"micromatch": "^4.0.8",
159159
"minidenticons": "^4.2.1",
160-
"next": "^16.2.3",
160+
"next": "^16.2.6",
161161
"next-auth": "^5.0.0-beta.30",
162162
"next-navigation-guard": "^0.2.0",
163163
"next-themes": "^0.3.0",
@@ -202,7 +202,7 @@
202202
"devDependencies": {
203203
"@asteasolutions/zod-to-openapi": "7.3.4",
204204
"@eslint/eslintrc": "^3",
205-
"@react-email/preview-server": "5.2.10",
205+
"@react-email/ui": "6.1.4",
206206
"@react-grab/mcp": "^0.1.23",
207207
"@tanstack/eslint-plugin-query": "^5.74.7",
208208
"@testing-library/dom": "^10.4.1",
@@ -226,7 +226,7 @@
226226
"npm-run-all": "^4.1.5",
227227
"postcss": "^8.5.10",
228228
"raw-loader": "^4.0.2",
229-
"react-email": "^5.2.10",
229+
"react-email": "^6.1.4",
230230
"react-grab": "^0.1.23",
231231
"react-scan": "^0.5.3",
232232
"tailwindcss": "^3.4.1",

packages/web/src/features/chat/components/chatThread/answerCard.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ import useCaptureEvent from "@/hooks/useCaptureEvent";
1818
import { LangfuseWeb } from "langfuse";
1919
import { env } from "@sourcebot/shared/client";
2020
import isEqual from "fast-deep-equal/react";
21+
import { FileSource } from "../../types";
2122

2223
interface AnswerCardProps {
2324
answerText: string;
2425
messageId: string;
2526
chatId: string;
2627
traceId?: string;
28+
sources: FileSource[];
2729
}
2830

2931
const langfuseWeb = env.NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY ? new LangfuseWeb({
@@ -36,6 +38,7 @@ const AnswerCardComponent = forwardRef<HTMLDivElement, AnswerCardProps>(({
3638
messageId,
3739
chatId,
3840
traceId,
41+
sources,
3942
}, forwardedRef) => {
4043
const markdownRendererRef = useRef<HTMLDivElement>(null);
4144
// eslint-disable-next-line react-hooks/refs -- ref.current is passed to a custom hook, not used directly in render output
@@ -53,14 +56,14 @@ const AnswerCardComponent = forwardRef<HTMLDivElement, AnswerCardProps>(({
5356

5457
const onCopyAnswer = useCallback(() => {
5558
const baseUrl = typeof window !== 'undefined' ? window.location.origin : '';
56-
const markdownText = convertLLMOutputToPortableMarkdown(answerText, baseUrl);
59+
const markdownText = convertLLMOutputToPortableMarkdown(answerText, baseUrl, sources);
5760
navigator.clipboard.writeText(markdownText);
5861
toast({
5962
description: "✅ Copied to clipboard",
6063
});
6164
captureEvent('wa_chat_copy_answer_pressed', { chatId });
6265
return true;
63-
}, [answerText, chatId, captureEvent, toast]);
66+
}, [answerText, sources, chatId, captureEvent, toast]);
6467

6568
const onFeedback = useCallback(async (feedbackType: 'like' | 'dislike') => {
6669
setIsSubmittingFeedback(true);

packages/web/src/features/chat/components/chatThread/chatThreadListItem.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ const ChatThreadListItemComponent = forwardRef<HTMLDivElement, ChatThreadListIte
371371
chatId={chatId}
372372
messageId={assistantMessage.id}
373373
traceId={assistantMessage.metadata?.traceId}
374+
sources={referencedFileSources}
374375
/>
375376
) : !isStreaming && (
376377
<p className="text-destructive">Error: No answer response was provided</p>

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,23 @@ export const createFileReference = ({ repo, path, startLine, endLine }: { repo:
244244
* Markdown format. Practically, this means converting references into Markdown
245245
* links and removing the answer tag.
246246
*/
247-
export const convertLLMOutputToPortableMarkdown = (text: string, baseUrl: string): string => {
247+
export const convertLLMOutputToPortableMarkdown = (text: string, baseUrl: string, sources: FileSource[]): string => {
248248
return text
249249
.replace(ANSWER_TAG, '')
250250
.replace(FILE_REFERENCE_REGEX, (_, repo, fileName, startLine, endLine) => {
251-
const displayName = fileName.split('/').pop() || fileName;
251+
const reference = createFileReference({
252+
repo,
253+
path: fileName,
254+
startLine,
255+
endLine
256+
});
257+
258+
const source = tryResolveFileReference(reference, sources);
259+
if (!source) {
260+
return fileName;
261+
}
252262

253-
let linkText = displayName;
263+
let linkText = source.name;
254264
if (startLine) {
255265
if (endLine && startLine !== endLine) {
256266
linkText += `:${startLine}-${endLine}`;
@@ -268,6 +278,7 @@ export const convertLLMOutputToPortableMarkdown = (text: string, baseUrl: string
268278
// Construct full browse URL
269279
const browsePath = getBrowsePath({
270280
repoName: repo,
281+
revisionName: source.revision,
271282
path: fileName,
272283
pathType: 'blob',
273284
highlightRange,

0 commit comments

Comments
 (0)