export function proposedPlanTitle(planMarkdown: string): string | null { const heading = planMarkdown.match(/^\s{0,3}#{1,6}\s+(.+)$/m)?.[1]?.trim(); return heading && heading.length > 0 ? heading : null; } function sanitizePlanFileSegment(input: string): string { const sanitized = input .toLowerCase() .replace(/[`'".,!?()[\]{}]+/g, "") .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, ""); return sanitized.length > 0 ? sanitized : "plan"; } export function buildPlanImplementationPrompt(planMarkdown: string): string { return `PLEASE IMPLEMENT THIS PLAN:\n${planMarkdown.trim()}`; } export function resolvePlanFollowUpSubmission(input: { draftText: string; planMarkdown: string; }): { text: string; interactionMode: "default" | "plan"; } { const trimmedDraftText = input.draftText.trim(); if (trimmedDraftText.length > 0) { return { text: trimmedDraftText, interactionMode: "plan", }; } return { text: buildPlanImplementationPrompt(input.planMarkdown), interactionMode: "default", }; } export function buildPlanImplementationThreadTitle(planMarkdown: string): string { const title = proposedPlanTitle(planMarkdown); if (!title) { return "Implement plan"; } return `Implement ${title}`; } export function buildProposedPlanMarkdownFilename(planMarkdown: string): string { const title = proposedPlanTitle(planMarkdown); return `${sanitizePlanFileSegment(title ?? "plan")}.md`; } export function normalizePlanMarkdownForExport(planMarkdown: string): string { return `${planMarkdown.trimEnd()}\n`; } export function downloadPlanAsTextFile(filename: string, contents: string): void { const blob = new Blob([contents], { type: "text/markdown;charset=utf-8" }); const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = filename; anchor.click(); window.setTimeout(() => { URL.revokeObjectURL(url); }, 0); }