/** * cli:scaffold-pwa — patchers.ts * * Pure string → string patchers for the client app's existing files. Each one: * - is IDEMPOTENT: applying it twice is a fixpoint (second run → changed:false, * byte-identical content); * - honours the `@customised` head marker (bespoke seam — never rewrite a file * an LLM/dev pass owns); * - returns { content, changed, warning? } — when an anchor cannot be found the * patcher returns the source UNCHANGED with a warning, and the caller surfaces * the full snippet in nextSteps (site-vitrine's snippet-fallback pattern). * * No filesystem access here — index.ts reads the targets, generate.ts routes * them through these patchers, index.ts writes the results. */ export interface PatchResult { content: string changed: boolean warning?: string } /** Resolved manifest values shared by the vite-config + index.html patchers. */ export interface ManifestConfig { name: string shortName: string description: string themeColor: string backgroundColor: string lang?: string } export interface MainTsxOptions { mobile: { enabled: boolean; breakpoint?: number } } /** Same contract as scaffold-component / scaffold-layout: a `@customised` head * marker means the file is bespoke-owned — patchers must never touch it. */ export function isCustomised(source: string): boolean { const head = source.trimStart().slice(0, 100) return ( head.startsWith('/* @customised') || head.startsWith('// @customised') || head.startsWith('