From 95db8f4c9b14229acf5a4864521f5d39d258dcdf Mon Sep 17 00:00:00 2001 From: felixlaga Date: Sat, 7 Nov 2026 17:16:34 +0900 Subject: [PATCH 1/2] fix(shared): inline code paths like `docker/Dockerfile` become file chips Inline code naming a relative path that ends in a well-known extensionless file, such as `docker/Dockerfile` or `src/Makefile`, stayed plain code. The same file did become a chip as an absolute path, with `./`, with a line number, or as a Markdown link. The extension check for inline code now also accepts the extensionless file names the Markdown link checks already recognize. Co-Authored-By: Claude Opus 5.5 --- packages/shared/src/markdownLinks.test.ts | 1 + packages/shared/src/markdownLinks.ts | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/markdownLinks.test.ts b/packages/shared/src/markdownLinks.test.ts index 68aa6950135fd..90c9431e4c26d 100644 --- a/packages/shared/src/markdownLinks.test.ts +++ b/packages/shared/src/markdownLinks.test.ts @@ -27,6 +27,7 @@ describe("inlineCodeFilePathCandidate", () => { ["origin/main", null], ["z-ai/glm-5.3", null], ["share/man/ls.1", "share/man/ls.1"], + ["docker/Dockerfile", "docker/Dockerfile"], ["src/main.ts/", null], ["./patches/", "./patches/"], // regression: #30757 an agent's shortened path is not a file diff --git a/packages/shared/src/markdownLinks.ts b/packages/shared/src/markdownLinks.ts index f8b0e8434e9b4..e0c311d2b37a1 100644 --- a/packages/shared/src/markdownLinks.ts +++ b/packages/shared/src/markdownLinks.ts @@ -199,7 +199,12 @@ export function inlineCodeFilePathCandidate(codeText: string): string | null { .split(/[\\/]/) .at(-1) ?? ""; if (VERSION_SUFFIX_PATTERN.test(basename)) return null; - if (!hasPosition && !FILE_EXTENSION_PATTERN.test(basename)) return null; + if ( + !hasPosition && + !FILE_EXTENSION_PATTERN.test(basename) && + !EXTENSIONLESS_FILE_NAMES.has(basename) + ) + return null; } return candidate; } From 720881e10e0cfb25fc7e295b51694efc3ba23fd2 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sun, 15 Nov 2026 05:10:48 +0000 Subject: [PATCH 2/2] fix(mobile): link inline code paths like `docker/Dockerfile` The native Markdown transform gates inline-code file links with its own regex, which required an extension on unprefixed relative paths, so the shared helper's fix never reached iOS or Android. Build the regex's relative-path branch from the shared extensionless filename allowlist. Co-Authored-By: Claude Opus 5.5 --- apps/mobile/src/lib/enrichedLinkPresentation.test.ts | 2 ++ apps/mobile/src/lib/enrichedLinkPresentation.ts | 11 +++++++++-- apps/mobile/src/lib/markdownInlineFileLinks.test.ts | 8 +++++++- packages/shared/src/markdownLinks.ts | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/mobile/src/lib/enrichedLinkPresentation.test.ts b/apps/mobile/src/lib/enrichedLinkPresentation.test.ts index 4dd5ecbd08317..771674cc4eff6 100644 --- a/apps/mobile/src/lib/enrichedLinkPresentation.test.ts +++ b/apps/mobile/src/lib/enrichedLinkPresentation.test.ts @@ -34,6 +34,8 @@ describe("Enriched link presentation", () => { "https://example.com/app.tsx", "x + y", "README.md", + "Dockerfile", + "docker/Dockerfiles", "/app/settings", ]) { expect(ENRICHED_INLINE_FILE_LINK_REGEX.test(text), text).toBe(false); diff --git a/apps/mobile/src/lib/enrichedLinkPresentation.ts b/apps/mobile/src/lib/enrichedLinkPresentation.ts index 5d2e9431339d1..f31d8659b6614 100644 --- a/apps/mobile/src/lib/enrichedLinkPresentation.ts +++ b/apps/mobile/src/lib/enrichedLinkPresentation.ts @@ -17,6 +17,7 @@ import { parseComposerContextHref, } from "@t3tools/shared/composerContextReferences"; import { hasThreadLinks, parseThreadLinkHref } from "@t3tools/shared/threadLinks"; +import { EXTENSIONLESS_FILE_NAMES } from "@t3tools/shared/markdownLinks"; export function enrichedContextLinkPresentation( href: string, @@ -91,8 +92,14 @@ export function enrichedLinkVariantPattern(url: string) { return `^${url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`; } -export const ENRICHED_INLINE_FILE_LINK_REGEX = - /^(?!\S*:\/\/)(?:(?:\.{1,2}[\\/]|~[\\/]|\/(?:Users|home|tmp|var|etc|opt|mnt|Volumes|private|root|usr|bin|sbin|lib|lib64|srv|dev|proc|sys|run|boot|media|workspace|workspaces)\/|[A-Za-z]:[\\/])[^\s`]+|(?:[\p{L}\p{M}\p{N}._-]+[\\/])+[\p{L}\p{M}\p{N}._-]+\.[A-Za-z0-9_-]+(?::\d+(?::\d+|-\d+)?)?|[\p{L}\p{M}\p{N}._-]+\.[A-Za-z0-9_-]+:\d+(?::\d+|-\d+)?)$/u; +const EXTENSIONLESS_FILE_NAME_PATTERN = [...EXTENSIONLESS_FILE_NAMES] + .map((name) => name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) + .join("|"); + +export const ENRICHED_INLINE_FILE_LINK_REGEX = new RegExp( + String.raw`^(?!\S*:\/\/)(?:(?:\.{1,2}[\\/]|~[\\/]|\/(?:Users|home|tmp|var|etc|opt|mnt|Volumes|private|root|usr|bin|sbin|lib|lib64|srv|dev|proc|sys|run|boot|media|workspace|workspaces)\/|[A-Za-z]:[\\/])[^\s\x60]+|(?:[\p{L}\p{M}\p{N}._-]+[\\/])+(?:[\p{L}\p{M}\p{N}._-]+\.[A-Za-z0-9_-]+|(?:${EXTENSIONLESS_FILE_NAME_PATTERN}))(?::\d+(?::\d+|-\d+)?)?|[\p{L}\p{M}\p{N}._-]+\.[A-Za-z0-9_-]+:\d+(?::\d+|-\d+)?)$`, + "u", +); export function enrichedSkillLinkRegex(skills?: ReadonlyArray) { const names = [...new Set(skills?.map((skill) => skill.name) ?? [])].filter(Boolean); diff --git a/apps/mobile/src/lib/markdownInlineFileLinks.test.ts b/apps/mobile/src/lib/markdownInlineFileLinks.test.ts index e2d81cf869561..3de6590dc7a4b 100644 --- a/apps/mobile/src/lib/markdownInlineFileLinks.test.ts +++ b/apps/mobile/src/lib/markdownInlineFileLinks.test.ts @@ -93,7 +93,13 @@ describe("inline code that names a file", () => { expect(rewrite("See `src/math.ts:2` and `./README.md`.")).toBe( "See [src/math.ts:2]() and [./README.md](<./README.md>).", ); - for (const path of ["src/數學.ts:2", "數學/math.ts:2", "數學.ts:2", "src/數學.ts:2-4"]) { + for (const path of [ + "src/數學.ts:2", + "數學/math.ts:2", + "數學.ts:2", + "src/數學.ts:2-4", + "docker/Dockerfile", + ]) { expect(rewrite(`See \`${path}\`.`), path).toBe(`See [${path}](<${path}>).`); } }); diff --git a/packages/shared/src/markdownLinks.ts b/packages/shared/src/markdownLinks.ts index 5e2bc9ee86659..0ae35231179e1 100644 --- a/packages/shared/src/markdownLinks.ts +++ b/packages/shared/src/markdownLinks.ts @@ -68,7 +68,7 @@ const POSIX_FILE_ROOT_PREFIXES = [ "/workspaces/", ] as const; -const EXTENSIONLESS_FILE_NAMES = new Set([ +export const EXTENSIONLESS_FILE_NAMES: ReadonlySet = new Set([ "Makefile", "makefile", "GNUmakefile",