diff --git a/scripts/check-changed.test.ts b/scripts/check-changed.test.ts
index eaba712f4c516..40e75ecf31e59 100644
--- a/scripts/check-changed.test.ts
+++ b/scripts/check-changed.test.ts
@@ -407,6 +407,17 @@ it("checks changed source paths through the Windows launcher", () => {
expect(result.stdout).toContain("fixture stderr: lint");
});
+it("lints an Astro component and runs knip when only it changed", () => {
+ using project = launcherFixture();
+ const page = "packages/example/Page.astro";
+ project.write(page, "---\nconst title = 1;\n---\n
{title}
\n");
+ const result = project.run();
+ expect(result.status, result.stdout + result.stderr).toBe(0);
+ const calls = project.calls();
+ expect(calls.find(({ args }) => args[0] === "lint")?.args).toEqual(["lint", page]);
+ expect(calls.some(({ args }) => args[0] === "exec" && args[1] === "knip")).toBe(true);
+});
+
it.each(["install", "lint"])("reports a failing %s step with its output", (step) => {
using project = launcherFixture();
project.write(project.source, "export const value = 2;\n");
diff --git a/scripts/check-changed.ts b/scripts/check-changed.ts
index 0bf96fb98ca3f..92c47696e6f49 100644
--- a/scripts/check-changed.ts
+++ b/scripts/check-changed.ts
@@ -172,7 +172,8 @@ export const comparisonBase = Effect.fn("checkChanged.comparisonBase")(function*
return closest;
});
-const CODE = /\.[cm]?[jt]sx?$/;
+// CI's lint and knip also read Astro components' frontmatter.
+const CODE = /\.(?:[cm]?[jt]sx?|astro)$/;
const TEST = /\.test\.[cm]?[jt]sx?$/;
// CI runs the .github/scripts tests with `node --test`; vitest passes a failing node:test file.
const NODE_TEST = /^\.github[/\\]scripts[/\\]/;