diff --git a/packages/client-runtime/src/markdownLinks.test.ts b/packages/client-runtime/src/markdownLinks.test.ts index 4aea947b87d6..0a12f14dc6b8 100644 --- a/packages/client-runtime/src/markdownLinks.test.ts +++ b/packages/client-runtime/src/markdownLinks.test.ts @@ -22,6 +22,15 @@ describe("inlineCodeFilePathCandidate", () => { ["127.0.0.1:3000", null], ["example.com/index.html", null], ["example.pl/index.html", null], + ["z-ai/glm-5.3", null], + ["z-ai/glm-5.3:12", null], + ["python/3.12", null], + ["Qwen/Qwen2.5-Coder", null], + ["meta-llama/Llama-3.1-8B", null], + ["share/man/ls.1", "share/man/ls.1"], + ["usr/lib/libfoo.so.1", "usr/lib/libfoo.so.1"], + ["vendor/jquery-3.6.0.min.js", "vendor/jquery-3.6.0.min.js"], + ["./models/glm-5.3", "./models/glm-5.3"], ])("distinguishes file paths from code and hostnames in %s", (source, candidate) => { expect(inlineCodeFilePathCandidate(source)).toBe(candidate); }); diff --git a/packages/client-runtime/src/markdownLinks.ts b/packages/client-runtime/src/markdownLinks.ts index 29a337e49c42..a7fc6881c694 100644 --- a/packages/client-runtime/src/markdownLinks.ts +++ b/packages/client-runtime/src/markdownLinks.ts @@ -14,6 +14,9 @@ const POSITION_ONLY_PATTERN = /^\d+(?::\d+)?$/; const INLINE_CODE_DISQUALIFIER_PATTERN = /[\s`]/; const PATH_SEPARATOR_PATTERN = /[\\/]/; const FILE_EXTENSION_PATTERN = /\.[A-Za-z0-9_-]+$/; +// A final dot between digits marks a version or model id (`glm-5.3`, +// `Qwen2.5-Coder`), not an extension. `ls.1` and `libfoo.so.1` stay files. +const VERSION_SUFFIX_PATTERN = /\d\.\d[^.]*$/; const NUMERIC_DOTTED_PATTERN = /^\d+(?:\.\d+)+$/; // Standard OS and dev-container roots; deliberately excludes app-route-ish // prefixes like /app/ or /chat/ so SPA routes never read as files. @@ -176,6 +179,7 @@ export function inlineCodeFilePathCandidate(codeText: string): string | null { .replace(/[/\\]+$/, "") .split(/[\\/]/) .at(-1) ?? ""; + if (VERSION_SUFFIX_PATTERN.test(basename)) return null; if (!hasPosition && !FILE_EXTENSION_PATTERN.test(basename)) return null; } return candidate;