diff --git a/news/changelog-1.9.md b/news/changelog-1.9.md index 51f9f904b8..c6f919abb1 100644 --- a/news/changelog-1.9.md +++ b/news/changelog-1.9.md @@ -217,6 +217,7 @@ All changes included in 1.9: - ([#13856](https://github.com/quarto-dev/quarto-cli/issues/13856)): Add code annotation support for Typst and Observable.js code blocks. (author: @mcanouil) - ([#13890](https://github.com/quarto-dev/quarto-cli/issues/13890)): Fix render failure when using `embed-resources: true` with input path through a symlinked directory. The cleanup now resolves symlinks before comparing paths. - ([#13907](https://github.com/quarto-dev/quarto-cli/issues/13907)): Ignore AI assistant configuration files (`CLAUDE.md`, `AGENTS.md`) when scanning for project input files and in extension templates, similar to how `README.md` is handled. +- ([#14198](https://github.com/quarto-dev/quarto-cli/issues/14198)): Ignore `.local.md` variants of AI assistant configuration files (`CLAUDE.local.md`, `AGENTS.local.md`) during project render and `quarto use template`. - ([#13935](https://github.com/quarto-dev/quarto-cli/issues/13935)): Fix `quarto install`, `quarto update`, and `quarto uninstall` interactive tool selection. - ([#13992](https://github.com/quarto-dev/quarto-cli/issues/13992)): Fix crash when rendering div with both cross-reference ID and conditional visibility to PDF. - ([#13997](https://github.com/quarto-dev/quarto-cli/issues/13997)): Fix Windows dart-sass theme compilation failing when Quarto is installed in a path with spaces (e.g., `C:\Program Files\`) and the project path also contains spaces. diff --git a/src/extension/template.ts b/src/extension/template.ts index 87e4302900..84c1243139 100644 --- a/src/extension/template.ts +++ b/src/extension/template.ts @@ -58,5 +58,7 @@ const kBuiltInExcludes = [ "LICENSE", "_extensions", "CLAUDE.md", + "CLAUDE.local.md", "AGENTS.md", + "AGENTS.local.md", ]; diff --git a/src/project/project-context.ts b/src/project/project-context.ts index df308c0d4f..f68be8bb46 100644 --- a/src/project/project-context.ts +++ b/src/project/project-context.ts @@ -880,8 +880,8 @@ function projectHiddenIgnoreGlob(dir: string) { .concat(["**/_*", "**/_*/**"]) // underscore prefix .concat(["**/.*", "**/.*/**"]) // hidden (dot prefix) .concat(["**/README.?([Rrq])md"]) // README - .concat(["**/CLAUDE.md"]) // Anthropic claude code file - .concat(["**/AGENTS.md"]) // https://agents.md/ + .concat(["**/CLAUDE.md", "**/CLAUDE.local.md"]) // Anthropic claude code file + .concat(["**/AGENTS.md", "**/AGENTS.local.md"]) // https://agents.md/ .concat(["**/*.llms.md"]); // llms.txt companion markdown files } diff --git a/tests/smoke/project/project-ai-config.test.ts b/tests/smoke/project/project-ai-config.test.ts index b5a2752bc8..fab64c00df 100644 --- a/tests/smoke/project/project-ai-config.test.ts +++ b/tests/smoke/project/project-ai-config.test.ts @@ -10,12 +10,16 @@ import { docs } from "../../utils.ts"; import { join } from "../../../src/deno_ral/path.ts"; import { existsSync } from "../../../src/deno_ral/fs.ts"; +import { removeIfExists } from "../../../src/core/path.ts"; import { testQuartoCmd } from "../../test.ts"; import { fileExists, pathDoNotExists, noErrors } from "../../verify.ts"; const projectDir = docs("project/ai-config-files"); const outputDir = join(projectDir, "_site"); +// .local.md fixture files are created at runtime to avoid .gitignore conflicts +const localFiles = ["CLAUDE.local.md", "AGENTS.local.md"]; + // Test that AI assistant config files are properly excluded testQuartoCmd( "render", @@ -25,10 +29,22 @@ testQuartoCmd( fileExists(join(outputDir, "index.html")), // Control: regular file should be rendered pathDoNotExists(join(outputDir, "CLAUDE.html")), // CLAUDE.md should be ignored pathDoNotExists(join(outputDir, "AGENTS.html")), // AGENTS.md should be ignored + pathDoNotExists(join(outputDir, "CLAUDE.local.html")), // CLAUDE.local.md should be ignored + pathDoNotExists(join(outputDir, "AGENTS.local.html")), // AGENTS.local.md should be ignored ], { + setup: async () => { + for (const file of localFiles) { + await Deno.writeTextFile( + join(projectDir, file), + "This is a local AI config file that should be ignored during project scanning.\n", + ); + } + }, teardown: async () => { - // Clean up _site directory + for (const file of localFiles) { + removeIfExists(join(projectDir, file)); + } if (existsSync(outputDir)) { await Deno.remove(outputDir, { recursive: true }); } diff --git a/tests/smoke/use/template-ai-config.test.ts b/tests/smoke/use/template-ai-config.test.ts index 12e81b7854..904cad2804 100644 --- a/tests/smoke/use/template-ai-config.test.ts +++ b/tests/smoke/use/template-ai-config.test.ts @@ -29,6 +29,14 @@ Deno.writeTextFileSync( join(templateSourceDir, "AGENTS.md"), "# Agents Configuration\n\nThis should be excluded." ); +Deno.writeTextFileSync( + join(templateSourceDir, "CLAUDE.local.md"), + "# Claude Local Configuration\n\nThis should be excluded." +); +Deno.writeTextFileSync( + join(templateSourceDir, "AGENTS.local.md"), + "# Agents Local Configuration\n\nThis should be excluded." +); Deno.writeTextFileSync( join(templateSourceDir, "README.md"), "# Template README\n\nThis should also be excluded." @@ -46,6 +54,8 @@ testQuartoCmd( fileExists(`${templateFolder}.qmd`), // Template file should be copied and renamed pathDoNotExists(join(workingDir, "CLAUDE.md")), // CLAUDE.md should be excluded pathDoNotExists(join(workingDir, "AGENTS.md")), // AGENTS.md should be excluded + pathDoNotExists(join(workingDir, "CLAUDE.local.md")), // CLAUDE.local.md should be excluded + pathDoNotExists(join(workingDir, "AGENTS.local.md")), // AGENTS.local.md should be excluded pathDoNotExists(join(workingDir, "README.md")), // README.md should also be excluded (sanity check) ], {