From 84c0f345612fb1672be05af732c80f7893aa9276 Mon Sep 17 00:00:00 2001 From: Pluviobyte Date: Fri, 29 May 2026 06:30:48 +0000 Subject: [PATCH] fix(prompt-files): avoid crash when tag is unclosed parsePromptFile only checked for an opening `` tag before running `prompt.split("")[1].trim()`. A `.prompt` file that contains `` but omits the closing `` makes that split return a single-element array, so `[1]` is undefined and `.trim()` throws `TypeError: Cannot read properties of undefined (reading 'trim')`, failing config load over a simple authoring typo. Require both tags before parsing the system block; an unclosed tag now falls through and the whole body is treated as the prompt. Adds tests for the closed, unclosed, and no-system cases. Co-authored-by: Cursor --- core/promptFiles/parsePromptFile.ts | 4 ++- core/promptFiles/parsePromptFile.vitest.ts | 32 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 core/promptFiles/parsePromptFile.vitest.ts diff --git a/core/promptFiles/parsePromptFile.ts b/core/promptFiles/parsePromptFile.ts index 4b6cf6917b8..06eb0458c76 100644 --- a/core/promptFiles/parsePromptFile.ts +++ b/core/promptFiles/parsePromptFile.ts @@ -15,7 +15,9 @@ export function parsePromptFile(path: string, content: string) { const version = preamble.version ?? 2; let systemMessage: string | undefined = undefined; - if (prompt.includes("")) { + // Require both tags: a `` with no matching `` would make + // `split("")[1]` undefined and crash on `.trim()`. + if (prompt.includes("") && prompt.includes("")) { systemMessage = prompt.split("")[1].split("")[0].trim(); prompt = prompt.split("")[1].trim(); } diff --git a/core/promptFiles/parsePromptFile.vitest.ts b/core/promptFiles/parsePromptFile.vitest.ts new file mode 100644 index 00000000000..dd8f508d090 --- /dev/null +++ b/core/promptFiles/parsePromptFile.vitest.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from "vitest"; + +import { parsePromptFile } from "./parsePromptFile.js"; + +describe("parsePromptFile", () => { + it("extracts the system message when both tags are present", () => { + const result = parsePromptFile( + "greeting.prompt", + "You are helpful\nSummarize the file", + ); + + expect(result.systemMessage).toBe("You are helpful"); + expect(result.prompt).toBe("Summarize the file"); + }); + + it("does not throw when has no closing tag", () => { + const content = "You forgot to close the tag\nSummarize the file"; + + expect(() => parsePromptFile("broken.prompt", content)).not.toThrow(); + + const result = parsePromptFile("broken.prompt", content); + expect(result.systemMessage).toBeUndefined(); + expect(result.prompt).toBe(content); + }); + + it("leaves the prompt untouched when there is no system block", () => { + const result = parsePromptFile("plain.prompt", "Just a prompt body"); + + expect(result.systemMessage).toBeUndefined(); + expect(result.prompt).toBe("Just a prompt body"); + }); +});