markform 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +32 -4
  2. package/dist/ai-sdk.d.mts +1 -1
  3. package/dist/ai-sdk.mjs +1 -1
  4. package/dist/{apply-CD-t7ovb.mjs → apply-C7mO7VkZ.mjs} +100 -74
  5. package/dist/apply-C7mO7VkZ.mjs.map +1 -0
  6. package/dist/bin.mjs +1 -1
  7. package/dist/{cli-ChdIy1a7.mjs → cli-C8F9yDsv.mjs} +17 -1213
  8. package/dist/cli-C8F9yDsv.mjs.map +1 -0
  9. package/dist/cli.mjs +1 -1
  10. package/dist/{coreTypes-BQrWf_Wt.d.mts → coreTypes-BlsJkU1w.d.mts} +1 -1
  11. package/dist/fillRecord-DTl5lnK0.d.mts +345 -0
  12. package/dist/fillRecordRenderer-CruJrLkj.mjs +1256 -0
  13. package/dist/fillRecordRenderer-CruJrLkj.mjs.map +1 -0
  14. package/dist/index.d.mts +5 -342
  15. package/dist/index.mjs +3 -3
  16. package/dist/render.d.mts +74 -0
  17. package/dist/render.mjs +4 -0
  18. package/dist/{session-ZgegwtkT.mjs → session-BCcltrLA.mjs} +1 -1
  19. package/dist/{session-ZgegwtkT.mjs.map → session-BCcltrLA.mjs.map} +1 -1
  20. package/dist/{session-BPuQ-ok0.mjs → session-VeSkVrck.mjs} +1 -1
  21. package/dist/{shared-DwdyWmvE.mjs → shared-CsdT2T7k.mjs} +1 -1
  22. package/dist/{shared-DwdyWmvE.mjs.map → shared-CsdT2T7k.mjs.map} +1 -1
  23. package/dist/{shared-BTR35aMz.mjs → shared-fb0nkzQi.mjs} +1 -1
  24. package/dist/{src-DOPe4tmu.mjs → src-CbRnGzMK.mjs} +16 -11
  25. package/dist/{src-DOPe4tmu.mjs.map → src-CbRnGzMK.mjs.map} +1 -1
  26. package/dist/urlFormat-lls7CsEP.mjs +71 -0
  27. package/dist/urlFormat-lls7CsEP.mjs.map +1 -0
  28. package/docs/markform-apis.md +53 -0
  29. package/examples/simple/simple-skipped-filled.report.md +8 -8
  30. package/examples/twitter-thread/twitter-thread.form.md +373 -0
  31. package/package.json +5 -1
  32. package/dist/apply-CD-t7ovb.mjs.map +0 -1
  33. package/dist/cli-ChdIy1a7.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-ChdIy1a7.mjs","names":["formatMarkdown","isInteractive","displayContent","formatState","formatConsoleReport","readFile","isInteractive","formatMarkdown","scanFormsDirectory","scanFormsDirectory","formatMarkdown","isInteractive","displayContent","readFile","formatPatchValue","formatPatchValue","readFile","readFile","readFile","readFile","readFile","formatPatchValue","formatState","formatPriority","formatSeverity","formatConsoleReport","readFile","formatMarkdown","isInteractive","displayContent","readFile","readFile","readFile","readFileAsync","readFile","readFile","readFile","formatConsoleReport","readFile","readFile"],"sources":["../src/cli/lib/cliVersion.ts","../src/cli/lib/paths.ts","../src/cli/commands/apis.ts","../src/cli/commands/apply.ts","../src/cli/lib/fileViewer.ts","../src/cli/lib/browseHelpers.ts","../src/cli/commands/browse.ts","../src/cli/commands/docs.ts","../src/cli/lib/exportHelpers.ts","../src/cli/commands/dump.ts","../src/cli/examples/exampleRegistry.ts","../src/cli/lib/formatting.ts","../src/cli/lib/runMode.ts","../src/cli/lib/versioning.ts","../src/cli/lib/interactivePrompts.ts","../src/cli/lib/patchFormat.ts","../src/cli/lib/fillLogging.ts","../src/cli/lib/runHelpers.ts","../src/cli/commands/run.ts","../src/cli/commands/examples.ts","../src/cli/commands/export.ts","../src/cli/lib/fillCallbacks.ts","../src/cli/commands/fill.ts","../src/cli/commands/inspect.ts","../src/cli/commands/readme.ts","../src/cli/commands/report.ts","../src/cli/commands/spec.ts","../src/cli/commands/models.ts","../src/cli/commands/plan.ts","../src/cli/commands/serve.ts","../src/cli/commands/render.ts","../src/cli/lib/initialValues.ts","../src/cli/commands/research.ts","../src/cli/commands/schema.ts","../src/cli/commands/status.ts","../src/cli/commands/validate.ts","../src/cli/cli.ts"],"sourcesContent":["/**\n * CLI version helper that computes git version in development mode.\n *\n * When running via tsx (development), __MARKFORM_VERSION__ is not injected,\n * so VERSION from index.ts returns 'development'. This module computes the\n * actual git version dynamically for consistent version display.\n */\n\nimport { execSync } from 'node:child_process';\nimport { VERSION } from '../../index.js';\n\n/**\n * Get version from git tags with format: X.Y.Z-dev.N.hash\n * Only called when running in development mode (via tsx).\n */\nfunction getGitVersion(): string {\n try {\n const git = (args: string) =>\n execSync(`git ${args}`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();\n\n const tag = git('describe --tags --abbrev=0');\n const tagVersion = tag.replace(/^v/, '');\n const [major, minor, patch] = tagVersion.split('.').map(Number);\n const commitsSinceTag = parseInt(git(`rev-list ${tag}..HEAD --count`), 10);\n const hash = git('rev-parse --short=7 HEAD');\n\n let dirty = false;\n try {\n git('diff --quiet');\n git('diff --cached --quiet');\n } catch {\n dirty = true;\n }\n\n if (commitsSinceTag === 0 && !dirty) {\n return tagVersion;\n }\n\n const bumpedPatch = (patch ?? 0) + 1;\n const suffix = dirty ? `${hash}-dirty` : hash;\n return `${major}.${minor}.${bumpedPatch}-dev.${commitsSinceTag}.${suffix}`;\n } catch {\n return 'development';\n }\n}\n\n/**\n * CLI version - uses build-time VERSION if available, otherwise computes from git.\n */\nexport const CLI_VERSION: string = VERSION === 'development' ? getGitVersion() : VERSION;\n","/**\n * Path utilities for CLI commands.\n *\n * This module contains Node.js-dependent path utilities that are only used\n * by CLI code. Keeping these separate from settings.ts allows the core\n * library to remain Node.js-free.\n */\n\nimport { resolve } from 'node:path';\n\nimport { DEFAULT_FORMS_DIR } from '../../settings.js';\n\n// Re-export for convenience - CLI code can import all path-related things from here\nexport { DEFAULT_FORMS_DIR };\n\n/**\n * Resolve the forms directory path to an absolute path.\n * Uses the provided override or falls back to DEFAULT_FORMS_DIR.\n *\n * @param override Optional override path from CLI --forms-dir option\n * @param cwd Base directory for resolving relative paths (defaults to process.cwd())\n * @returns Absolute path to the forms directory\n */\nexport function getFormsDir(override?: string, cwd: string = process.cwd()): string {\n const formsDir = override ?? DEFAULT_FORMS_DIR;\n return resolve(cwd, formsDir);\n}\n","/**\n * APIs command - Display the Markform API documentation.\n *\n * Shows the markform-apis.md file, formatted for the terminal when interactive,\n * or as plain text when piped. This documents the TypeScript and AI SDK APIs.\n */\n\nimport type { Command } from 'commander';\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport pc from 'picocolors';\n\nimport { getCommandContext, logError, stripHtmlComments } from '../lib/shared.js';\n\n/**\n * Get the path to the markform-apis.md file.\n * Works both during development and when installed as a package.\n */\nfunction getApisPath(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const dirName = thisDir.split(/[/\\\\]/).pop();\n\n if (dirName === 'dist') {\n // Bundled: dist -> package root -> docs/markform-apis.md\n return join(dirname(thisDir), 'docs', 'markform-apis.md');\n }\n\n // Development: src/cli/commands -> src/cli -> src -> package root -> docs/markform-apis.md\n return join(dirname(dirname(dirname(thisDir))), 'docs', 'markform-apis.md');\n}\n\n/**\n * Load the APIs documentation content.\n */\nfunction loadApis(): string {\n const apisPath = getApisPath();\n try {\n return readFileSync(apisPath, 'utf-8');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to load API docs from ${apisPath}: ${message}`);\n }\n}\n\n/**\n * Apply basic terminal formatting to markdown content.\n * Colorizes headers, code blocks, and other elements for better readability.\n */\nfunction formatMarkdown(content: string, useColors: boolean): string {\n if (!useColors) {\n return content;\n }\n\n const lines = content.split('\\n');\n const formatted: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n // Track code blocks\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n formatted.push(pc.dim(line));\n continue;\n }\n\n if (inCodeBlock) {\n formatted.push(pc.dim(line));\n continue;\n }\n\n // Headers\n if (line.startsWith('# ')) {\n formatted.push(pc.bold(pc.cyan(line)));\n continue;\n }\n if (line.startsWith('## ')) {\n formatted.push(pc.bold(pc.blue(line)));\n continue;\n }\n if (line.startsWith('### ')) {\n formatted.push(pc.bold(line));\n continue;\n }\n\n // Inline code (backticks)\n let formattedLine = line.replace(/`([^`]+)`/g, (_match, code: string) => {\n return pc.yellow(code);\n });\n\n // Bold text\n formattedLine = formattedLine.replace(/\\*\\*([^*]+)\\*\\*/g, (_match, text: string) => {\n return pc.bold(text);\n });\n\n // Links - show text in cyan, URL dimmed\n formattedLine = formattedLine.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_match, text: string, url: string) => {\n return `${pc.cyan(text)} ${pc.dim(`(${url})`)}`;\n },\n );\n\n formatted.push(formattedLine);\n }\n\n return formatted.join('\\n');\n}\n\n/**\n * Check if stdout is an interactive terminal.\n */\nfunction isInteractive(): boolean {\n return process.stdout.isTTY === true;\n}\n\n/**\n * Display content.\n */\nfunction displayContent(content: string): void {\n console.log(content);\n}\n\n/**\n * Register the apis command.\n */\nexport function registerApisCommand(program: Command): void {\n program\n .command('apis')\n .description('Display Markform TypeScript and AI SDK API documentation')\n .option('--raw', 'Output raw markdown without formatting')\n .action((options: { raw?: boolean }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const rawApis = loadApis();\n // Strip HTML comments (license headers, etc.) for cleaner output\n const apis = stripHtmlComments(rawApis);\n\n // Determine if we should colorize\n const shouldColorize = !options.raw && isInteractive() && !ctx.quiet;\n\n const formatted = formatMarkdown(apis, shouldColorize);\n displayContent(formatted);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Apply command - Apply patches to a form.\n *\n * Reads patches from JSON and applies them to the form,\n * outputting the modified form or a report.\n */\n\nimport type { Command } from 'commander';\n\nimport pc from 'picocolors';\n\nimport { applyPatches } from '../../engine/apply.js';\nimport { parseForm } from '../../engine/parse.js';\nimport { serializeForm } from '../../engine/serialize.js';\nimport type { ApplyResult, InspectIssue, ProgressState } from '../../engine/coreTypes.js';\nimport { PatchSchema } from '../../engine/coreTypes.js';\nimport {\n formatOutput,\n getCommandContext,\n logDryRun,\n logError,\n logSuccess,\n logVerbose,\n readFile,\n writeFile,\n} from '../lib/shared.js';\n\ninterface ApplyReport {\n apply_status: 'applied' | 'partial' | 'rejected';\n form_state: ProgressState;\n is_complete: boolean;\n structure: ApplyResult['structureSummary'];\n progress: ApplyResult['progressSummary'];\n issues: InspectIssue[];\n}\n\n/**\n * Format state badge for console output.\n */\nfunction formatState(state: ProgressState, useColors: boolean): string {\n const badges: Record<ProgressState, [string, (s: string) => string]> = {\n complete: ['✓ complete', pc.green],\n incomplete: ['○ incomplete', pc.yellow],\n empty: ['◌ empty', pc.dim],\n invalid: ['✗ invalid', pc.red],\n };\n const [text, colorFn] = badges[state] ?? [state, (s: string) => s];\n return useColors ? colorFn(text) : text;\n}\n\n/**\n * Format apply report for console output.\n */\nfunction formatConsoleReport(report: ApplyReport, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n const green = useColors ? pc.green : (s: string) => s;\n const red = useColors ? pc.red : (s: string) => s;\n\n // Header\n lines.push(bold(cyan('Apply Result')));\n lines.push('');\n\n // Status\n const statusColor = report.apply_status === 'applied' ? green : red;\n lines.push(`${bold('Status:')} ${statusColor(report.apply_status)}`);\n lines.push(`${bold('Form State:')} ${formatState(report.form_state, useColors)}`);\n lines.push(`${bold('Complete:')} ${report.is_complete ? green('yes') : dim('no')}`);\n lines.push('');\n\n // Progress summary\n const counts = report.progress.counts;\n lines.push(bold('Progress:'));\n lines.push(` Total fields: ${counts.totalFields}`);\n lines.push(` Valid: ${counts.validFields}, Invalid: ${counts.invalidFields}`);\n lines.push(` Filled: ${counts.filledFields}, Empty: ${counts.emptyFields}`);\n lines.push(` Empty required: ${counts.emptyRequiredFields}`);\n lines.push('');\n\n // Issues\n if (report.issues.length > 0) {\n lines.push(bold(`Issues (${report.issues.length}):`));\n for (const issue of report.issues) {\n const priority = `P${issue.priority}`;\n lines.push(` ${dim(priority)} ${dim(issue.ref)}: ${issue.message}`);\n }\n } else {\n lines.push(dim('No issues.'));\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Register the apply command.\n */\nexport function registerApplyCommand(program: Command): void {\n program\n .command('apply <file>')\n .description('Apply patches to a form')\n .option('--patch <json>', 'JSON array of patches to apply')\n .option('-o, --output <file>', 'Output file (defaults to stdout)')\n .option('--report', 'Output apply result report instead of modified form')\n .option('--normalize', 'Regenerate form without preserving external content')\n .action(\n async (\n file: string,\n options: { patch?: string; output?: string; report?: boolean; normalize?: boolean },\n cmd: Command,\n ) => {\n const ctx = getCommandContext(cmd);\n\n try {\n // Validate patch option\n if (!options.patch) {\n logError('--patch option is required');\n process.exit(1);\n }\n\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Parsing patches...');\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(options.patch) as unknown;\n } catch {\n logError('Invalid JSON in --patch option');\n process.exit(1);\n }\n\n if (!Array.isArray(parsedJson)) {\n logError('--patch must be a JSON array');\n process.exit(1);\n }\n const patches = parsedJson as unknown[];\n\n // Validate each patch against schema\n const validatedPatches = [];\n for (let i = 0; i < patches.length; i++) {\n const result = PatchSchema.safeParse(patches[i]);\n if (!result.success) {\n logError(\n `Invalid patch at index ${i}: ${result.error.issues[0]?.message ?? 'Unknown error'}`,\n );\n process.exit(1);\n }\n validatedPatches.push(result.data);\n }\n\n if (ctx.dryRun) {\n logDryRun(`Would apply ${validatedPatches.length} patches to ${file}`, {\n patches: validatedPatches,\n });\n return;\n }\n\n logVerbose(ctx, `Applying ${validatedPatches.length} patches...`);\n const result = applyPatches(form, validatedPatches);\n\n if (result.applyStatus === 'rejected') {\n logError('Patches rejected - structural validation failed');\n const report: ApplyReport = {\n apply_status: result.applyStatus,\n form_state: result.formState,\n is_complete: result.isComplete,\n structure: result.structureSummary,\n progress: result.progressSummary,\n issues: result.issues,\n };\n const output = formatOutput(ctx, report, (data, useColors) =>\n formatConsoleReport(data as ApplyReport, useColors),\n );\n console.error(output);\n process.exit(1);\n }\n\n // Output result\n if (options.report) {\n // Output apply result report\n const report: ApplyReport = {\n apply_status: result.applyStatus,\n form_state: result.formState,\n is_complete: result.isComplete,\n structure: result.structureSummary,\n progress: result.progressSummary,\n issues: result.issues,\n };\n\n const output = formatOutput(ctx, report, (data, useColors) =>\n formatConsoleReport(data as ApplyReport, useColors),\n );\n if (options.output) {\n await writeFile(options.output, output);\n logSuccess(ctx, `Report written to ${options.output}`);\n } else {\n console.log(output);\n }\n } else {\n // Output modified form (always markdown)\n // --normalize disables content preservation (regenerates from scratch)\n const output = serializeForm(form, {\n preserveContent: !options.normalize,\n });\n if (options.output) {\n await writeFile(options.output, output);\n logSuccess(ctx, `Modified form written to ${options.output}`);\n } else {\n console.log(output);\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n },\n );\n}\n","/**\n * File viewer utility for displaying files with colorization and pagination.\n *\n * Provides a modern console experience:\n * - Syntax highlighting for markdown and YAML\n * - Pagination using system pager (less) when available\n * - Fallback to console output when not interactive\n */\n\nimport * as p from '@clack/prompts';\nimport { spawn } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { basename } from 'node:path';\nimport pc from 'picocolors';\n\n/**\n * File option for the viewer chooser.\n */\nexport interface FileOption {\n path: string;\n label: string;\n hint?: string;\n}\n\n/**\n * Check if stdout is an interactive terminal.\n */\nfunction isInteractive(): boolean {\n return process.stdout.isTTY === true;\n}\n\n/**\n * Apply terminal formatting to markdown content.\n * Colorizes headers, code blocks, and other elements.\n */\nfunction formatMarkdown(content: string): string {\n const lines = content.split('\\n');\n const formatted: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n // Track code blocks\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n formatted.push(pc.dim(line));\n continue;\n }\n\n if (inCodeBlock) {\n formatted.push(pc.cyan(line));\n continue;\n }\n\n // Headers\n if (line.startsWith('# ')) {\n formatted.push(pc.bold(pc.magenta(line)));\n continue;\n }\n if (line.startsWith('## ')) {\n formatted.push(pc.bold(pc.blue(line)));\n continue;\n }\n if (line.startsWith('### ')) {\n formatted.push(pc.bold(pc.cyan(line)));\n continue;\n }\n if (line.startsWith('#### ')) {\n formatted.push(pc.bold(line));\n continue;\n }\n\n // Inline code (backticks)\n let formattedLine = line.replace(/`([^`]+)`/g, (_match, code: string) => {\n return pc.yellow(code);\n });\n\n // Bold text\n formattedLine = formattedLine.replace(/\\*\\*([^*]+)\\*\\*/g, (_match, text: string) => {\n return pc.bold(text);\n });\n\n // Links - show text in cyan, URL dimmed\n formattedLine = formattedLine.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_match, text: string, url: string) => {\n return `${pc.cyan(text)} ${pc.dim(`(${url})`)}`;\n },\n );\n\n // Markform tags - highlight them distinctively\n formattedLine = formattedLine.replace(\n /\\{%\\s*(\\w+)\\s*([^%]*)\\s*%\\}/g,\n (_match, tag: string, attrs: string) => {\n const attrsPart = attrs.trim() ? ` ${pc.dim(attrs.trim())}` : '';\n return `${pc.dim('{% ')}${pc.green(tag)}${attrsPart} ${pc.dim('%}')}`;\n },\n );\n\n formatted.push(formattedLine);\n }\n\n return formatted.join('\\n');\n}\n\n/**\n * Apply terminal formatting to YAML content.\n */\nfunction formatYaml(content: string): string {\n const lines = content.split('\\n');\n const formatted: string[] = [];\n\n for (const line of lines) {\n // Comments\n if (line.trim().startsWith('#')) {\n formatted.push(pc.dim(line));\n continue;\n }\n\n // Key-value pairs\n const match = /^(\\s*)([^:]+)(:)(.*)$/.exec(line);\n if (match) {\n const [, indent, key, colon, value] = match;\n formatted.push(`${indent}${pc.cyan(key)}${pc.dim(colon)}${pc.yellow(value)}`);\n continue;\n }\n\n // List items\n if (line.trim().startsWith('-')) {\n formatted.push(pc.green(line));\n continue;\n }\n\n formatted.push(line);\n }\n\n return formatted.join('\\n');\n}\n\n/**\n * Format file content based on extension.\n */\nfunction formatContent(content: string, filename: string): string {\n if (filename.endsWith('.yml') || filename.endsWith('.yaml')) {\n return formatYaml(content);\n }\n if (filename.endsWith('.md')) {\n return formatMarkdown(content);\n }\n return content;\n}\n\n/**\n * Display content using system pager (less) if available.\n * Falls back to console.log if not interactive or pager unavailable.\n *\n * @returns Promise that resolves when viewing is complete\n */\nasync function displayWithPager(content: string, title: string): Promise<void> {\n if (!isInteractive()) {\n console.log(content);\n return;\n }\n\n // Show title header\n const header = `${pc.bgCyan(pc.black(` ${title} `))}`;\n\n return new Promise((resolve) => {\n // Try to use less with useful options:\n // -R: interpret ANSI colors\n // -S: don't wrap long lines\n // -X: don't clear screen on exit\n // -F: quit if content fits on one screen\n // -K: exit on Ctrl-C\n const pager = spawn('less', ['-R', '-S', '-X', '-F', '-K'], {\n stdio: ['pipe', 'inherit', 'inherit'],\n });\n\n pager.on('error', () => {\n // If less is not available, fall back to console output\n console.log(header);\n console.log('');\n console.log(content);\n console.log('');\n resolve();\n });\n\n pager.on('close', () => {\n resolve();\n });\n\n // Write content with header\n pager.stdin.write(header + '\\n\\n');\n pager.stdin.write(content);\n pager.stdin.end();\n });\n}\n\n/**\n * Load and display a file with formatting and pagination.\n */\nexport async function viewFile(filePath: string): Promise<void> {\n const content = readFileSync(filePath, 'utf-8');\n const filename = basename(filePath);\n const formatted = formatContent(content, filename);\n await displayWithPager(formatted, filename);\n}\n\n/**\n * Show an interactive file viewer chooser.\n *\n * Presents a list of files to view:\n * - \"Show report:\" for the report output (.report.md) at the top\n * - \"Show source:\" for other files (.form.md, .raw.md, .yml)\n * - \"Quit\" at the bottom\n *\n * Loops until the user selects Quit.\n *\n * @param files Array of file options to display\n */\nexport async function showFileViewerChooser(files: FileOption[]): Promise<void> {\n if (!isInteractive()) {\n return;\n }\n\n console.log('');\n\n // Identify report (.report.md) vs source files\n const reportFile = files.find((f) => f.path.endsWith('.report.md'));\n const sourceFiles = files.filter((f) => !f.path.endsWith('.report.md'));\n\n while (true) {\n const options: { value: string; label: string; hint?: string }[] = [];\n\n // Report file first (if exists)\n if (reportFile) {\n options.push({\n value: reportFile.path,\n label: `Show report: ${pc.green(basename(reportFile.path))}`,\n hint: reportFile.hint ?? '',\n });\n }\n\n // Source files\n for (const file of sourceFiles) {\n options.push({\n value: file.path,\n label: `Show source: ${pc.green(basename(file.path))}`,\n hint: file.hint ?? '',\n });\n }\n\n // Quit option at the end\n options.push({\n value: 'quit',\n label: 'Quit',\n hint: '',\n });\n\n const selection = await p.select({\n message: 'View files:',\n options,\n });\n\n if (p.isCancel(selection) || selection === 'quit') {\n break;\n }\n\n await viewFile(selection);\n console.log('');\n }\n}\n","/**\n * Browse helpers - Pure/testable functions extracted from browse command.\n *\n * These functions handle file scanning and formatting for the browse command,\n * separated from interactive UI code to enable unit testing.\n */\n\nimport { readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport pc from 'picocolors';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** File extensions we support viewing */\nexport const VIEWABLE_EXTENSIONS = [\n '.form.md',\n '.report.md',\n '.yml',\n '.yaml',\n '.schema.json',\n '.raw.md',\n];\n\nexport interface FileEntry {\n path: string;\n filename: string;\n mtime: Date;\n extension: string;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Check if a file has a viewable extension.\n */\nexport function isViewableFile(filename: string): boolean {\n return VIEWABLE_EXTENSIONS.some((ext) => filename.endsWith(ext));\n}\n\n/**\n * Get the display extension for sorting/grouping.\n */\nexport function getExtension(filename: string): string {\n for (const ext of VIEWABLE_EXTENSIONS) {\n if (filename.endsWith(ext)) {\n return ext;\n }\n }\n return '';\n}\n\n/**\n * Scan forms directory for viewable files.\n */\nexport function scanFormsDirectory(formsDir: string, filter?: string): FileEntry[] {\n const entries: FileEntry[] = [];\n\n try {\n const files = readdirSync(formsDir);\n for (const file of files) {\n if (!isViewableFile(file)) continue;\n\n // Apply filter if provided\n if (filter && !file.toLowerCase().includes(filter.toLowerCase())) {\n continue;\n }\n\n const fullPath = join(formsDir, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile()) {\n entries.push({\n path: fullPath,\n filename: file,\n mtime: stat.mtime,\n extension: getExtension(file),\n });\n }\n } catch {\n // Skip files we can't stat\n }\n }\n } catch {\n // Directory doesn't exist or can't be read\n }\n\n // Sort by modification time (most recent first), then by filename\n entries.sort((a, b) => {\n const timeDiff = b.mtime.getTime() - a.mtime.getTime();\n if (timeDiff !== 0) return timeDiff;\n return a.filename.localeCompare(b.filename);\n });\n\n return entries;\n}\n\n/**\n * Get extension hint for display.\n */\nexport function getExtensionHint(ext: string): string {\n switch (ext) {\n case '.form.md':\n return 'markform source';\n case '.report.md':\n return 'output report';\n case '.yml':\n case '.yaml':\n return 'YAML values';\n case '.schema.json':\n return 'JSON Schema';\n case '.raw.md':\n return 'raw markdown';\n default:\n return '';\n }\n}\n\n/**\n * Format file entry for menu display.\n */\nexport function formatFileLabel(entry: FileEntry): string {\n const icon = entry.extension === '.report.md' ? pc.green('*') : ' ';\n return `${icon} ${entry.filename}`;\n}\n","/**\n * Browse command - Interactive file browser for the forms directory.\n *\n * Provides a menu-based interface for viewing files with syntax highlighting\n * and pagination. Shows .form.md, .report.md, .yml, and .schema.json files.\n *\n * Usage:\n * markform browse # Browse all files in forms/\n * markform browse --filter=foo # Only show files matching pattern\n */\n\nimport { statSync } from 'node:fs';\nimport { basename } from 'node:path';\n\nimport type { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { getFormsDir } from '../lib/paths.js';\nimport { getCommandContext, logError, formatPath } from '../lib/shared.js';\nimport { showFileViewerChooser, viewFile, type FileOption } from '../lib/fileViewer.js';\nimport { scanFormsDirectory, getExtensionHint, formatFileLabel } from '../lib/browseHelpers.js';\n\n// =============================================================================\n// Exported Functions\n// =============================================================================\n\n/**\n * Browse files in the forms directory interactively.\n *\n * This is the core browse functionality that can be called programmatically\n * from other commands (like examples).\n *\n * @param formsDir - Path to the forms directory\n * @param filter - Optional filter pattern to match filenames\n * @returns Promise that resolves when user quits the browser\n */\nexport async function browseFormsDirectory(formsDir: string, filter?: string): Promise<void> {\n const entries = scanFormsDirectory(formsDir, filter);\n\n if (entries.length === 0) {\n if (filter) {\n p.log.warn(`No files matching \"${filter}\" found in ${formatPath(formsDir)}`);\n } else {\n p.log.warn(`No viewable files found in ${formatPath(formsDir)}`);\n }\n return;\n }\n\n // Convert to FileOption format for the viewer\n const files: FileOption[] = entries.map((entry) => ({\n path: entry.path,\n label: basename(entry.path),\n hint: getExtensionHint(entry.extension),\n }));\n\n // Use the existing file viewer chooser\n await showFileViewerChooser(files);\n}\n\n/**\n * Browse specific output files after a form run.\n *\n * This is a convenience function for the examples workflow that shows\n * the standard output files (report, yml, form, schema) for a completed form.\n *\n * @param basePath - Base path of the output (e.g., \"forms/movie-research-demo-filled1\")\n */\nexport async function browseOutputFiles(basePath: string): Promise<void> {\n // Standard output file extensions\n const outputExtensions = ['.report.md', '.yml', '.form.md', '.schema.json'];\n\n const files: FileOption[] = [];\n for (const ext of outputExtensions) {\n const fullPath = basePath + ext;\n try {\n statSync(fullPath);\n files.push({\n path: fullPath,\n label: basename(fullPath),\n hint: getExtensionHint(ext),\n });\n } catch {\n // File doesn't exist, skip\n }\n }\n\n if (files.length === 0) {\n return;\n }\n\n await showFileViewerChooser(files);\n}\n\n// =============================================================================\n// Command Registration\n// =============================================================================\n\n/**\n * Register the browse command.\n */\nexport function registerBrowseCommand(program: Command): void {\n program\n .command('browse')\n .description('Browse and view files in the forms directory')\n .option('--filter <pattern>', 'Only show files matching pattern')\n .action(async (options: { filter?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const formsDir = getFormsDir(ctx.formsDir);\n\n p.intro(pc.bgCyan(pc.black(' markform browse ')));\n\n const entries = scanFormsDirectory(formsDir, options.filter);\n\n if (entries.length === 0) {\n if (options.filter) {\n p.log.warn(`No files matching \"${options.filter}\" found in ${formatPath(formsDir)}`);\n } else {\n p.log.warn(`No viewable files found in ${formatPath(formsDir)}`);\n }\n console.log('');\n console.log(`Run ${pc.cyan(\"'markform examples'\")} to get started.`);\n p.outro('');\n return;\n }\n\n // Show file count\n console.log(pc.dim(`Found ${entries.length} file(s) in ${formatPath(formsDir)}`));\n\n // Build menu options\n const menuOptions: { value: string; label: string; hint?: string }[] = entries.map(\n (entry) => ({\n value: entry.path,\n label: formatFileLabel(entry),\n hint: getExtensionHint(entry.extension),\n }),\n );\n\n // Add quit option\n menuOptions.push({\n value: 'quit',\n label: 'Quit',\n hint: '',\n });\n\n // Interactive loop\n while (true) {\n const selection = await p.select({\n message: 'Select a file to view:',\n options: menuOptions,\n });\n\n if (p.isCancel(selection)) {\n break;\n }\n\n // Now selection is narrowed to string\n if (selection === 'quit') {\n break;\n }\n\n // View the selected file\n await viewFile(selection);\n console.log('');\n }\n\n p.outro('');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Docs command - Display the Markform quick reference.\n *\n * Shows the markform-reference.md file, formatted for the terminal when interactive,\n * or as plain text when piped. This is a concise reference for writing forms,\n * optimized for agent consumption.\n */\n\nimport type { Command } from 'commander';\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport pc from 'picocolors';\n\nimport { getCommandContext, logError, stripHtmlComments } from '../lib/shared.js';\n\n/**\n * Get the path to the markform-reference.md file.\n * Works both during development and when installed as a package.\n */\nfunction getDocsPath(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const dirName = thisDir.split(/[/\\\\]/).pop();\n\n if (dirName === 'dist') {\n // Bundled: dist -> package root -> docs/markform-reference.md\n return join(dirname(thisDir), 'docs', 'markform-reference.md');\n }\n\n // Development: src/cli/commands -> src/cli -> src -> package root -> docs/markform-reference.md\n return join(dirname(dirname(dirname(thisDir))), 'docs', 'markform-reference.md');\n}\n\n/**\n * Load the docs content.\n */\nfunction loadDocs(): string {\n const docsPath = getDocsPath();\n try {\n return readFileSync(docsPath, 'utf-8');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to load reference docs from ${docsPath}: ${message}`);\n }\n}\n\n/**\n * Apply basic terminal formatting to markdown content.\n * Colorizes headers, code blocks, and other elements for better readability.\n */\nfunction formatMarkdown(content: string, useColors: boolean): string {\n if (!useColors) {\n return content;\n }\n\n const lines = content.split('\\n');\n const formatted: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n // Track code blocks\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n formatted.push(pc.dim(line));\n continue;\n }\n\n if (inCodeBlock) {\n formatted.push(pc.dim(line));\n continue;\n }\n\n // Headers\n if (line.startsWith('# ')) {\n formatted.push(pc.bold(pc.cyan(line)));\n continue;\n }\n if (line.startsWith('## ')) {\n formatted.push(pc.bold(pc.blue(line)));\n continue;\n }\n if (line.startsWith('### ')) {\n formatted.push(pc.bold(line));\n continue;\n }\n\n // Inline code (backticks)\n let formattedLine = line.replace(/`([^`]+)`/g, (_match, code: string) => {\n return pc.yellow(code);\n });\n\n // Bold text\n formattedLine = formattedLine.replace(/\\*\\*([^*]+)\\*\\*/g, (_match, text: string) => {\n return pc.bold(text);\n });\n\n // Links - show text in cyan, URL dimmed\n formattedLine = formattedLine.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_match, text: string, url: string) => {\n return `${pc.cyan(text)} ${pc.dim(`(${url})`)}`;\n },\n );\n\n formatted.push(formattedLine);\n }\n\n return formatted.join('\\n');\n}\n\n/**\n * Check if stdout is an interactive terminal.\n */\nfunction isInteractive(): boolean {\n return process.stdout.isTTY === true;\n}\n\n/**\n * Display content.\n */\nfunction displayContent(content: string): void {\n console.log(content);\n}\n\n/**\n * Register the docs command.\n */\nexport function registerDocsCommand(program: Command): void {\n program\n .command('docs')\n .description('Display concise Markform syntax reference (agent-friendly)')\n .option('--raw', 'Output raw markdown without formatting')\n .action((options: { raw?: boolean }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const rawDocs = loadDocs();\n // Strip HTML comments (license headers, etc.) for cleaner output\n const docs = stripHtmlComments(rawDocs);\n\n // Determine if we should colorize\n const shouldColorize = !options.raw && isInteractive() && !ctx.quiet;\n\n const formatted = formatMarkdown(docs, shouldColorize);\n displayContent(formatted);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Export helpers for multi-format form output.\n *\n * Provides reusable functions for exporting forms to multiple formats:\n * - Markform format (.form.md) - canonical form with directives\n * - Raw markdown (.raw.md) - plain readable markdown\n * - YAML values (.yml) - extracted field values\n * - JSON Schema (.schema.json) - form structure for validation/tooling\n */\n\nimport YAML from 'yaml';\n\nimport { serializeForm, serializeReport } from '../../engine/serialize.js';\nimport { formToJsonSchema } from '../../engine/jsonSchema.js';\nimport type { ParsedForm } from '../../engine/coreTypes.js';\nimport { deriveExportPath, deriveReportPath, deriveSchemaPath } from '../../settings.js';\nimport type { ExportResult } from './cliTypes.js';\nimport { writeFile } from './shared.js';\n\n// Re-export types for backwards compatibility\nexport type { ExportResult } from './cliTypes.js';\n\n/**\n * Convert field responses to structured format for export (markform-218).\n *\n * Includes state for all fields:\n * - { state: 'unanswered' } for unfilled fields\n * - { state: 'skipped' } for skipped fields\n * - { state: 'aborted' } for aborted fields\n * - { state: 'answered', value: ... } for answered fields\n */\nexport function toStructuredValues(form: ParsedForm): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [fieldId, response] of Object.entries(form.responsesByFieldId)) {\n if (!response || response.state === 'unanswered') {\n result[fieldId] = { state: 'unanswered' };\n continue;\n }\n\n if (response.state === 'skipped') {\n result[fieldId] = {\n state: 'skipped',\n ...(response.reason && { reason: response.reason }),\n };\n continue;\n }\n\n if (response.state === 'aborted') {\n result[fieldId] = {\n state: 'aborted',\n ...(response.reason && { reason: response.reason }),\n };\n continue;\n }\n\n // state === 'answered'\n if (!response.value) {\n result[fieldId] = { state: 'answered', value: null };\n continue;\n }\n\n const value = response.value;\n let exportValue: unknown;\n\n switch (value.kind) {\n case 'string':\n exportValue = value.value ?? null;\n break;\n case 'number':\n exportValue = value.value ?? null;\n break;\n case 'string_list':\n exportValue = value.items;\n break;\n case 'single_select':\n exportValue = value.selected ?? null;\n break;\n case 'multi_select':\n exportValue = value.selected;\n break;\n case 'checkboxes':\n exportValue = value.values;\n break;\n case 'url':\n exportValue = value.value ?? null;\n break;\n case 'url_list':\n exportValue = value.items;\n break;\n case 'date':\n exportValue = value.value ?? null;\n break;\n case 'year':\n exportValue = value.value ?? null;\n break;\n case 'table':\n // Export table rows as array of objects with column IDs as keys\n exportValue = value.rows.map((row) => {\n const rowObj: Record<string, unknown> = {};\n for (const [colId, cellResp] of Object.entries(row)) {\n rowObj[colId] = cellResp.value ?? null;\n }\n return rowObj;\n });\n break;\n default: {\n // Exhaustiveness check - TypeScript will error if a case is missing\n const _exhaustive: never = value;\n throw new Error(`Unhandled field value kind: ${(_exhaustive as { kind: string }).kind}`);\n }\n }\n\n result[fieldId] = { state: 'answered', value: exportValue };\n }\n\n return result;\n}\n\n/**\n * Convert notes to export format (markform-219).\n */\nexport function toNotesArray(form: ParsedForm) {\n return form.notes.map((note) => ({\n id: note.id,\n ref: note.ref,\n role: note.role,\n text: note.text,\n }));\n}\n\n/**\n * Derive export paths from a base form path.\n * Uses centralized extension constants from settings.ts.\n *\n * Standard exports: report, values (yaml), form, schema.\n * Raw markdown is available via CLI but not in standard exports.\n *\n * @param basePath - Path to the .form.md file\n * @returns Object with paths for all export formats\n */\nexport function deriveExportPaths(basePath: string): ExportResult {\n return {\n reportPath: deriveReportPath(basePath),\n yamlPath: deriveExportPath(basePath, 'yaml'),\n formPath: deriveExportPath(basePath, 'form'),\n schemaPath: deriveSchemaPath(basePath),\n };\n}\n\n/**\n * Export form to multiple formats.\n *\n * Standard exports:\n * - Report format (.report.md) - filtered markdown (excludes instructions, report=false)\n * - YAML values (.yml) - structured format with state and notes\n * - Markform format (.form.md) - canonical form with directives\n * - JSON Schema (.schema.json) - form structure for validation/tooling\n *\n * Note: Raw markdown (.raw.md) is available via CLI `markform export --raw`\n * but is not included in standard multi-format export.\n *\n * @param form - The parsed form to export\n * @param basePath - Base path for the .form.md file (other paths are derived)\n * @returns Paths to all exported files\n */\nexport async function exportMultiFormat(form: ParsedForm, basePath: string): Promise<ExportResult> {\n const paths = deriveExportPaths(basePath);\n\n // Export report markdown (filtered, no instructions, excludes report=false)\n const reportContent = serializeReport(form);\n await writeFile(paths.reportPath, reportContent);\n\n // Export YAML values with structured format (markform-218, markform-219)\n const values = toStructuredValues(form);\n const notes = toNotesArray(form);\n const exportData = {\n values,\n ...(notes.length > 0 && { notes }),\n };\n const yamlContent = YAML.stringify(exportData);\n await writeFile(paths.yamlPath, yamlContent);\n\n // Export form markdown\n const formContent = serializeForm(form);\n await writeFile(paths.formPath, formContent);\n\n // Export JSON Schema\n const schemaResult = formToJsonSchema(form);\n const schemaContent = JSON.stringify(schemaResult.schema, null, 2) + '\\n';\n await writeFile(paths.schemaPath, schemaContent);\n\n return paths;\n}\n\n/**\n * Export form to markform format only.\n *\n * Use this for commands like `markform fill` where only the canonical format\n * is needed by default. Users can generate raw/yaml via `markform export` or\n * `markform dump`. Note: The `examples` command uses exportMultiFormat() for\n * both user and agent fills.\n *\n * @param form - The parsed form to export\n * @param outputPath - Path to write the .form.md file\n */\nexport async function exportFormOnly(form: ParsedForm, outputPath: string): Promise<void> {\n const formContent = serializeForm(form);\n await writeFile(outputPath, formContent);\n}\n","/**\n * Dump command - Extract and display form values only.\n *\n * A lightweight alternative to inspect that outputs only the values map,\n * without structure, progress, or validation information.\n * Useful for quick value extraction, scripting, and integration.\n *\n * Output includes full state for all fields:\n * - answered: shows the value\n * - skipped: shows reason if available\n * - unanswered: indicates field is not yet filled\n */\n\nimport type { Command } from 'commander';\n\nimport pc from 'picocolors';\n\nimport { parseForm } from '../../engine/parse.js';\nimport type { FieldResponse, ParsedForm } from '../../engine/coreTypes.js';\nimport { toStructuredValues, toNotesArray } from '../lib/exportHelpers.js';\nimport { formatOutput, getCommandContext, logError, logVerbose, readFile } from '../lib/shared.js';\n\n/**\n * Format a field response for console display, including state information.\n */\nfunction formatFieldResponse(response: FieldResponse, useColors: boolean): string {\n const dim = useColors ? pc.dim : (s: string) => s;\n const green = useColors ? pc.green : (s: string) => s;\n const yellow = useColors ? pc.yellow : (s: string) => s;\n\n if (response.state === 'unanswered') {\n return dim('(unanswered)');\n }\n\n if (response.state === 'skipped') {\n const reason = response.reason ? ` ${response.reason}` : '';\n return yellow(`[skipped]${reason}`);\n }\n\n if (response.state === 'aborted') {\n const reason = response.reason ? ` ${response.reason}` : '';\n return yellow(`[aborted]${reason}`);\n }\n\n // state === 'answered'\n const value = response.value;\n if (!value) {\n return dim('(empty)');\n }\n\n switch (value.kind) {\n case 'string':\n return value.value ? green(`\"${value.value}\"`) : dim('(empty)');\n case 'number':\n return value.value !== null ? green(String(value.value)) : dim('(empty)');\n case 'string_list':\n return value.items.length > 0 ? green(`[${value.items.join(', ')}]`) : dim('(empty)');\n case 'single_select':\n return value.selected ? green(value.selected) : dim('(none selected)');\n case 'multi_select':\n return value.selected.length > 0\n ? green(`[${value.selected.join(', ')}]`)\n : dim('(none selected)');\n case 'checkboxes': {\n const entries = Object.entries(value.values);\n if (entries.length === 0) {\n return dim('(no entries)');\n }\n return entries.map(([k, v]) => `${k}:${v}`).join(', ');\n }\n case 'url':\n return value.value ? green(`\"${value.value}\"`) : dim('(empty)');\n case 'url_list':\n return value.items.length > 0 ? green(`[${value.items.join(', ')}]`) : dim('(empty)');\n case 'date':\n return value.value ? green(value.value) : dim('(empty)');\n case 'year':\n return value.value !== null ? green(String(value.value)) : dim('(empty)');\n case 'table': {\n const rowCount = value.rows?.length ?? 0;\n return rowCount > 0 ? green(`(${rowCount} rows)`) : dim('(empty)');\n }\n default: {\n // Exhaustiveness check - TypeScript will error if a case is missing\n const _exhaustive: never = value;\n throw new Error(`Unhandled field value kind: ${(_exhaustive as { kind: string }).kind}`);\n }\n }\n}\n\n/**\n * Format form responses for console output, showing all fields with their states.\n */\nfunction formatConsoleResponses(form: ParsedForm, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n\n for (const [fieldId, response] of Object.entries(form.responsesByFieldId)) {\n const valueStr = formatFieldResponse(response, useColors);\n lines.push(`${bold(fieldId)}: ${valueStr}`);\n }\n\n if (lines.length === 0) {\n lines.push(dim('(no fields)'));\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Register the dump command.\n */\nexport function registerDumpCommand(program: Command): void {\n program\n .command('dump <file>')\n .description('Extract and display form values with state (lightweight inspect)')\n .action(async (file: string, _options: Record<string, unknown>, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n // For JSON/YAML output, use toStructuredValues which includes state\n // For console/plaintext, use formatted output with field states\n const isStructured = ctx.format === 'json' || ctx.format === 'yaml';\n\n if (isStructured) {\n // Use toStructuredValues for state-aware structured output\n const structuredOutput = {\n values: toStructuredValues(form),\n ...(form.notes.length > 0 && { notes: toNotesArray(form) }),\n };\n\n const output = formatOutput(ctx, structuredOutput, () => '');\n console.log(output);\n } else {\n // Use formatted output for console/plaintext with state display\n const output = formatOutput(ctx, form, (data, useColors) =>\n formatConsoleResponses(data as ParsedForm, useColors),\n );\n console.log(output);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Example form registry.\n * Provides form content from the examples directory for the examples CLI command.\n *\n * Metadata (title, description) is loaded dynamically from the form's YAML frontmatter\n * rather than being duplicated here, following the single source of truth principle.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport Markdoc from '@markdoc/markdoc';\nimport YAML from 'yaml';\n\nimport type { ExampleDefinition } from '../lib/cliTypes.js';\n\n// Re-export types for backwards compatibility\nexport type { ExampleDefinition } from '../lib/cliTypes.js';\n\n/**\n * Example definitions without content or metadata.\n * Title and description are loaded dynamically from frontmatter.\n */\nexport const EXAMPLE_DEFINITIONS: ExampleDefinition[] = [\n {\n id: 'movie-research-demo',\n filename: 'movie-research-demo.form.md',\n path: 'movie-research/movie-research-demo.form.md',\n type: 'research',\n },\n {\n id: 'simple',\n filename: 'simple.form.md',\n path: 'simple/simple.form.md',\n type: 'fill',\n },\n {\n id: 'movie-deep-research',\n filename: 'movie-deep-research.form.md',\n path: 'movie-research/movie-deep-research.form.md',\n type: 'research',\n },\n {\n id: 'startup-deep-research',\n filename: 'startup-deep-research.form.md',\n path: 'startup-deep-research/startup-deep-research.form.md',\n type: 'research',\n },\n];\n\n/** Default example ID for menus (movie-research-demo, index 0) */\nexport const DEFAULT_EXAMPLE_ID = 'movie-research-demo';\n\n/**\n * Get the canonical order index for an example by filename.\n * Returns -1 if not found (unknown files sort to the end).\n */\nexport function getExampleOrder(filename: string): number {\n const index = EXAMPLE_DEFINITIONS.findIndex((e) => e.filename === filename);\n return index >= 0 ? index : EXAMPLE_DEFINITIONS.length;\n}\n\n/**\n * Get the path to the examples directory.\n * Works both during development and when installed as a package.\n */\nfunction getExamplesDir(): string {\n // Get the directory of this file\n // - Bundled mode: thisDir is /path/to/package/dist\n // - Dev mode: thisDir is /path/to/package/src/cli/examples\n const thisDir = dirname(fileURLToPath(import.meta.url));\n\n // Check if we're in the dist directory (bundled mode)\n // Use basename to check the directory name, not a substring match\n const dirName = thisDir.split(/[/\\\\]/).pop();\n if (dirName === 'dist') {\n // Bundled: dist -> package root -> examples\n return join(dirname(thisDir), 'examples');\n }\n\n // Development mode: src/cli/examples -> src/cli -> src -> package root -> examples\n return join(dirname(dirname(dirname(thisDir))), 'examples');\n}\n\n/**\n * Load the content of an example form.\n * @param exampleId - The example ID (e.g., 'simple', 'movie-deep-research')\n * @returns The form content as a string\n * @throws Error if the example is not found\n */\nexport function loadExampleContent(exampleId: string): string {\n const example = EXAMPLE_DEFINITIONS.find((e) => e.id === exampleId);\n if (!example) {\n throw new Error(`Unknown example: ${exampleId}`);\n }\n\n const examplesDir = getExamplesDir();\n const filePath = join(examplesDir, example.path);\n\n try {\n return readFileSync(filePath, 'utf-8');\n } catch (error) {\n throw new Error(\n `Failed to load example '${exampleId}' from ${filePath}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Get all example IDs.\n */\nexport function getExampleIds(): string[] {\n return EXAMPLE_DEFINITIONS.map((e) => e.id);\n}\n\n/**\n * Get an example definition by ID.\n */\nexport function getExampleById(id: string): ExampleDefinition | undefined {\n return EXAMPLE_DEFINITIONS.find((e) => e.id === id);\n}\n\n/**\n * Get the absolute path to an example's source file.\n * @param exampleId - The example ID (e.g., 'simple', 'movie-deep-research')\n * @returns The absolute path to the example form file\n * @throws Error if the example is not found\n */\nexport function getExamplePath(exampleId: string): string {\n const example = EXAMPLE_DEFINITIONS.find((e) => e.id === exampleId);\n if (!example) {\n throw new Error(`Unknown example: ${exampleId}`);\n }\n return join(getExamplesDir(), example.path);\n}\n\n/**\n * Extract YAML frontmatter from markdown content using Markdoc's native support.\n * @param content - The markdown file content\n * @returns The parsed frontmatter object or null if no frontmatter found\n */\nfunction extractFrontmatter(content: string): Record<string, unknown> | null {\n const ast = Markdoc.parse(content);\n const rawFrontmatter = ast.attributes.frontmatter as string | undefined;\n if (!rawFrontmatter) {\n return null;\n }\n try {\n return YAML.parse(rawFrontmatter) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Load metadata (title, description) from an example's YAML frontmatter.\n * @param exampleId - The example ID (e.g., 'simple', 'movie-deep-research')\n * @returns Object with title and description from frontmatter\n */\nexport function loadExampleMetadata(exampleId: string): { title?: string; description?: string } {\n const content = loadExampleContent(exampleId);\n const frontmatter = extractFrontmatter(content);\n\n if (!frontmatter?.markform) {\n return {};\n }\n\n const markform = frontmatter.markform as Record<string, unknown>;\n return {\n title: typeof markform.title === 'string' ? markform.title : undefined,\n description: typeof markform.description === 'string' ? markform.description : undefined,\n };\n}\n\n/**\n * Get an example definition with metadata loaded from frontmatter.\n * @param id - The example ID\n * @returns ExampleDefinition with title and description populated\n */\nexport function getExampleWithMetadata(id: string): ExampleDefinition | undefined {\n const example = getExampleById(id);\n if (!example) {\n return undefined;\n }\n\n const metadata = loadExampleMetadata(id);\n return {\n ...example,\n title: metadata.title,\n description: metadata.description,\n };\n}\n\n/**\n * Get all example definitions with metadata loaded from frontmatter.\n * @returns Array of ExampleDefinition with title and description populated\n */\nexport function getAllExamplesWithMetadata(): ExampleDefinition[] {\n return EXAMPLE_DEFINITIONS.map((example) => {\n const metadata = loadExampleMetadata(example.id);\n return {\n ...example,\n title: metadata.title,\n description: metadata.description,\n };\n });\n}\n","/**\n * Color and output formatting utilities for CLI.\n */\n\nimport pc from 'picocolors';\n\nimport type { InspectIssue, IssueReason } from '../../engine/coreTypes.js';\nimport type { FormDisplayInfo } from './cliTypes.js';\n\n/**\n * Semantic color helpers for consistent CLI output.\n */\nexport const colors = {\n success: (msg: string) => pc.green(msg),\n error: (msg: string) => pc.red(msg),\n warn: (msg: string) => pc.yellow(msg),\n info: (msg: string) => pc.cyan(msg),\n dim: (msg: string) => pc.dim(msg),\n bold: (msg: string) => pc.bold(msg),\n title: (msg: string) => pc.bold(pc.cyan(msg)),\n};\n\n/**\n * Format a duration in seconds.\n */\nexport function formatDuration(ms: number): string {\n const seconds = (ms / 1000).toFixed(1);\n return `${seconds}s`;\n}\n\n/**\n * Format a timing message.\n */\nexport function formatTiming(label: string, durationMs: number): string {\n return pc.cyan(`⏰ ${label}: ${formatDuration(durationMs)}`);\n}\n\n/**\n * Format a count with label.\n */\nexport function formatCount(count: number, label: string): string {\n return `${count} ${label}${count === 1 ? '' : 's'}`;\n}\n\n/**\n * Format a state badge.\n */\nexport function formatState(state: string): string {\n switch (state) {\n case 'complete':\n return pc.green('✓ complete');\n case 'incomplete':\n return pc.yellow('○ incomplete');\n case 'empty':\n return pc.dim('◌ empty');\n case 'invalid':\n return pc.red('✗ invalid');\n default:\n return state;\n }\n}\n\n/**\n * Format a priority badge.\n *\n * Priority tiers and colors:\n * - P1: bold red (critical)\n * - P2: yellow (high)\n * - P3: cyan (medium)\n * - P4: blue (low)\n * - P5: dim/gray (minimal)\n */\nexport function formatPriority(priority: number): string {\n const label = `P${priority}`;\n switch (priority) {\n case 1:\n return pc.red(pc.bold(label));\n case 2:\n return pc.yellow(label);\n case 3:\n return pc.cyan(label);\n case 4:\n return pc.blue(label);\n case 5:\n default:\n return pc.dim(label);\n }\n}\n\n/**\n * Get a short status word from an issue reason.\n */\nexport function issueReasonToStatus(reason: IssueReason): string {\n switch (reason) {\n case 'required_missing':\n return 'missing';\n case 'validation_error':\n return 'invalid';\n case 'checkbox_incomplete':\n return 'incomplete';\n case 'min_items_not_met':\n return 'too-few';\n case 'optional_unanswered':\n return 'unanswered';\n default:\n return 'issue';\n }\n}\n\n/**\n * Format a single issue as \"fieldId (status)\".\n */\nexport function formatIssueBrief(issue: InspectIssue): string {\n const status = issueReasonToStatus(issue.reason);\n return `${issue.ref} (${status})`;\n}\n\n/**\n * Format a list of issues as a compact comma-separated summary.\n * Example: \"company_name (missing), revenue (invalid), tasks (incomplete)\"\n */\nexport function formatIssuesSummary(issues: InspectIssue[]): string {\n return issues.map(formatIssueBrief).join(', ');\n}\n\n/**\n * Format issues for turn logging - shows count and brief field list.\n * Example: \"5 issue(s): company_name (missing), revenue (invalid), ...\"\n */\nexport function formatTurnIssues(issues: InspectIssue[], maxShow = 5): string {\n const count = issues.length;\n if (count === 0) {\n return '0 issues';\n }\n\n const shown = issues.slice(0, maxShow);\n const summary = shown.map(formatIssueBrief).join(', ');\n const suffix = count > maxShow ? `, +${count - maxShow} more` : '';\n\n return `${count} issue(s): ${summary}${suffix}`;\n}\n\n// =============================================================================\n// Form Display Formatting\n// =============================================================================\n\n/**\n * Format form info for menu label display.\n * Format: \"filename - Title [runMode]\"\n * Example: \"movie-deep-research.form.md - Movie Deep Research [research]\"\n */\nexport function formatFormLabel(info: FormDisplayInfo): string {\n const titlePart = info.title ? ` - ${info.title}` : '';\n const runModePart = info.runMode ? ` [${info.runMode}]` : '';\n return `${info.filename}${titlePart}${runModePart}`;\n}\n\n/**\n * Format form info for menu hint display.\n * Returns description without parentheses (prompts library adds them).\n */\nexport function formatFormHint(info: FormDisplayInfo): string {\n return info.description ?? '';\n}\n\n/**\n * Format form info for log line (e.g., after copying).\n * Format: \"filename - Title\" (dimmed title)\n * Example: \"✓ movie-deep-research.form.md - Movie Deep Research\"\n */\nexport function formatFormLogLine(info: FormDisplayInfo, prefix: string): string {\n const titlePart = info.title ? ` - ${info.title}` : '';\n return `${prefix} ${info.filename}${pc.dim(titlePart)}`;\n}\n","/**\n * Run mode utilities for the CLI.\n *\n * Provides functions for:\n * - Validating run_mode against form structure\n * - Inferring run_mode from field roles\n * - Determining run mode for execution\n */\n\nimport type { ParsedForm, RunMode } from '../../engine/coreTypes.js';\nimport { getAllFields } from '../../engine/inspect.js';\nimport { isResearchForm } from '../../research/researchFormValidation.js';\nimport { AGENT_ROLE, USER_ROLE } from '../../settings.js';\n\n/**\n * Get the set of unique roles present in a form's fields.\n */\nexport function getFieldRoles(form: ParsedForm): Set<string> {\n const allFields = getAllFields(form);\n return new Set(allFields.map((field) => field.role));\n}\n\n/**\n * Validation result for run_mode.\n */\nexport interface RunModeValidationResult {\n valid: boolean;\n error?: string;\n}\n\n/**\n * Validate that run_mode is consistent with form structure.\n *\n * Rules:\n * - interactive: Form MUST have at least one role=\"user\" field\n * - fill: Form MUST have at least one role=\"agent\" field\n * - research: Form MUST have at least one role=\"agent\" field\n */\nexport function validateRunMode(form: ParsedForm, runMode: RunMode): RunModeValidationResult {\n const roles = getFieldRoles(form);\n\n switch (runMode) {\n case 'interactive':\n if (!roles.has(USER_ROLE)) {\n return {\n valid: false,\n error: `run_mode=\"interactive\" but form has no user-role fields. Available roles: ${[...roles].join(', ') || '(none)'}`,\n };\n }\n break;\n\n case 'fill':\n case 'research':\n if (!roles.has(AGENT_ROLE)) {\n return {\n valid: false,\n error: `run_mode=\"${runMode}\" but form has no agent-role fields. Available roles: ${[...roles].join(', ') || '(none)'}`,\n };\n }\n break;\n }\n\n return { valid: true };\n}\n\n/**\n * Result of run mode determination.\n */\nexport type DetermineRunModeResult =\n | { success: true; runMode: RunMode; source: 'explicit' | 'inferred' }\n | { success: false; error: string };\n\n/**\n * Determine the run mode for a form.\n *\n * 1. If explicit run_mode in frontmatter, validate and use it\n * 2. Otherwise, infer from field roles:\n * - All user fields → interactive\n * - All agent fields → fill (or research if isResearchForm)\n * - Mixed roles → error (require explicit run_mode)\n */\nexport function determineRunMode(form: ParsedForm): DetermineRunModeResult {\n // 1. Explicit run_mode in frontmatter takes precedence\n const explicitMode = form.metadata?.runMode;\n if (explicitMode) {\n const validation = validateRunMode(form, explicitMode);\n if (!validation.valid) {\n return { success: false, error: validation.error! };\n }\n return { success: true, runMode: explicitMode, source: 'explicit' };\n }\n\n // 2. Infer from field roles (no complex heuristics)\n const roles = getFieldRoles(form);\n\n // Handle empty form\n if (roles.size === 0) {\n return { success: false, error: 'Form has no fields' };\n }\n\n // Single role: user only\n if (roles.size === 1 && roles.has(USER_ROLE)) {\n return { success: true, runMode: 'interactive', source: 'inferred' };\n }\n\n // Single role: agent only\n if (roles.size === 1 && roles.has(AGENT_ROLE)) {\n // Check if research-configured\n if (isResearchForm(form)) {\n return { success: true, runMode: 'research', source: 'inferred' };\n }\n return { success: true, runMode: 'fill', source: 'inferred' };\n }\n\n // Mixed roles or unknown - require explicit run_mode\n return {\n success: false,\n error:\n `Cannot determine run mode. Form has roles: ${[...roles].join(', ')}. ` +\n `Add 'run_mode' to frontmatter: interactive, fill, or research.`,\n };\n}\n\n/**\n * Get a human-readable description of the run mode source.\n */\nexport function formatRunModeSource(source: 'explicit' | 'inferred'): string {\n return source === 'explicit' ? 'from frontmatter' : 'inferred from field roles';\n}\n","/**\n * Versioned filename utilities for form output.\n *\n * Generates versioned filenames to avoid overwriting existing files.\n * Pattern: name.form.md → name-filled1.form.md → name-filled2.form.md\n */\n\nimport { existsSync } from 'node:fs';\nimport { basename, join } from 'node:path';\n\n/**\n * Version pattern that matches -filledN or _filledN before the extension.\n * Also matches legacy -vN pattern for backwards compatibility.\n */\nconst VERSION_PATTERN = /^(.+?)(?:[-_]?(?:filled|v)(\\d+))?(\\.form\\.md)$/i;\n\n/**\n * Extension pattern for fallback matching.\n */\nconst EXTENSION_PATTERN = /^(.+)(\\.form\\.md)$/i;\n\n/**\n * Parse a versioned filename into its components.\n *\n * @param filePath - Path to parse\n * @returns Parsed components or null if not a valid form file\n */\nexport function parseVersionedPath(filePath: string): {\n base: string;\n version: number | null;\n extension: string;\n} | null {\n const match = VERSION_PATTERN.exec(filePath);\n if (match) {\n const base = match[1];\n const versionStr = match[2];\n const ext = match[3];\n // The regex guarantees base and ext are defined when match succeeds\n if (base !== undefined && ext !== undefined) {\n return {\n base,\n version: versionStr ? parseInt(versionStr, 10) : null,\n extension: ext,\n };\n }\n }\n\n const extMatch = EXTENSION_PATTERN.exec(filePath);\n if (extMatch) {\n const base = extMatch[1];\n const ext = extMatch[2];\n // The regex guarantees both groups are defined when match succeeds\n if (base !== undefined && ext !== undefined) {\n return {\n base,\n version: null,\n extension: ext,\n };\n }\n }\n\n return null;\n}\n\n/**\n * Generate the next versioned filename.\n *\n * If the file has no version, adds -filled1.\n * If the file has a version, increments it.\n *\n * @param filePath - Original file path\n * @returns Next versioned filename\n */\nexport function incrementVersion(filePath: string): string {\n const parsed = parseVersionedPath(filePath);\n\n if (parsed) {\n const newVersion = parsed.version !== null ? parsed.version + 1 : 1;\n return `${parsed.base}-filled${newVersion}${parsed.extension}`;\n }\n\n // Fallback for non-.form.md files\n return `${filePath}-filled1`;\n}\n\n/**\n * Generate a versioned filename that doesn't conflict with existing files.\n *\n * Starts from the incremented version and keeps incrementing until\n * a non-existent filename is found.\n *\n * @param filePath - Original file path\n * @returns Path to a non-existent versioned file\n */\nexport function generateVersionedPath(filePath: string): string {\n const parsed = parseVersionedPath(filePath);\n\n if (!parsed) {\n // Fallback for non-.form.md files\n let candidate = `${filePath}-filled1`;\n let version = 1;\n while (existsSync(candidate)) {\n version++;\n candidate = `${filePath}-filled${version}`;\n }\n return candidate;\n }\n\n // Start from version 1 or increment existing version\n let version = parsed.version !== null ? parsed.version + 1 : 1;\n let candidate = `${parsed.base}-filled${version}${parsed.extension}`;\n\n // Find next available version\n while (existsSync(candidate)) {\n version++;\n candidate = `${parsed.base}-filled${version}${parsed.extension}`;\n }\n\n return candidate;\n}\n\n/**\n * Generate a versioned filename within the forms directory.\n *\n * Derives the base name from the input path and creates a versioned\n * output path within the specified forms directory.\n *\n * @param inputPath - Original input file path (used to derive basename)\n * @param formsDir - Absolute path to the forms directory\n * @returns Absolute path to a non-existent versioned file in formsDir\n */\nexport function generateVersionedPathInFormsDir(inputPath: string, formsDir: string): string {\n // Get the filename from the input path\n const inputFilename = basename(inputPath);\n\n // Parse to get base name without version\n const parsed = parseVersionedPath(inputFilename);\n\n // Use the base name (stripped of any existing version) or the full filename\n const baseName = parsed?.base ?? inputFilename.replace(/\\.form\\.md$/i, '');\n const extension = parsed?.extension ?? '.form.md';\n\n // Start from version 1 and find next available\n let version = 1;\n let candidate = join(formsDir, `${baseName}-filled${version}${extension}`);\n\n while (existsSync(candidate)) {\n version++;\n candidate = join(formsDir, `${baseName}-filled${version}${extension}`);\n }\n\n return candidate;\n}\n","/**\n * Interactive prompts module for console-based form filling.\n *\n * Uses @clack/prompts to provide a rich terminal UI for users to\n * fill form fields interactively.\n */\n\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport type {\n Field,\n FieldValue,\n Patch,\n SkipFieldPatch,\n StringField,\n NumberField,\n StringListField,\n SingleSelectField,\n MultiSelectField,\n CheckboxesField,\n UrlField,\n UrlListField,\n DateField,\n YearField,\n ParsedForm,\n InspectIssue,\n} from '../../engine/coreTypes.js';\n\n/**\n * Context for a field prompt including description from docs.\n */\ninterface FieldPromptContext {\n field: Field;\n currentValue: FieldValue | undefined;\n description?: string;\n index: number;\n total: number;\n}\n\n/**\n * Get field description from form docs.\n */\nfunction getFieldDescription(form: ParsedForm, fieldId: string): string | undefined {\n const doc = form.docs.find(\n (d) => d.ref === fieldId && (d.tag === 'description' || d.tag === 'instructions'),\n );\n return doc?.bodyMarkdown;\n}\n\n/**\n * Get a field by ID from the form schema.\n */\nfunction getFieldById(form: ParsedForm, fieldId: string): Field | undefined {\n for (const group of form.schema.groups) {\n const field = group.children.find((f) => f.id === fieldId);\n if (field) {\n return field;\n }\n }\n return undefined;\n}\n\n/**\n * Format field label with required indicator and progress.\n */\nfunction formatFieldLabel(ctx: FieldPromptContext): string {\n const required = ctx.field.required ? pc.red('*') : '';\n const progress = `(${ctx.index} of ${ctx.total})`;\n return `${ctx.field.label}${required} ${progress}`;\n}\n\n/**\n * Create a skip_field patch for the given field.\n */\nfunction createSkipPatch(field: Field): SkipFieldPatch {\n return {\n op: 'skip_field',\n fieldId: field.id,\n role: 'user',\n reason: 'User skipped in console',\n };\n}\n\n/**\n * For optional fields, prompt user to choose between filling or skipping.\n * Returns \"fill\" if user wants to enter a value, or a skip_field patch if skipping.\n * Returns null if user cancelled.\n */\nasync function promptSkipOrFill(ctx: FieldPromptContext): Promise<'fill' | SkipFieldPatch | null> {\n const field = ctx.field;\n\n // Required fields must be filled - no skip option\n if (field.required) {\n return 'fill';\n }\n\n const result = await p.select({\n message: `${formatFieldLabel(ctx)} ${pc.dim('(optional)')}`,\n options: [\n { value: 'fill', label: 'Enter value' },\n { value: 'skip', label: 'Skip this field' },\n ],\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n if (result === 'skip') {\n return createSkipPatch(field);\n }\n\n return 'fill';\n}\n\n/**\n * Prompt for a string field value.\n */\nasync function promptForString(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as StringField;\n const currentVal = ctx.currentValue?.kind === 'string' ? ctx.currentValue.value : null;\n\n // Prefer field placeholder, fall back to current value or description\n const placeholderText =\n field.placeholder ?? currentVal ?? (ctx.description ? ctx.description.slice(0, 60) : undefined);\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: placeholderText,\n initialValue: currentVal ?? '',\n validate: (value) => {\n if (field.required && !value?.trim()) {\n return 'This field is required';\n }\n if (field.minLength && (value?.length ?? 0) < field.minLength) {\n return `Minimum ${field.minLength} characters required`;\n }\n if (field.maxLength && (value?.length ?? 0) > field.maxLength) {\n return `Maximum ${field.maxLength} characters allowed`;\n }\n if (field.pattern && value && !new RegExp(field.pattern).test(value)) {\n return `Must match pattern: ${field.pattern}`;\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n // Skip if empty and not required (user pressed Enter to skip)\n if (!result && !field.required) {\n return null;\n }\n\n return {\n op: 'set_string',\n fieldId: field.id,\n value: result ?? null,\n };\n}\n\n/**\n * Prompt for a number field value.\n */\nasync function promptForNumber(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as NumberField;\n const currentVal = ctx.currentValue?.kind === 'number' ? ctx.currentValue.value : null;\n\n // Prefer field placeholder, fall back to current value\n const placeholderText =\n field.placeholder ?? (currentVal !== null ? String(currentVal) : undefined);\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: placeholderText,\n initialValue: currentVal !== null ? String(currentVal) : '',\n validate: (value) => {\n if (field.required && !value?.trim()) {\n return 'This field is required';\n }\n if (!value?.trim()) {\n return undefined; // Allow empty for optional\n }\n const num = Number(value);\n if (isNaN(num)) {\n return 'Please enter a valid number';\n }\n if (field.integer && !Number.isInteger(num)) {\n return 'Please enter a whole number';\n }\n if (field.min !== undefined && num < field.min) {\n return `Minimum value is ${field.min}`;\n }\n if (field.max !== undefined && num > field.max) {\n return `Maximum value is ${field.max}`;\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n // Skip if empty and not required\n if (!result && !field.required) {\n return null;\n }\n\n return {\n op: 'set_number',\n fieldId: field.id,\n value: result ? Number(result) : null,\n };\n}\n\n/**\n * Prompt for a string list field value.\n */\nasync function promptForStringList(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as StringListField;\n const currentItems = ctx.currentValue?.kind === 'string_list' ? ctx.currentValue.items : [];\n\n // Prefer field placeholder, fall back to description or default hint\n let hint: string;\n if (field.placeholder) {\n hint = `${field.placeholder} (one item per line)`;\n } else if (ctx.description) {\n hint = `${ctx.description.slice(0, 50)}... (one item per line)`;\n } else {\n hint = 'Enter items, one per line. Press Enter twice when done.';\n }\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: hint,\n initialValue: currentItems.join('\\n'),\n validate: (value) => {\n const items = (value ?? '')\n .split('\\n')\n .map((s) => s.trim())\n .filter(Boolean);\n if (field.required && items.length === 0) {\n return 'At least one item is required';\n }\n if (field.minItems && items.length < field.minItems) {\n return `Minimum ${field.minItems} items required`;\n }\n if (field.maxItems && items.length > field.maxItems) {\n return `Maximum ${field.maxItems} items allowed`;\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n const items = (result ?? '')\n .split('\\n')\n .map((s) => s.trim())\n .filter(Boolean);\n\n // Skip if empty and not required\n if (items.length === 0 && !field.required) {\n return null;\n }\n\n return {\n op: 'set_string_list',\n fieldId: field.id,\n value: items,\n };\n}\n\n/**\n * Prompt for a single-select field value.\n */\nasync function promptForSingleSelect(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as SingleSelectField;\n const currentSelected =\n ctx.currentValue?.kind === 'single_select' ? ctx.currentValue.selected : null;\n\n const options = field.options.map((opt) => ({\n value: opt.id,\n label: opt.label,\n }));\n\n const result = await p.select({\n message: formatFieldLabel(ctx),\n options,\n initialValue: currentSelected ?? undefined,\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n return {\n op: 'set_single_select',\n fieldId: field.id,\n value: result,\n };\n}\n\n/**\n * Prompt for a multi-select field value.\n */\nasync function promptForMultiSelect(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as MultiSelectField;\n const currentSelected =\n ctx.currentValue?.kind === 'multi_select' ? ctx.currentValue.selected : [];\n\n const options = field.options.map((opt) => ({\n value: opt.id,\n label: opt.label,\n }));\n\n const result = await p.multiselect({\n message: formatFieldLabel(ctx),\n options,\n initialValues: currentSelected,\n required: field.required,\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n return {\n op: 'set_multi_select',\n fieldId: field.id,\n value: result,\n };\n}\n\n/**\n * Prompt for a checkboxes field value.\n *\n * Behavior varies by checkboxMode:\n * - simple: multiselect to pick items marked as done\n * - multi: per-option select with 5 states\n * - explicit: per-option yes/no/skip\n */\nasync function promptForCheckboxes(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as CheckboxesField;\n const currentValues = ctx.currentValue?.kind === 'checkboxes' ? ctx.currentValue.values : {};\n\n if (field.checkboxMode === 'simple') {\n // Simple mode: multiselect to mark items as done\n const options = field.options.map((opt) => ({\n value: opt.id,\n label: opt.label,\n }));\n\n const currentlyDone = field.options\n .filter((opt) => currentValues[opt.id] === 'done')\n .map((opt) => opt.id);\n\n const result = await p.multiselect({\n message: formatFieldLabel(ctx),\n options,\n initialValues: currentlyDone,\n required: field.required && field.minDone !== undefined && field.minDone > 0,\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n const selected = result;\n const values: Record<string, 'todo' | 'done'> = {};\n for (const opt of field.options) {\n values[opt.id] = selected.includes(opt.id) ? 'done' : 'todo';\n }\n\n return {\n op: 'set_checkboxes',\n fieldId: field.id,\n value: values,\n };\n }\n\n if (field.checkboxMode === 'explicit') {\n // Explicit mode: yes/no for each option\n const values: Record<string, 'yes' | 'no' | 'unfilled'> = {};\n\n for (const opt of field.options) {\n const current = currentValues[opt.id];\n const result = await p.select({\n message: `${opt.label}`,\n options: [\n { value: 'yes', label: 'Yes' },\n { value: 'no', label: 'No' },\n { value: 'unfilled', label: 'Skip' },\n ],\n initialValue: current === 'yes' || current === 'no' ? current : 'unfilled',\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n values[opt.id] = result as 'yes' | 'no' | 'unfilled';\n }\n\n return {\n op: 'set_checkboxes',\n fieldId: field.id,\n value: values,\n };\n }\n\n // Multi mode: 5 states per option\n const values: Record<string, 'todo' | 'done' | 'incomplete' | 'active' | 'na'> = {};\n\n for (const opt of field.options) {\n const current = currentValues[opt.id] as\n | 'todo'\n | 'done'\n | 'incomplete'\n | 'active'\n | 'na'\n | undefined;\n const result = await p.select({\n message: `${opt.label}`,\n options: [\n { value: 'todo', label: 'To do' },\n { value: 'active', label: 'In progress' },\n { value: 'done', label: 'Done' },\n { value: 'incomplete', label: 'Incomplete' },\n { value: 'na', label: 'N/A' },\n ],\n initialValue: current ?? 'todo',\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n values[opt.id] = result;\n }\n\n return {\n op: 'set_checkboxes',\n fieldId: field.id,\n value: values,\n };\n}\n\n/**\n * Prompt for a URL field value.\n */\nasync function promptForUrl(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as UrlField;\n const currentVal = ctx.currentValue?.kind === 'url' ? ctx.currentValue.value : null;\n\n // Prefer field placeholder, fall back to current value or default\n const placeholderText = field.placeholder ?? currentVal ?? 'https://example.com';\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: placeholderText,\n initialValue: currentVal ?? '',\n validate: (value) => {\n if (field.required && !value?.trim()) {\n return 'This field is required';\n }\n if (!value?.trim()) {\n return undefined; // Allow empty for optional\n }\n // Basic URL validation\n try {\n new URL(value);\n } catch {\n return 'Please enter a valid URL (e.g., https://example.com)';\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n // Skip if empty and not required (user pressed Enter to skip)\n if (!result && !field.required) {\n return null;\n }\n\n return {\n op: 'set_url',\n fieldId: field.id,\n value: result ?? null,\n };\n}\n\n/**\n * Check if a string is a valid ISO 8601 date (YYYY-MM-DD).\n */\nfunction isValidDate(str: string): boolean {\n const pattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n if (!pattern.test(str)) {\n return false;\n }\n const date = new Date(str);\n if (isNaN(date.getTime())) {\n return false;\n }\n // Check the date components match to reject invalid dates like 2025-02-30\n const [year, month, day] = str.split('-').map(Number);\n return (\n date.getUTCFullYear() === year && date.getUTCMonth() + 1 === month && date.getUTCDate() === day\n );\n}\n\n/**\n * Prompt for a date field value.\n */\nasync function promptForDate(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as DateField;\n const currentVal = ctx.currentValue?.kind === 'date' ? ctx.currentValue.value : null;\n\n // Build format hint\n const constraints: string[] = [];\n if (field.min) constraints.push(`min: ${field.min}`);\n if (field.max) constraints.push(`max: ${field.max}`);\n const formatHint = constraints.length > 0 ? ` (${constraints.join(', ')})` : '';\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: currentVal ?? `YYYY-MM-DD${formatHint}`,\n initialValue: currentVal ?? '',\n validate: (value) => {\n if (field.required && !value?.trim()) {\n return 'This field is required';\n }\n if (!value?.trim()) {\n return undefined; // Allow empty for optional\n }\n // Date format validation\n if (!isValidDate(value)) {\n return 'Please enter a valid date in YYYY-MM-DD format';\n }\n // Min/max validation\n if (field.min && value < field.min) {\n return `Date must be on or after ${field.min}`;\n }\n if (field.max && value > field.max) {\n return `Date must be on or before ${field.max}`;\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n // Skip if empty and not required (user pressed Enter to skip)\n if (!result && !field.required) {\n return null;\n }\n\n return {\n op: 'set_date',\n fieldId: field.id,\n value: result ?? null,\n };\n}\n\n/** Default year range for validation */\nconst DEFAULT_MIN_YEAR = 1000;\nconst DEFAULT_MAX_YEAR = 2500;\n\n/**\n * Prompt for a year field value.\n */\nasync function promptForYear(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as YearField;\n const currentVal = ctx.currentValue?.kind === 'year' ? ctx.currentValue.value : null;\n\n // Get effective min/max with defaults\n const minYear = field.min ?? DEFAULT_MIN_YEAR;\n const maxYear = field.max ?? DEFAULT_MAX_YEAR;\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: currentVal !== null ? String(currentVal) : `Year (${minYear}-${maxYear})`,\n initialValue: currentVal !== null ? String(currentVal) : '',\n validate: (value) => {\n if (field.required && !value?.trim()) {\n return 'This field is required';\n }\n if (!value?.trim()) {\n return undefined; // Allow empty for optional\n }\n // Year must be an integer\n const num = Number(value);\n if (isNaN(num) || !Number.isInteger(num)) {\n return 'Please enter a valid year (e.g., 2025)';\n }\n // Range validation\n if (num < minYear) {\n return `Year must be ${minYear} or later`;\n }\n if (num > maxYear) {\n return `Year must be ${maxYear} or earlier`;\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n // Skip if empty and not required\n if (!result && !field.required) {\n return null;\n }\n\n return {\n op: 'set_year',\n fieldId: field.id,\n value: result ? Number(result) : null,\n };\n}\n\n/**\n * Prompt for a URL list field value.\n */\nasync function promptForUrlList(ctx: FieldPromptContext): Promise<Patch | null> {\n const field = ctx.field as UrlListField;\n const currentItems = ctx.currentValue?.kind === 'url_list' ? ctx.currentValue.items : [];\n\n // Prefer field placeholder, fall back to description or default hint\n let hint: string;\n if (field.placeholder) {\n hint = `${field.placeholder} (one URL per line)`;\n } else if (ctx.description) {\n hint = `${ctx.description.slice(0, 50)}... (one URL per line)`;\n } else {\n hint = 'Enter URLs, one per line. Press Enter twice when done.';\n }\n\n const result = await p.text({\n message: formatFieldLabel(ctx),\n placeholder: hint,\n initialValue: currentItems.join('\\n'),\n validate: (value) => {\n const items = (value ?? '')\n .split('\\n')\n .map((s) => s.trim())\n .filter(Boolean);\n if (field.required && items.length === 0) {\n return 'At least one URL is required';\n }\n if (field.minItems && items.length < field.minItems) {\n return `Minimum ${field.minItems} URLs required`;\n }\n if (field.maxItems && items.length > field.maxItems) {\n return `Maximum ${field.maxItems} URLs allowed`;\n }\n // Validate each URL\n for (const item of items) {\n try {\n new URL(item);\n } catch {\n return `Invalid URL: ${item}`;\n }\n }\n return undefined;\n },\n });\n\n if (p.isCancel(result)) {\n return null;\n }\n\n const items = (result ?? '')\n .split('\\n')\n .map((s) => s.trim())\n .filter(Boolean);\n\n // Skip if empty and not required\n if (items.length === 0 && !field.required) {\n return null;\n }\n\n return {\n op: 'set_url_list',\n fieldId: field.id,\n value: items,\n };\n}\n\n/**\n * Prompt user for a single field value based on field kind.\n * Returns a Patch to set the value, or null if skipped/cancelled.\n *\n * For optional fields, first offers a choice to skip or fill.\n */\nexport async function promptForField(ctx: FieldPromptContext): Promise<Patch | null> {\n // Show description if available\n if (ctx.description) {\n p.note(ctx.description, pc.dim('Instructions'));\n }\n\n // For optional fields, offer skip/fill choice first\n const skipOrFillResult = await promptSkipOrFill(ctx);\n\n if (skipOrFillResult === null) {\n // User cancelled\n return null;\n }\n\n if (typeof skipOrFillResult !== 'string') {\n // User chose to skip - return the skip_field patch\n return skipOrFillResult;\n }\n\n // User chose to fill - proceed to field-specific prompt\n switch (ctx.field.kind) {\n case 'string':\n return promptForString(ctx);\n case 'number':\n return promptForNumber(ctx);\n case 'string_list':\n return promptForStringList(ctx);\n case 'single_select':\n return promptForSingleSelect(ctx);\n case 'multi_select':\n return promptForMultiSelect(ctx);\n case 'checkboxes':\n return promptForCheckboxes(ctx);\n case 'url':\n return promptForUrl(ctx);\n case 'url_list':\n return promptForUrlList(ctx);\n case 'date':\n return promptForDate(ctx);\n case 'year':\n return promptForYear(ctx);\n default:\n // Unknown field kind - skip\n return null;\n }\n}\n\n/**\n * Run an interactive fill session for a list of field issues.\n * Returns patches for all filled fields.\n *\n * @param form - The parsed form\n * @param issues - The issues indicating fields to fill\n * @returns Array of patches to apply\n */\nexport async function runInteractiveFill(\n form: ParsedForm,\n issues: InspectIssue[],\n): Promise<{ patches: Patch[]; cancelled: boolean }> {\n // Filter to field-level issues only (not form/group/option)\n const fieldIssues = issues.filter((i) => i.scope === 'field');\n\n // Deduplicate by fieldId (a field might have multiple issues)\n const seenFieldIds = new Set<string>();\n const uniqueFieldIssues = fieldIssues.filter((issue) => {\n if (seenFieldIds.has(issue.ref)) {\n return false;\n }\n seenFieldIds.add(issue.ref);\n return true;\n });\n\n if (uniqueFieldIssues.length === 0) {\n p.note('No fields to fill for the selected role.', 'Info');\n return { patches: [], cancelled: false };\n }\n\n const patches: Patch[] = [];\n let index = 0;\n\n for (const issue of uniqueFieldIssues) {\n const field = getFieldById(form, issue.ref);\n if (!field) {\n continue;\n }\n\n index++;\n const response = form.responsesByFieldId[field.id];\n const ctx: FieldPromptContext = {\n field,\n currentValue: response?.state === 'answered' ? response.value : undefined,\n description: getFieldDescription(form, field.id),\n index,\n total: uniqueFieldIssues.length,\n };\n\n const patch = await promptForField(ctx);\n\n if (patch === null && p.isCancel(patch)) {\n // User cancelled (Ctrl+C)\n const shouldContinue = await p.confirm({\n message: 'Cancel and discard changes?',\n initialValue: false,\n });\n\n if (p.isCancel(shouldContinue) || shouldContinue) {\n return { patches: [], cancelled: true };\n }\n // Continue filling - re-prompt this field\n index--;\n continue;\n }\n\n if (patch) {\n patches.push(patch);\n }\n }\n\n return { patches, cancelled: false };\n}\n\n/**\n * Show intro message for interactive fill session.\n */\nexport function showInteractiveIntro(formTitle: string, role: string, fieldCount: number): void {\n p.intro(pc.bgCyan(pc.black(' Markform Interactive Fill ')));\n\n const lines = [\n `${pc.bold('Form:')} ${formTitle}`,\n `${pc.bold('Role:')} ${role}`,\n `${pc.bold('Fields:')} ${fieldCount} to fill`,\n ];\n\n p.note(lines.join('\\n'), 'Session Info');\n}\n\n/**\n * Show outro message after interactive fill.\n */\nexport function showInteractiveOutro(patchCount: number, cancelled: boolean): void {\n if (cancelled) {\n p.cancel('Interactive fill cancelled.');\n return;\n }\n\n if (patchCount === 0) {\n p.outro(pc.yellow('No changes made.'));\n return;\n }\n\n p.outro(`✓ ${patchCount} field(s) updated.`);\n}\n","/**\n * Patch formatting utilities for CLI display.\n *\n * Shared between fill.ts and examples.ts for consistent logging.\n */\n\nimport type { Patch } from '../../engine/coreTypes.js';\n\n/** Maximum characters for a patch value display before truncation */\nconst PATCH_VALUE_MAX_LENGTH = 1000;\n\n/**\n * Truncate a string to max length with ellipsis if needed.\n */\nfunction truncate(value: string, maxLength: number = PATCH_VALUE_MAX_LENGTH): string {\n if (value.length <= maxLength) {\n return value;\n }\n return value.slice(0, maxLength) + '…';\n}\n\n/**\n * Format a patch value for display with truncation.\n */\nexport function formatPatchValue(patch: Patch): string {\n switch (patch.op) {\n case 'set_string':\n return patch.value ? truncate(`\"${patch.value}\"`) : '(empty)';\n case 'set_number':\n return patch.value !== null ? String(patch.value) : '(empty)';\n case 'set_string_list':\n return patch.value.length > 0 ? truncate(`[${patch.value.join(', ')}]`) : '(empty)';\n case 'set_single_select':\n return patch.value ?? '(none)';\n case 'set_multi_select':\n return patch.value.length > 0 ? truncate(`[${patch.value.join(', ')}]`) : '(none)';\n case 'set_checkboxes':\n return truncate(\n Object.entries(patch.value)\n .map(([k, v]) => `${k}:${v}`)\n .join(', '),\n );\n case 'clear_field':\n return '(cleared)';\n case 'skip_field':\n return patch.reason ? truncate(`(skipped: ${patch.reason})`) : '(skipped)';\n case 'abort_field':\n return patch.reason ? truncate(`(aborted: ${patch.reason})`) : '(aborted)';\n case 'set_url':\n return patch.value ? truncate(`\"${patch.value}\"`) : '(empty)';\n case 'set_url_list':\n return patch.value.length > 0 ? truncate(`[${patch.value.join(', ')}]`) : '(empty)';\n case 'set_date':\n return patch.value ? truncate(`\"${patch.value}\"`) : '(empty)';\n case 'set_year':\n return patch.value !== null ? String(patch.value) : '(empty)';\n case 'set_table': {\n const rowCount = patch.value?.length ?? 0;\n return rowCount > 0 ? truncate(`[${rowCount} rows]`) : '(empty)';\n }\n case 'add_note':\n return truncate(`note: ${patch.text}`);\n case 'remove_note':\n return `(remove note ${patch.noteId})`;\n }\n}\n\n/**\n * Get a short display name for the patch operation type.\n */\nexport function formatPatchType(patch: Patch): string {\n switch (patch.op) {\n case 'set_string':\n return 'string';\n case 'set_number':\n return 'number';\n case 'set_string_list':\n return 'string_list';\n case 'set_single_select':\n return 'select';\n case 'set_multi_select':\n return 'multi_select';\n case 'set_checkboxes':\n return 'checkboxes';\n case 'clear_field':\n return 'clear';\n case 'skip_field':\n return 'skip';\n case 'abort_field':\n return 'abort';\n case 'set_url':\n return 'url';\n case 'set_url_list':\n return 'url_list';\n case 'set_date':\n return 'date';\n case 'set_year':\n return 'year';\n case 'set_table':\n return 'table';\n case 'add_note':\n return 'note';\n case 'remove_note':\n return 'remove_note';\n }\n}\n","/**\n * Fill Logging Callbacks - Create FillCallbacks for unified CLI logging.\n *\n * Provides consistent turn-by-turn logging across all CLI commands that\n * run form-filling (fill, run, examples). API consumers can also use\n * these callbacks or implement their own.\n *\n * Default output (always shown unless --quiet):\n * - Turn numbers with issues list (field IDs + issue types)\n * - Patches per turn (field ID + value)\n * - Completion status\n *\n * Verbose output (--verbose flag):\n * - Token counts per turn\n * - Tool call start/end with timing\n * - Detailed stats and LLM metadata\n */\n\nimport pc from 'picocolors';\n\nimport type { FillCallbacks } from '../../harness/harnessTypes.js';\nimport type { CommandContext } from './cliTypes.js';\nimport type { SpinnerHandle } from './shared.js';\nimport { logInfo, logVerbose } from './shared.js';\nimport { formatTurnIssues } from './formatting.js';\nimport { formatPatchType, formatPatchValue } from './patchFormat.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for creating fill logging callbacks.\n */\nexport interface FillLoggingOptions {\n /** Spinner handle for updating during LLM/tool calls */\n spinner?: SpinnerHandle;\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create FillCallbacks that produce standard CLI logging output.\n *\n * Default output (always shown unless --quiet):\n * - Turn numbers with issues list (field IDs + issue types)\n * - Patches per turn (field ID + value)\n * - Completion status\n *\n * Verbose output (--verbose flag):\n * - Token counts per turn\n * - Tool call start/end with timing\n * - Detailed stats and LLM metadata\n *\n * This is used by fill, run, and examples commands for consistent output.\n *\n * @param ctx - Command context for verbose/quiet flags\n * @param options - Optional spinner for tool progress\n * @returns FillCallbacks with all logging implemented\n *\n * @example\n * ```typescript\n * const callbacks = createFillLoggingCallbacks(ctx, { spinner });\n * const result = await fillForm({\n * form: formMarkdown,\n * model: 'anthropic/claude-sonnet-4-5',\n * enableWebSearch: true,\n * callbacks,\n * });\n * ```\n */\nexport function createFillLoggingCallbacks(\n ctx: CommandContext,\n options: FillLoggingOptions = {},\n): FillCallbacks {\n return {\n // DEFAULT: Always show turn number and issues\n onIssuesIdentified: ({ turnNumber, issues }) => {\n logInfo(ctx, `${pc.bold(`Turn ${turnNumber}:`)} ${formatTurnIssues(issues)}`);\n },\n\n // DEFAULT: Always show patches with field IDs and values\n onPatchesGenerated: ({ patches, stats }) => {\n logInfo(ctx, ` -> ${pc.yellow(String(patches.length))} patch(es):`);\n\n for (const patch of patches) {\n const typeName = formatPatchType(patch);\n const value = formatPatchValue(patch);\n // Some patches (add_note, remove_note) don't have fieldId\n const fieldId =\n 'fieldId' in patch ? patch.fieldId : patch.op === 'add_note' ? patch.ref : '';\n if (fieldId) {\n logInfo(ctx, ` ${pc.cyan(fieldId)} ${pc.dim(`(${typeName})`)} = ${pc.green(value)}`);\n } else {\n logInfo(ctx, ` ${pc.dim(`(${typeName})`)} = ${pc.green(value)}`);\n }\n }\n\n // VERBOSE: Token counts and detailed stats\n if (stats && ctx.verbose) {\n logVerbose(ctx, ` Tokens: in=${stats.inputTokens ?? 0} out=${stats.outputTokens ?? 0}`);\n if (stats.toolCalls && stats.toolCalls.length > 0) {\n const toolSummary = stats.toolCalls.map((t) => `${t.name}(${t.count})`).join(', ');\n logVerbose(ctx, ` Tools: ${toolSummary}`);\n }\n }\n },\n\n // DEFAULT: Show completion status\n onTurnComplete: ({ isComplete }) => {\n if (isComplete) {\n logInfo(ctx, pc.green(` ✓ Complete`));\n }\n },\n\n // VERBOSE: Tool call details (with spinner update for web search)\n onToolStart: ({ name }) => {\n // Web search gets spinner update even without --verbose\n if (name.includes('search')) {\n options.spinner?.message(`Web search...`);\n }\n logVerbose(ctx, ` Tool started: ${name}`);\n },\n\n onToolEnd: ({ name, durationMs, error }) => {\n if (error) {\n logVerbose(ctx, ` Tool ${name} failed: ${error} (${durationMs}ms)`);\n } else {\n logVerbose(ctx, ` Tool ${name} completed (${durationMs}ms)`);\n }\n },\n\n // VERBOSE: LLM call metadata\n onLlmCallStart: ({ model }) => {\n logVerbose(ctx, ` LLM call: ${model}`);\n },\n\n onLlmCallEnd: ({ model, inputTokens, outputTokens }) => {\n logVerbose(ctx, ` LLM response: ${model} (in=${inputTokens} out=${outputTokens})`);\n },\n };\n}\n","/**\n * Run helpers - Pure/testable functions extracted from run command.\n *\n * These functions handle form scanning, metadata loading, and model options,\n * separated from interactive UI code to enable unit testing.\n */\n\nimport { readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport pc from 'picocolors';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { SUGGESTED_LLMS, hasWebSearchSupport } from '../../llms.js';\nimport { getProviderInfo, type ProviderName } from '../../harness/modelResolver.js';\nimport { determineRunMode } from './runMode.js';\nimport { readFile } from './shared.js';\nimport { getExampleOrder } from '../examples/exampleRegistry.js';\nimport type { FormDisplayInfo } from './cliTypes.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface FormEntry extends FormDisplayInfo {\n path: string;\n mtime: Date;\n}\n\nexport interface ModelOption {\n value: string;\n label: string;\n hint?: string;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Scan forms directory for .form.md files.\n */\nexport function scanFormsDirectory(formsDir: string): FormEntry[] {\n const entries: FormEntry[] = [];\n\n try {\n const files = readdirSync(formsDir);\n for (const file of files) {\n if (!file.endsWith('.form.md')) continue;\n\n const fullPath = join(formsDir, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile()) {\n entries.push({\n path: fullPath,\n filename: file,\n mtime: stat.mtime,\n });\n }\n } catch {\n // Skip files we can't stat\n }\n }\n } catch {\n // Directory doesn't exist or can't be read\n }\n\n // Sort by canonical example order, then alphabetically for unknown files\n entries.sort((a, b) => {\n const orderDiff = getExampleOrder(a.filename) - getExampleOrder(b.filename);\n if (orderDiff !== 0) return orderDiff;\n return a.filename.localeCompare(b.filename);\n });\n\n return entries;\n}\n\n/**\n * Load form metadata for menu display.\n */\nexport async function enrichFormEntry(entry: FormEntry): Promise<FormEntry> {\n try {\n const content = await readFile(entry.path);\n const form = parseForm(content);\n const runModeResult = determineRunMode(form);\n\n return {\n ...entry,\n title: form.schema.title,\n description: form.schema.description,\n runMode: runModeResult.success ? runModeResult.runMode : undefined,\n };\n } catch {\n return entry;\n }\n}\n\n/**\n * Build model options for the select prompt.\n */\nexport function buildModelOptions(webSearchOnly: boolean): ModelOption[] {\n const options: ModelOption[] = [];\n\n for (const [provider, models] of Object.entries(SUGGESTED_LLMS)) {\n // Filter for web search support if required\n if (webSearchOnly && !hasWebSearchSupport(provider)) {\n continue;\n }\n\n const info = getProviderInfo(provider as ProviderName);\n const hasKey = !!process.env[info.envVar];\n const keyStatus = hasKey ? pc.green('✓') : '○';\n\n for (const model of models) {\n options.push({\n value: `${provider}/${model}`,\n label: `${provider}/${model}`,\n hint: `${keyStatus} ${info.envVar}`,\n });\n }\n }\n\n options.push({\n value: 'custom',\n label: 'Enter custom model ID...',\n hint: 'provider/model-id format',\n });\n\n return options;\n}\n","/**\n * Run command - Interactive launcher for running forms.\n *\n * Provides a menu-based interface for selecting and running forms\n * from the forms directory. Automatically detects run mode based\n * on frontmatter or field roles.\n *\n * Usage:\n * markform run # Browse forms, select, run\n * markform run movie.form.md # Run specific form directly\n * markform run --limit=50 # Override menu limit\n */\n\nimport { join } from 'node:path';\n\nimport type { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { inspect } from '../../engine/inspect.js';\nimport { applyPatches } from '../../engine/apply.js';\nimport type { ParsedForm } from '../../engine/coreTypes.js';\nimport {\n AGENT_ROLE,\n USER_ROLE,\n MAX_FORMS_IN_MENU,\n DEFAULT_MAX_TURNS,\n DEFAULT_MAX_PATCHES_PER_TURN,\n DEFAULT_MAX_ISSUES_PER_TURN,\n DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN,\n DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN,\n} from '../../settings.js';\nimport { getFormsDir } from '../lib/paths.js';\nimport { determineRunMode, formatRunModeSource } from '../lib/runMode.js';\nimport { exportMultiFormat } from '../lib/exportHelpers.js';\nimport { generateVersionedPathInFormsDir } from '../lib/versioning.js';\nimport {\n runInteractiveFill,\n showInteractiveIntro,\n showInteractiveOutro,\n} from '../lib/interactivePrompts.js';\nimport { formatFormLabel, formatFormHint } from '../lib/formatting.js';\nimport type { ExportResult } from '../lib/cliTypes.js';\nimport { getExampleById, DEFAULT_EXAMPLE_ID } from '../examples/exampleRegistry.js';\nimport {\n ensureFormsDir,\n formatPath,\n getCommandContext,\n logError,\n logInfo,\n logTiming,\n logVerbose,\n readFile,\n type CommandContext,\n} from '../lib/shared.js';\nimport { createFillLoggingCallbacks } from '../lib/fillLogging.js';\nimport { fillForm } from '../../harness/programmaticFill.js';\nimport { scanFormsDirectory, enrichFormEntry, buildModelOptions } from '../lib/runHelpers.js';\n\n/**\n * Prompt user to select a model.\n */\nasync function promptForModel(webSearchRequired: boolean): Promise<string | null> {\n const modelOptions = buildModelOptions(webSearchRequired);\n\n if (webSearchRequired && modelOptions.length === 1) {\n p.log.warn('No web-search-capable providers found. OpenAI, Google, or xAI API key required.');\n }\n\n const message = webSearchRequired\n ? 'Select LLM model (web search required):'\n : 'Select LLM model:';\n\n const selection = await p.select({\n message,\n options: modelOptions,\n });\n\n if (p.isCancel(selection)) {\n return null;\n }\n\n if (selection === 'custom') {\n const customModel = await p.text({\n message: 'Model ID (provider/model-id):',\n placeholder: 'anthropic/claude-sonnet-4-20250514',\n validate: (value) => {\n if (!value?.includes('/')) {\n return 'Format: provider/model-id (e.g., anthropic/claude-sonnet-4-20250514)';\n }\n return undefined;\n },\n });\n\n if (p.isCancel(customModel)) {\n return null;\n }\n\n return customModel;\n }\n\n return selection;\n}\n\n/**\n * Collect user input interactively (without exporting).\n * Returns true if successful, false if cancelled.\n */\nasync function collectUserInput(form: ParsedForm): Promise<boolean> {\n const targetRoles = [USER_ROLE];\n\n // Inspect form to get user-role issues\n const inspectResult = inspect(form, { targetRoles });\n const fieldIssues = inspectResult.issues.filter((i) => i.scope === 'field');\n const uniqueFieldIds = new Set(fieldIssues.map((i) => i.ref));\n\n if (uniqueFieldIds.size === 0) {\n return true; // No user fields to fill\n }\n\n // Show intro\n const formTitle = form.schema.title ?? form.schema.id;\n showInteractiveIntro(formTitle, targetRoles.join(', '), uniqueFieldIds.size);\n\n // Run interactive prompts\n const { patches, cancelled } = await runInteractiveFill(form, inspectResult.issues);\n\n if (cancelled) {\n showInteractiveOutro(0, true);\n return false;\n }\n\n // Apply patches to form (in place)\n if (patches.length > 0) {\n applyPatches(form, patches);\n }\n\n showInteractiveOutro(patches.length, false);\n return true;\n}\n\n/**\n * Run interactive fill workflow.\n * @returns ExportResult with paths to output files, or undefined if cancelled/no fields\n */\nasync function runInteractiveWorkflow(\n form: ParsedForm,\n filePath: string,\n formsDir: string,\n): Promise<ExportResult | undefined> {\n const startTime = Date.now();\n const targetRoles = [USER_ROLE];\n\n // Inspect form to get issues\n const inspectResult = inspect(form, { targetRoles });\n const fieldIssues = inspectResult.issues.filter((i) => i.scope === 'field');\n const uniqueFieldIds = new Set(fieldIssues.map((i) => i.ref));\n\n if (uniqueFieldIds.size === 0) {\n p.log.info('No user-role fields to fill.');\n return undefined;\n }\n\n // Show intro\n const formTitle = form.schema.title ?? form.schema.id;\n showInteractiveIntro(formTitle, targetRoles.join(', '), uniqueFieldIds.size);\n\n // Run interactive prompts\n const { patches, cancelled } = await runInteractiveFill(form, inspectResult.issues);\n\n if (cancelled) {\n showInteractiveOutro(0, true);\n return undefined;\n }\n\n // Apply patches\n if (patches.length > 0) {\n applyPatches(form, patches);\n }\n\n // Export\n await ensureFormsDir(formsDir);\n const outputPath = generateVersionedPathInFormsDir(filePath, formsDir);\n const exportResult = await exportMultiFormat(form, outputPath);\n\n showInteractiveOutro(patches.length, false);\n console.log('');\n p.log.success('Outputs:');\n console.log(` ${formatPath(exportResult.reportPath)} ${pc.dim('(output report)')}`);\n console.log(` ${formatPath(exportResult.yamlPath)} ${pc.dim('(output values)')}`);\n console.log(` ${formatPath(exportResult.formPath)} ${pc.dim('(filled markform source)')}`);\n console.log(` ${formatPath(exportResult.schemaPath)} ${pc.dim('(JSON Schema)')}`);\n\n logTiming(\n { verbose: false, format: 'console', dryRun: false, quiet: false, overwrite: false },\n 'Fill time',\n Date.now() - startTime,\n );\n\n return exportResult;\n}\n\n/**\n * Run agent fill workflow using fillForm with logging callbacks.\n * @returns ExportResult with paths to output files\n */\nasync function runAgentFillWorkflow(\n form: ParsedForm,\n modelId: string,\n formsDir: string,\n filePath: string,\n isResearch: boolean,\n overwrite: boolean,\n ctx: CommandContext,\n): Promise<ExportResult> {\n const startTime = Date.now();\n\n // Config based on mode\n const maxTurns = DEFAULT_MAX_TURNS;\n const maxPatchesPerTurn = isResearch\n ? DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN\n : DEFAULT_MAX_PATCHES_PER_TURN;\n const maxIssuesPerTurn = isResearch\n ? DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN\n : DEFAULT_MAX_ISSUES_PER_TURN;\n\n logVerbose(\n ctx,\n `Config: max_turns=${maxTurns}, max_issues_per_turn=${maxIssuesPerTurn}, max_patches_per_turn=${maxPatchesPerTurn}`,\n );\n\n // Create logging callbacks\n const callbacks = createFillLoggingCallbacks(ctx);\n\n // Run form fill\n const workflowLabel = isResearch ? 'Research' : 'Agent fill';\n p.log.step(pc.bold(`${workflowLabel} in progress...`));\n\n const result = await fillForm({\n form,\n model: modelId,\n maxTurnsTotal: maxTurns,\n maxPatchesPerTurn,\n maxIssuesPerTurn,\n targetRoles: [AGENT_ROLE],\n fillMode: overwrite ? 'overwrite' : 'continue',\n enableWebSearch: isResearch,\n captureWireFormat: false,\n recordFill: false,\n callbacks,\n });\n\n // Check result\n if (result.status.ok) {\n p.log.success(pc.green(`Form completed in ${result.turns} turn(s)`));\n } else if (result.status.reason === 'max_turns') {\n p.log.warn(pc.yellow(`Max turns reached (${maxTurns})`));\n } else {\n throw new Error(result.status.message ?? `Fill failed: ${result.status.reason}`);\n }\n\n // Export\n await ensureFormsDir(formsDir);\n const outputPath = generateVersionedPathInFormsDir(filePath, formsDir);\n const exportResult = await exportMultiFormat(result.form, outputPath);\n\n console.log('');\n p.log.success(`${workflowLabel} complete. Outputs:`);\n console.log(` ${formatPath(exportResult.reportPath)} ${pc.dim('(output report)')}`);\n console.log(` ${formatPath(exportResult.yamlPath)} ${pc.dim('(output values)')}`);\n console.log(` ${formatPath(exportResult.formPath)} ${pc.dim('(filled markform source)')}`);\n console.log(` ${formatPath(exportResult.schemaPath)} ${pc.dim('(JSON Schema)')}`);\n\n logTiming(ctx, isResearch ? 'Research time' : 'Fill time', Date.now() - startTime);\n\n return exportResult;\n}\n\n// =============================================================================\n// Exported Workflow Function\n// =============================================================================\n\n/**\n * Run a form directly (callable from other commands).\n * This executes the same workflow as `markform run <file>`.\n *\n * @param selectedPath - Path to the form file\n * @param formsDir - Directory for output files\n * @param overwrite - Whether to overwrite existing field values\n * @param ctx - Optional command context for logging (defaults to non-verbose/quiet)\n * @returns ExportResult with paths to output files, or undefined if cancelled/no output\n */\nexport async function runForm(\n selectedPath: string,\n formsDir: string,\n overwrite: boolean,\n ctx?: CommandContext,\n): Promise<ExportResult | undefined> {\n // Default context for when called programmatically without CLI context\n const effectiveCtx: CommandContext = ctx ?? {\n verbose: false,\n quiet: false,\n dryRun: false,\n format: 'console',\n overwrite,\n };\n\n const content = await readFile(selectedPath);\n const form = parseForm(content);\n\n const runModeResult = determineRunMode(form);\n if (!runModeResult.success) {\n throw new Error(runModeResult.error);\n }\n\n const { runMode } = runModeResult;\n\n switch (runMode) {\n case 'interactive':\n return runInteractiveWorkflow(form, selectedPath, formsDir);\n\n case 'fill':\n case 'research': {\n const isResearch = runMode === 'research';\n\n // First collect user input if form has user-role fields\n const userInputSuccess = await collectUserInput(form);\n if (!userInputSuccess) {\n p.cancel('Cancelled.');\n return undefined;\n }\n\n // Then prompt for model and run agent fill\n const modelId = await promptForModel(isResearch);\n if (!modelId) {\n p.cancel('Cancelled.');\n return undefined;\n }\n return runAgentFillWorkflow(\n form,\n modelId,\n formsDir,\n selectedPath,\n isResearch,\n overwrite,\n effectiveCtx,\n );\n }\n }\n}\n\n// =============================================================================\n// Command Registration\n// =============================================================================\n\n/**\n * Register the run command.\n */\nexport function registerRunCommand(program: Command): void {\n program\n .command('run [file]')\n .description('Browse and run forms from the forms directory')\n .option(\n '--limit <n>',\n `Maximum forms to show in menu (default: ${MAX_FORMS_IN_MENU})`,\n String(MAX_FORMS_IN_MENU),\n )\n .action(async (file: string | undefined, options: { limit?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const formsDir = getFormsDir(ctx.formsDir);\n const limit = options.limit ? parseInt(options.limit, 10) : MAX_FORMS_IN_MENU;\n let selectedPath: string;\n\n // =====================================================================\n // STEP 1: Select a form\n // =====================================================================\n if (file) {\n // Direct file path provided\n selectedPath = file.startsWith('/') ? file : join(formsDir, file);\n if (!selectedPath.endsWith('.form.md') && !selectedPath.endsWith('.md')) {\n // Try adding extension\n const withExt = `${selectedPath}.form.md`;\n selectedPath = withExt;\n }\n } else {\n // Show menu\n p.intro(pc.bgCyan(pc.black(' markform run ')));\n\n const entries = scanFormsDirectory(formsDir);\n\n if (entries.length === 0) {\n p.log.warn(`No forms found in ${formatPath(formsDir)}`);\n console.log('');\n console.log(`Run ${pc.cyan(\"'markform examples'\")} to get started.`);\n p.outro('');\n return;\n }\n\n // Enrich entries with metadata (limit to menu size)\n const entriesToShow = entries.slice(0, limit);\n const enrichedEntries = await Promise.all(entriesToShow.map(enrichFormEntry));\n\n // Build menu options using shared formatters\n const menuOptions = enrichedEntries.map((entry) => ({\n value: entry.path,\n label: formatFormLabel(entry),\n hint: formatFormHint(entry),\n }));\n\n // Find the default example for initial selection\n const defaultExample = getExampleById(DEFAULT_EXAMPLE_ID);\n const defaultEntry = enrichedEntries.find((e) => e.filename === defaultExample?.filename);\n const initialValue = defaultEntry?.path;\n\n if (entries.length > limit) {\n console.log(pc.dim(`Showing ${limit} of ${entries.length} forms`));\n }\n\n const selection = await p.select({\n message: 'Select a form to run:',\n options: menuOptions,\n initialValue,\n });\n\n if (p.isCancel(selection)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n selectedPath = selection;\n }\n\n // =====================================================================\n // STEP 2: Parse form and determine run mode\n // =====================================================================\n logVerbose(ctx, `Reading form: ${selectedPath}`);\n const content = await readFile(selectedPath);\n const form = parseForm(content);\n\n const runModeResult = determineRunMode(form);\n if (!runModeResult.success) {\n logError(runModeResult.error);\n process.exit(1);\n }\n\n const { runMode, source } = runModeResult;\n logInfo(ctx, `Run mode: ${runMode} (${formatRunModeSource(source)})`);\n\n // =====================================================================\n // STEP 3: Execute workflow based on run mode\n // =====================================================================\n switch (runMode) {\n case 'interactive':\n await runInteractiveWorkflow(form, selectedPath, formsDir);\n break;\n\n case 'fill':\n case 'research': {\n const isResearch = runMode === 'research';\n\n // First collect user input if form has user-role fields\n const userInputSuccess = await collectUserInput(form);\n if (!userInputSuccess) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n\n // Then prompt for model and run agent fill\n const modelId = await promptForModel(isResearch);\n if (!modelId) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n await runAgentFillWorkflow(\n form,\n modelId,\n formsDir,\n selectedPath,\n isResearch,\n ctx.overwrite,\n ctx,\n );\n break;\n }\n }\n\n if (!file) {\n p.outro('Happy form filling!');\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Examples command - Copy bundled example forms to the forms directory.\n *\n * This command provides a simple way to get started with markform by\n * copying bundled example forms to your local forms directory.\n *\n * Usage:\n * markform examples # Copy all bundled examples to ./forms/\n * markform examples --list # List bundled examples (no copy)\n * markform examples --name=foo # Copy specific example only\n */\n\nimport { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { Command } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport {\n EXAMPLE_DEFINITIONS,\n DEFAULT_EXAMPLE_ID,\n getExampleById,\n getExamplePath,\n getExampleOrder,\n loadExampleContent,\n getAllExamplesWithMetadata,\n} from '../examples/exampleRegistry.js';\nimport { getFormsDir } from '../lib/paths.js';\nimport {\n ensureFormsDir,\n formatPath,\n getCommandContext,\n logError,\n readFile,\n writeFile,\n} from '../lib/shared.js';\nimport { formatFormLogLine, formatFormLabel, formatFormHint } from '../lib/formatting.js';\nimport { parseForm } from '../../engine/parse.js';\nimport { determineRunMode } from '../lib/runMode.js';\nimport type { FormDisplayInfo, FormRunMode } from '../lib/cliTypes.js';\nimport { runForm } from './run.js';\nimport { browseOutputFiles } from './browse.js';\n\n/**\n * Print non-interactive list of examples.\n */\nfunction printExamplesList(): void {\n console.log(pc.bold('Available examples:\\n'));\n const examples = getAllExamplesWithMetadata();\n for (const example of examples) {\n const typeLabel = example.type === 'research' ? pc.magenta('[research]') : pc.blue('[fill]');\n console.log(` ${pc.cyan(example.id)} ${typeLabel}`);\n console.log(` ${pc.bold(example.title ?? example.id)}`);\n console.log(` ${example.description ?? 'No description'}`);\n console.log(` Source: ${formatPath(getExamplePath(example.id))}`);\n console.log('');\n }\n}\n\n/**\n * Copy an example form to the forms directory.\n *\n * @returns true if copied, false if skipped\n */\nasync function copyExample(\n exampleId: string,\n formsDir: string,\n overwrite: boolean,\n _quiet: boolean,\n): Promise<{ copied: boolean; skipped: boolean; path: string }> {\n const example = getExampleById(exampleId);\n if (!example) {\n throw new Error(`Unknown example: ${exampleId}`);\n }\n\n const outputPath = join(formsDir, example.filename);\n\n // Check if file exists\n if (existsSync(outputPath)) {\n if (!overwrite) {\n return { copied: false, skipped: true, path: outputPath };\n }\n }\n\n // Load and write the example\n const content = loadExampleContent(exampleId);\n await writeFile(outputPath, content);\n\n return { copied: true, skipped: false, path: outputPath };\n}\n\ninterface FormEntry extends FormDisplayInfo {\n path: string;\n}\n\n/**\n * Scan forms directory and enrich entries with metadata.\n */\nasync function getFormEntries(formsDir: string): Promise<FormEntry[]> {\n const entries: FormEntry[] = [];\n\n try {\n const files = readdirSync(formsDir);\n for (const file of files) {\n if (!file.endsWith('.form.md')) continue;\n\n const fullPath = join(formsDir, file);\n try {\n const stat = statSync(fullPath);\n if (stat.isFile()) {\n // Load metadata\n const content = await readFile(fullPath);\n const form = parseForm(content);\n const runModeResult = determineRunMode(form);\n\n entries.push({\n path: fullPath,\n filename: file,\n title: form.schema.title,\n description: form.schema.description,\n runMode: runModeResult.success ? (runModeResult.runMode as FormRunMode) : undefined,\n });\n }\n } catch {\n // Skip files we can't read\n }\n }\n } catch {\n // Directory doesn't exist or can't be read\n }\n\n return entries;\n}\n\n/**\n * Copy all examples to the forms directory.\n * Returns { copied, skipped } counts for the caller to handle prompts.\n */\nasync function copyAllExamples(\n formsDir: string,\n overwrite: boolean,\n quiet: boolean,\n): Promise<{ copied: number; skipped: number }> {\n const examples = getAllExamplesWithMetadata();\n const total = examples.length;\n\n if (!quiet) {\n console.log(`Copying ${total} example forms to ${formatPath(formsDir)}...`);\n console.log('');\n }\n\n let copied = 0;\n let skipped = 0;\n\n for (const example of examples) {\n const result = await copyExample(example.id, formsDir, overwrite, quiet);\n\n if (result.copied) {\n copied++;\n if (!quiet) {\n console.log(formatFormLogLine(example, ` ${pc.green('✓')}`));\n }\n } else if (result.skipped) {\n skipped++;\n if (!quiet) {\n console.log(\n `${formatFormLogLine(example, ` ${pc.yellow('○')}`)} ${pc.dim('(exists, skipped)')}`,\n );\n }\n }\n }\n\n if (!quiet) {\n console.log('');\n if (skipped > 0) {\n console.log(\n pc.yellow(`Skipped ${skipped} existing file(s). Use --overwrite to replace them.`),\n );\n }\n console.log(pc.green(`Done! Copied ${copied} example form(s) to ${formatPath(formsDir)}`));\n }\n\n return { copied, skipped };\n}\n\n/**\n * Show form selection menu and return the selected path.\n */\nasync function showFormMenu(formsDir: string): Promise<string | null> {\n const entries = await getFormEntries(formsDir);\n\n if (entries.length === 0) {\n return null;\n }\n\n // Sort by canonical order from exampleRegistry\n const sortedEntries = [...entries].sort((a, b) => {\n return getExampleOrder(a.filename) - getExampleOrder(b.filename);\n });\n\n // Find the default example index for initial selection\n const defaultExample = getExampleById(DEFAULT_EXAMPLE_ID);\n const defaultIndex = sortedEntries.findIndex((e) => e.filename === defaultExample?.filename);\n\n const menuOptions = sortedEntries.map((entry) => ({\n value: entry.path,\n label: formatFormLabel(entry),\n hint: formatFormHint(entry),\n }));\n\n // Use the default example's path as initial value\n const defaultEntry = defaultIndex >= 0 ? sortedEntries[defaultIndex] : undefined;\n const initialValue = defaultEntry?.path;\n\n const selection = await p.select({\n message: 'Select a form to run:',\n options: menuOptions,\n initialValue,\n });\n\n if (p.isCancel(selection)) {\n return null;\n }\n\n return selection;\n}\n\n/**\n * Copy a specific example to the forms directory.\n */\nasync function copySingleExample(\n exampleId: string,\n formsDir: string,\n overwrite: boolean,\n quiet: boolean,\n): Promise<void> {\n const example = getExampleById(exampleId);\n if (!example) {\n throw new Error(`Unknown example: ${exampleId}`);\n }\n\n if (!quiet) {\n console.log(`Copying ${example.filename} to ${formatPath(formsDir)}...`);\n }\n\n const result = await copyExample(exampleId, formsDir, overwrite, quiet);\n\n if (result.copied) {\n if (!quiet) {\n console.log(formatFormLogLine(example, ` ${pc.green('✓')}`));\n console.log('');\n console.log(pc.green('Done!'));\n console.log(`Run ${pc.cyan(`'markform run ${example.filename}'`)} to try it.`);\n }\n } else if (result.skipped) {\n if (!quiet) {\n console.log(\n `${formatFormLogLine(example, ` ${pc.yellow('○')}`)} ${pc.dim('(exists, skipped)')}`,\n );\n console.log('');\n console.log(pc.yellow(`File already exists. Use --overwrite to replace it.`));\n }\n }\n}\n\n/**\n * Register the examples command.\n */\nexport function registerExamplesCommand(program: Command): void {\n program\n .command('examples')\n .description('Copy bundled example forms to the forms directory')\n .option('--list', 'List available examples without copying')\n .option('--name <example>', 'Copy specific example by ID')\n .action(async (options: { list?: boolean; name?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n // --list mode: just print examples and exit\n if (options.list) {\n printExamplesList();\n return;\n }\n\n // Ensure forms directory exists\n const formsDir = getFormsDir(ctx.formsDir);\n await ensureFormsDir(formsDir);\n\n // Validate --name if provided\n if (options.name) {\n const example = getExampleById(options.name);\n if (!example) {\n logError(`Unknown example: ${options.name}`);\n console.log('\\nAvailable examples:');\n for (const ex of EXAMPLE_DEFINITIONS) {\n console.log(` ${ex.id}`);\n }\n process.exit(1);\n }\n\n // Copy single example\n await copySingleExample(options.name, formsDir, ctx.overwrite, ctx.quiet);\n } else {\n // Copy all examples\n const { copied, skipped } = await copyAllExamples(formsDir, ctx.overwrite, ctx.quiet);\n\n // Prompt to run a form (if not quiet and forms exist - either copied or already present)\n if (!ctx.quiet && (copied > 0 || skipped > 0)) {\n console.log('');\n const wantToRun = await p.confirm({\n message: 'Do you want to try running a form?',\n initialValue: true,\n });\n\n if (p.isCancel(wantToRun) || !wantToRun) {\n console.log('');\n console.log(`Run ${pc.cyan(\"'markform run'\")} to select and run a form later.`);\n } else {\n // Show form selection menu\n const selectedPath = await showFormMenu(formsDir);\n if (selectedPath) {\n console.log('');\n // Run the selected form directly\n const exportResult = await runForm(selectedPath, formsDir, ctx.overwrite);\n\n // Offer to browse output files if form was completed\n if (exportResult) {\n console.log('');\n const wantToBrowse = await p.confirm({\n message: 'Would you like to view the output files?',\n initialValue: true,\n });\n\n if (!p.isCancel(wantToBrowse) && wantToBrowse) {\n // Get base path by removing extension from form path\n const basePath = exportResult.formPath.replace(/\\.form\\.md$/, '');\n await browseOutputFiles(basePath);\n }\n }\n }\n }\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Export command - Export form as markform or plain markdown or structured data.\n *\n * Default output is markform format (canonical markdown with markdoc directives).\n * With --format=markdown, outputs plain readable markdown without markdoc.\n * With --format=json or --format=yaml, outputs structured data with:\n * - schema: Form structure and field definitions\n * - values: Current field values\n * - markdown: Canonical markdown string\n */\n\nimport type { Command } from 'commander';\n\nimport YAML from 'yaml';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { serializeForm, serializeRawMarkdown } from '../../engine/serialize.js';\nimport type { FieldValue, Id, Note, SyntaxStyle } from '../../engine/coreTypes.js';\nimport { getCommandContext, logError, logVerbose, readFile } from '../lib/shared.js';\n\ninterface ExportField {\n id: string;\n kind: string;\n label: string;\n required: boolean;\n options?: { id: string; label: string }[];\n placeholder?: string;\n examples?: string[];\n}\n\ninterface ExportGroup {\n id: string;\n title?: string;\n children: ExportField[];\n}\n\ninterface ExportSchema {\n id: string;\n title?: string;\n groups: ExportGroup[];\n}\n\ninterface ExportOutput {\n schema: ExportSchema;\n values: Record<Id, FieldValue>;\n notes: Note[];\n markdown: string;\n}\n\n/** Export format options */\ntype ExportFormat = 'markform' | 'markdown' | 'json' | 'yaml';\n\n/**\n * Register the export command.\n */\nexport function registerExportCommand(program: Command): void {\n program\n .command('export <file>')\n .description(\n 'Export form as markform (default), markdown (readable), or json/yaml for structured data',\n )\n .option('--compact', 'Output compact JSON (no formatting, only for JSON format)')\n .option('--normalize', 'Regenerate form without preserving external content')\n .option(\n '--syntax <style>',\n 'Output syntax style: comments (HTML comments) or tags (Markdoc). Default: preserve original.',\n (value: string) => {\n if (value !== 'comments' && value !== 'tags') {\n throw new Error(`Invalid syntax value: ${value}. Must be 'comments' or 'tags'.`);\n }\n return value as SyntaxStyle;\n },\n )\n .action(\n async (\n file: string,\n options: { compact?: boolean; normalize?: boolean; syntax?: SyntaxStyle },\n cmd: Command,\n ) => {\n const ctx = getCommandContext(cmd);\n\n // Determine format: map global format to export format\n // json/yaml from global --format work for export\n // console/plaintext from global map to markform (export's default)\n let format: ExportFormat = 'markform';\n if (ctx.format === 'json') {\n format = 'json';\n } else if (ctx.format === 'yaml') {\n format = 'yaml';\n } else if (ctx.format === 'markdown') {\n format = 'markdown';\n } else if (ctx.format === 'markform') {\n format = 'markform';\n }\n // \"console\" and \"plaintext\" default to \"markform\" for export\n\n try {\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n // For markform format, output canonical markdoc markdown\n if (format === 'markform') {\n console.log(\n serializeForm(form, {\n preserveContent: !options.normalize,\n syntaxStyle: options.syntax,\n }),\n );\n return;\n }\n\n // For markdown format, output plain readable markdown\n if (format === 'markdown') {\n console.log(serializeRawMarkdown(form));\n return;\n }\n\n // For JSON/YAML, build the full structured output\n const schema: ExportSchema = {\n id: form.schema.id,\n title: form.schema.title,\n groups: form.schema.groups.map((group) => ({\n id: group.id,\n title: group.title,\n children: group.children.map((field) => ({\n id: field.id,\n kind: field.kind,\n label: field.label,\n required: field.required,\n ...(field.kind === 'single_select' ||\n field.kind === 'multi_select' ||\n field.kind === 'checkboxes'\n ? {\n options: field.options.map((opt) => ({\n id: opt.id,\n label: opt.label,\n })),\n }\n : {}),\n ...(field.placeholder ? { placeholder: field.placeholder } : {}),\n ...(field.examples && field.examples.length > 0\n ? { examples: field.examples }\n : {}),\n })),\n })),\n };\n\n // Extract values from responses for export\n const values: Record<string, FieldValue> = {};\n for (const [fieldId, response] of Object.entries(form.responsesByFieldId)) {\n if (response.state === 'answered' && response.value) {\n values[fieldId] = response.value;\n }\n }\n\n const output: ExportOutput = {\n schema,\n values,\n notes: form.notes,\n markdown: serializeForm(form, {\n preserveContent: !options.normalize,\n syntaxStyle: options.syntax,\n }),\n };\n\n // Output in JSON or YAML format\n if (format === 'json') {\n if (options.compact) {\n console.log(JSON.stringify(output));\n } else {\n console.log(JSON.stringify(output, null, 2));\n }\n } else {\n // YAML format\n console.log(YAML.stringify(output));\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n },\n );\n}\n","/**\n * CLI Fill Callbacks - Helper to create FillCallbacks for CLI commands.\n *\n * Provides real-time feedback during web search tool execution.\n */\n\nimport type { FillCallbacks } from '../../harness/harnessTypes.js';\nimport type { SpinnerHandle } from './shared.js';\nimport { logVerbose } from './shared.js';\nimport type { CommandContext } from './cliTypes.js';\n\n/**\n * Create FillCallbacks for CLI commands.\n *\n * Provides spinner feedback during tool execution (especially web search).\n * Only implements tool callbacks - turn/LLM callbacks are handled by CLI's\n * own logging which has richer context.\n *\n * @param spinner - Active spinner handle to update\n * @param ctx - Command context for verbose logging\n * @returns FillCallbacks with onToolStart and onToolEnd\n *\n * @example\n * ```typescript\n * const spinner = createSpinner({ type: 'api', provider, model });\n * const callbacks = createCliToolCallbacks(spinner, ctx);\n * const agent = createLiveAgent({ model, callbacks, ... });\n * ```\n */\nexport function createCliToolCallbacks(\n spinner: SpinnerHandle,\n ctx: CommandContext,\n): Pick<FillCallbacks, 'onToolStart' | 'onToolEnd'> {\n return {\n onToolStart: ({ name }) => {\n // Update spinner for web search tools\n if (name.includes('search')) {\n spinner.message(`🔍 Web search...`);\n }\n logVerbose(ctx, ` Tool started: ${name}`);\n },\n\n onToolEnd: ({ name, durationMs, error }) => {\n if (error) {\n logVerbose(ctx, ` Tool ${name} failed: ${error} (${durationMs}ms)`);\n } else {\n logVerbose(ctx, ` Tool ${name} completed (${durationMs}ms)`);\n }\n },\n };\n}\n","/**\n * Fill command - Run an agent to autonomously fill a form.\n *\n * Supports both mock mode (for testing) and live mode (with LLM agent).\n * Records session transcripts for debugging and golden tests.\n */\n\nimport type { Command } from 'commander';\n\nimport { resolve } from 'node:path';\n\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { writeFileSync } from 'node:fs';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { serializeForm } from '../../engine/serialize.js';\nimport { serializeSession } from '../../engine/session.js';\nimport { computeProgressSummary, computeStructureSummary } from '../../engine/summaries.js';\nimport type {\n FillMode,\n HarnessConfig,\n MockMode,\n ParsedForm,\n PatchRejection,\n SessionFinal,\n SessionTranscript,\n SessionTurnContext,\n SessionTurnStats,\n WireFormat,\n} from '../../engine/coreTypes.js';\nimport type { TurnProgress } from '../../harness/harnessTypes.js';\nimport { FillRecordCollector } from '../../harness/fillRecordCollector.js';\nimport { stripUnstableFillRecordFields } from '../../harness/fillRecord.js';\nimport { formatFillRecordSummary } from '../../harness/formatFillRecordSummary.js';\nimport { createHarness } from '../../harness/harness.js';\nimport { resolveHarnessConfig } from '../../harness/harnessConfigResolver.js';\nimport { createLiveAgent, buildMockWireFormat } from '../../harness/liveAgent.js';\nimport { createMockAgent } from '../../harness/mockAgent.js';\nimport { fillForm } from '../../harness/programmaticFill.js';\nimport {\n DEFAULT_MAX_ISSUES_PER_TURN,\n DEFAULT_MAX_PATCHES_PER_TURN,\n DEFAULT_MAX_TURNS,\n AGENT_ROLE,\n USER_ROLE,\n parseRolesFlag,\n deriveFillRecordPath,\n} from '../../settings.js';\nimport { getFormsDir } from '../lib/paths.js';\nimport { formatSuggestedLlms } from '../../llms.js';\nimport type { Agent } from '../../harness/mockAgent.js';\nimport { resolveModel } from '../../harness/modelResolver.js';\nimport {\n createSpinner,\n ensureFormsDir,\n formatOutput,\n formatPath,\n getCommandContext,\n logError,\n logInfo,\n logSuccess,\n logTiming,\n logVerbose,\n logWarn,\n readFile,\n writeFile,\n type SpinnerHandle,\n} from '../lib/shared.js';\nimport { exportMultiFormat } from '../lib/exportHelpers.js';\nimport { generateVersionedPathInFormsDir } from '../lib/versioning.js';\nimport {\n runInteractiveFill,\n showInteractiveIntro,\n showInteractiveOutro,\n} from '../lib/interactivePrompts.js';\nimport { formatPatchValue, formatPatchType } from '../lib/patchFormat.js';\nimport { formatTurnIssues } from '../lib/formatting.js';\nimport { inspect } from '../../engine/inspect.js';\nimport { applyPatches } from '../../engine/apply.js';\nimport { createCliToolCallbacks } from '../lib/fillCallbacks.js';\n\n/**\n * Format session transcript for console output.\n */\nfunction formatConsoleSession(transcript: SessionTranscript, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n const green = useColors ? pc.green : (s: string) => s;\n const yellow = useColors ? pc.yellow : (s: string) => s;\n\n // Header\n lines.push(bold(cyan('Session Transcript')));\n lines.push('');\n\n // Session info\n lines.push(`${bold('Form:')} ${transcript.form.path}`);\n lines.push(`${bold('Mode:')} ${transcript.mode}`);\n lines.push(`${bold('Version:')} ${transcript.sessionVersion}`);\n lines.push('');\n\n // Harness config\n lines.push(bold('Harness Config:'));\n lines.push(` Max turns: ${transcript.harness.maxTurns}`);\n lines.push(` Max patches/turn: ${transcript.harness.maxPatchesPerTurn}`);\n lines.push(` Max issues/turn: ${transcript.harness.maxIssuesPerTurn}`);\n lines.push('');\n\n // Turns summary\n lines.push(bold(`Turns (${transcript.turns.length}):`));\n for (const turn of transcript.turns) {\n const issueCount = turn.inspect.issues.length;\n const patchCount = turn.apply.patches.length;\n const afterIssues = turn.after.requiredIssueCount;\n\n lines.push(\n ` Turn ${turn.turn}: ${dim(`${issueCount} issues`)} → ${yellow(`${patchCount} patches`)} → ${afterIssues === 0 ? green('0 remaining') : dim(`${afterIssues} remaining`)}`,\n );\n }\n lines.push('');\n\n // Final result\n const expectText = transcript.final.expectComplete ? green('✓ complete') : yellow('○ incomplete');\n lines.push(`${bold('Expected:')} ${expectText}`);\n lines.push(`${bold('Completed form:')} ${transcript.final.expectedCompletedForm}`);\n\n return lines.join('\\n');\n}\n\n/**\n * Register the fill command.\n */\nexport function registerFillCommand(program: Command): void {\n program\n .command('fill <file>')\n .description('Run an agent to autonomously fill a form')\n .option('--mock', 'Use mock agent (requires --mock-source)')\n .option(\n '--model <id>',\n 'Model ID for live agent (format: provider/model-id, e.g. openai/gpt-5-mini)',\n )\n .option('--mock-source <file>', 'Path to completed form for mock agent')\n .option('--record <file>', 'Record session transcript to file')\n .option(\n '--max-turns <n>',\n `Maximum turns (default: ${DEFAULT_MAX_TURNS})`,\n String(DEFAULT_MAX_TURNS),\n )\n .option(\n '--max-patches <n>',\n `Maximum patches per turn (default: ${DEFAULT_MAX_PATCHES_PER_TURN})`,\n String(DEFAULT_MAX_PATCHES_PER_TURN),\n )\n .option(\n '--max-issues <n>',\n `Maximum issues shown per turn (default: ${DEFAULT_MAX_ISSUES_PER_TURN})`,\n String(DEFAULT_MAX_ISSUES_PER_TURN),\n )\n .option('--max-fields <n>', 'Maximum unique fields per turn (applied before --max-issues)')\n .option('--max-groups <n>', 'Maximum unique groups per turn (applied before --max-issues)')\n .option(\n '--roles <roles>',\n \"Target roles to fill (comma-separated, or '*' for all; default: 'agent', or 'user' in --interactive mode)\",\n )\n .option(\n '--mode <mode>',\n 'Fill mode: continue (skip filled fields) or overwrite (re-fill; default: continue)',\n )\n .option('-o, --output <file>', 'Write final form to file')\n .option('--prompt <file>', 'Path to custom system prompt file (appends to default)')\n .option(\n '--instructions <text>',\n 'Inline system prompt (appends to default; takes precedence over --prompt)',\n )\n .option(\n '-i, --interactive',\n 'Interactive mode: prompt user for field values (defaults to user role)',\n )\n .option('--normalize', 'Regenerate form without preserving external content')\n .option('--record-fill', 'Write fill record to sidecar .fill.json file')\n .option(\n '--record-fill-stable',\n 'Write fill record without timestamps/durations (for golden tests)',\n )\n .option('--parallel', 'Enable parallel execution for forms with parallel batches')\n .action(\n async (\n file: string,\n options: {\n mock?: boolean;\n model?: string;\n mockSource?: string;\n record?: string;\n maxTurns?: string;\n maxPatches?: string;\n maxIssues?: string;\n maxFields?: string;\n maxGroups?: string;\n roles?: string;\n mode?: string;\n output?: string;\n prompt?: string;\n instructions?: string;\n interactive?: boolean;\n normalize?: boolean;\n recordFill?: boolean;\n recordFillStable?: boolean;\n parallel?: boolean;\n },\n cmd: Command,\n ) => {\n const ctx = getCommandContext(cmd);\n const filePath = resolve(file);\n\n // Declare variables that may be needed in error handler\n // These are accessible in catch block for partial fill record writing\n let harness: ReturnType<typeof createHarness> | undefined;\n let collector: FillRecordCollector | undefined;\n let targetRoles: string[] = [];\n let form: ParsedForm | undefined;\n\n try {\n const startTime = Date.now();\n\n // Parse and validate --roles (default depends on mode)\n if (options.roles) {\n try {\n targetRoles = parseRolesFlag(options.roles);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(`Invalid --roles: ${message}`);\n process.exit(1);\n }\n } else {\n // Default: user role for interactive, agent role for agent mode\n targetRoles = options.interactive ? [USER_ROLE] : [AGENT_ROLE];\n }\n\n // Parse and validate --mode\n let fillMode: FillMode = 'continue'; // Default\n if (options.mode) {\n if (options.mode !== 'continue' && options.mode !== 'overwrite') {\n logError(`Invalid --mode: ${options.mode}. Valid modes: continue, overwrite`);\n process.exit(1);\n }\n fillMode = options.mode;\n }\n\n logVerbose(ctx, `Reading form: ${filePath}`);\n const formContent = await readFile(filePath);\n\n logVerbose(ctx, 'Parsing form...');\n form = parseForm(formContent);\n\n // =====================================================================\n // INTERACTIVE MODE\n // =====================================================================\n if (options.interactive) {\n // Validate: --interactive conflicts with mock mode\n if (options.mock) {\n logError('--interactive cannot be used with --mock');\n process.exit(1);\n }\n if (options.model) {\n logError('--interactive cannot be used with --model');\n process.exit(1);\n }\n if (options.mockSource) {\n logError('--interactive cannot be used with --mock-source');\n process.exit(1);\n }\n\n // Inspect form to get issues for target roles\n const inspectResult = inspect(form, { targetRoles });\n\n // Show intro\n const formTitle = form.schema.title ?? form.schema.id;\n const fieldIssues = inspectResult.issues.filter((i) => i.scope === 'field');\n const uniqueFieldIds = new Set(fieldIssues.map((i) => i.ref));\n showInteractiveIntro(formTitle, targetRoles.join(', '), uniqueFieldIds.size);\n\n // Run interactive prompts\n const { patches, cancelled } = await runInteractiveFill(form, inspectResult.issues);\n\n if (cancelled) {\n showInteractiveOutro(0, true);\n process.exit(1);\n }\n\n // Apply patches to form (mutates form in place)\n if (patches.length > 0) {\n applyPatches(form, patches);\n }\n\n const durationMs = Date.now() - startTime;\n\n // Write output files (all formats)\n // Default to forms directory when --output is not specified\n let outputPath: string;\n if (options.output) {\n outputPath = resolve(options.output);\n } else {\n const formsDir = getFormsDir(ctx.formsDir);\n await ensureFormsDir(formsDir);\n outputPath = generateVersionedPathInFormsDir(filePath, formsDir);\n }\n\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would write form to: ${outputPath}`);\n showInteractiveOutro(patches.length, false);\n } else {\n // Export all formats (report, yaml, form, schema)\n const { reportPath, yamlPath, formPath, schemaPath } = await exportMultiFormat(\n form,\n outputPath,\n );\n\n showInteractiveOutro(patches.length, false);\n console.log('');\n p.log.success('Outputs:');\n console.log(` ${formatPath(reportPath)} ${pc.dim('(output report)')}`);\n console.log(` ${formatPath(yamlPath)} ${pc.dim('(output values)')}`);\n console.log(` ${formatPath(formPath)} ${pc.dim('(filled markform source)')}`);\n console.log(` ${formatPath(schemaPath)} ${pc.dim('(JSON Schema)')}`);\n }\n\n logTiming(ctx, 'Fill time', durationMs);\n\n // Show next step hint\n if (patches.length > 0) {\n console.log('');\n console.log('Next step: fill remaining fields with agent');\n console.log(` markform fill ${formatPath(outputPath)} --model=<provider/model>`);\n }\n\n process.exit(0);\n }\n\n // =====================================================================\n // AGENT MODE (mock or live)\n // =====================================================================\n\n // Validate options based on mode\n if (options.mock && !options.mockSource) {\n logError('--mock requires --mock-source <file>');\n process.exit(1);\n }\n\n if (!options.mock && !options.model) {\n logError('Live agent requires --model <provider/model-id>');\n console.log('');\n console.log(formatSuggestedLlms());\n process.exit(1);\n }\n\n // Warn about --roles=* in non-interactive mode\n if (targetRoles.includes('*')) {\n logWarn(ctx, 'Warning: Filling all roles including user-designated fields');\n }\n\n // =====================================================================\n // PARALLEL EXECUTION PATH (uses programmatic fillForm API)\n // =====================================================================\n if (options.parallel && !options.mock) {\n logInfo(ctx, pc.cyan(`Filling form (parallel): ${filePath}`));\n logInfo(ctx, `Agent: live (${options.model})`);\n\n // Determine system prompt\n let systemPrompt: string | undefined;\n if (options.instructions) {\n systemPrompt = options.instructions;\n } else if (options.prompt) {\n const promptPath = resolve(options.prompt);\n systemPrompt = await readFile(promptPath);\n }\n\n // Determine output path\n let outputPath: string;\n if (options.output) {\n outputPath = resolve(options.output);\n } else {\n const formsDir = getFormsDir(ctx.formsDir);\n await ensureFormsDir(formsDir);\n outputPath = generateVersionedPathInFormsDir(filePath, formsDir);\n }\n\n // Run programmatic fill with parallel enabled\n const result = await fillForm({\n form,\n model: options.model!,\n enableParallel: true,\n enableWebSearch: true,\n captureWireFormat: false,\n recordFill: true,\n targetRoles,\n fillMode,\n maxTurnsTotal: options.maxTurns ? parseInt(options.maxTurns, 10) : undefined,\n maxPatchesPerTurn: options.maxPatches ? parseInt(options.maxPatches, 10) : undefined,\n maxIssuesPerTurn: options.maxIssues ? parseInt(options.maxIssues, 10) : undefined,\n systemPromptAddition: systemPrompt,\n callbacks: {\n onTurnStart: ({ turnNumber, executionId }) => {\n logInfo(\n ctx,\n `${pc.bold(`Turn ${turnNumber}:`)} started (${pc.dim(executionId)})`,\n );\n },\n onTurnComplete: (progress) => {\n const patchText = progress.patchesApplied === 1 ? 'patch' : 'patches';\n logInfo(\n ctx,\n ` → ${pc.yellow(String(progress.patchesApplied))} ${patchText} applied`,\n );\n if (progress.isComplete) {\n logInfo(ctx, pc.green(` ✓ Complete`));\n }\n },\n onBatchStart: ({ batchId, itemCount }) => {\n logInfo(ctx, pc.cyan(`Starting batch \"${batchId}\" with ${itemCount} items`));\n },\n onBatchComplete: ({ batchId, patchesApplied }) => {\n logInfo(ctx, pc.cyan(`Batch \"${batchId}\" completed: ${patchesApplied} patches`));\n },\n },\n });\n\n const durationMs = Date.now() - startTime;\n\n // Check if completed\n if (result.status.ok) {\n logSuccess(ctx, `Form completed in ${result.turns} turn(s)`);\n } else {\n logWarn(ctx, `Fill incomplete: ${result.status.reason}`);\n }\n\n logTiming(ctx, 'Fill time', durationMs);\n\n // Write output\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would write form to: ${outputPath}`);\n } else {\n await writeFile(outputPath, result.markdown);\n logSuccess(ctx, `Form written to: ${outputPath}`);\n }\n\n // Print fill record summary\n if (result.record && !ctx.quiet) {\n console.log('');\n const summary = formatFillRecordSummary(result.record, { verbose: ctx.verbose });\n console.error(summary);\n }\n\n // Write fill record sidecar\n if ((options.recordFill || options.recordFillStable) && result.record) {\n const sidecarPath = deriveFillRecordPath(outputPath);\n const recordToWrite = options.recordFillStable\n ? stripUnstableFillRecordFields(result.record)\n : result.record;\n\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would write fill record to: ${sidecarPath}`);\n } else {\n writeFileSync(sidecarPath, JSON.stringify(recordToWrite, null, 2));\n logSuccess(ctx, `Fill record written to: ${sidecarPath}`);\n }\n }\n\n process.exit(result.status.ok ? 0 : 1);\n }\n\n // =====================================================================\n // SERIAL EXECUTION PATH (original manual harness loop)\n // =====================================================================\n\n // Parse harness config using resolver (handles frontmatter defaults)\n const cliOptions = {\n maxTurns: options.maxTurns ? parseInt(options.maxTurns, 10) : undefined,\n maxPatchesPerTurn: options.maxPatches ? parseInt(options.maxPatches, 10) : undefined,\n maxIssuesPerTurn: options.maxIssues ? parseInt(options.maxIssues, 10) : undefined,\n maxFieldsPerTurn: options.maxFields ? parseInt(options.maxFields, 10) : undefined,\n maxGroupsPerTurn: options.maxGroups ? parseInt(options.maxGroups, 10) : undefined,\n targetRoles,\n fillMode,\n };\n const harnessConfig = resolveHarnessConfig(form, cliOptions);\n\n // Create harness\n harness = createHarness(form, harnessConfig);\n\n // Note: collector is declared in outer scope for error handler access\n\n // Create agent based on type\n let agent: Agent;\n let mockPath: string | undefined;\n let agentProvider: string | undefined;\n let agentModelName: string | undefined;\n let targetRole: string = AGENT_ROLE; // Track for mock wire format\n\n // Mutable spinner reference for tool callbacks (updated each turn)\n // Using explicit type to avoid narrowing issues in closures\n let currentSpinner = null as SpinnerHandle | null;\n\n if (options.mock) {\n // Mock agent requires a completed form as source\n mockPath = resolve(options.mockSource!);\n logVerbose(ctx, `Reading mock source: ${mockPath}`);\n const mockContent = await readFile(mockPath);\n const mockForm = parseForm(mockContent);\n agent = createMockAgent(mockForm);\n\n // Always create collector for summary output\n const structureSummary = computeStructureSummary(form.schema);\n collector = new FillRecordCollector({\n form: {\n id: form.schema.id,\n title: form.schema.title,\n description: form.schema.description,\n structure: structureSummary,\n },\n provider: 'mock',\n model: 'mock',\n parallelEnabled: false,\n });\n } else {\n // Live agent uses LLM (model is required, validated above)\n const modelIdString = options.model!;\n logVerbose(ctx, `Resolving model: ${modelIdString}`);\n const { model, provider, modelId } = await resolveModel(modelIdString);\n\n // Store provider and model name for spinner display\n agentProvider = provider;\n agentModelName = modelId;\n\n // Always create collector for summary output\n const structureSummary = computeStructureSummary(form.schema);\n collector = new FillRecordCollector({\n form: {\n id: form.schema.id,\n title: form.schema.title,\n description: form.schema.description,\n structure: structureSummary,\n },\n provider,\n model: modelIdString,\n parallelEnabled: false,\n });\n\n // Determine system prompt: --instructions > --prompt > default\n let systemPrompt: string | undefined;\n if (options.instructions) {\n systemPrompt = options.instructions;\n logVerbose(ctx, 'Using inline system prompt from --instructions');\n } else if (options.prompt) {\n const promptPath = resolve(options.prompt);\n logVerbose(ctx, `Reading system prompt from: ${promptPath}`);\n systemPrompt = await readFile(promptPath);\n }\n\n // Create callbacks that reference the mutable spinner\n // Callbacks update spinner during tool execution (especially web search)\n const cliCallbacks = createCliToolCallbacks(\n {\n // Proxy to current spinner (may be null between turns)\n message: (msg) => currentSpinner?.message(msg),\n update: (context) => currentSpinner?.update(context),\n stop: (msg) => currentSpinner?.stop(msg),\n error: (msg) => currentSpinner?.error(msg),\n getElapsedMs: () => currentSpinner?.getElapsedMs() ?? 0,\n },\n ctx,\n );\n\n // Merge CLI callbacks with collector callbacks\n // Collector is always defined at this point (created above)\n const liveCollector = collector;\n const callbacks = {\n onTurnStart: (turn: {\n turnNumber: number;\n issuesCount: number;\n order?: number;\n executionId?: string;\n }) => {\n liveCollector.onTurnStart({\n turnNumber: turn.turnNumber,\n issuesCount: turn.issuesCount,\n order: turn.order ?? 0,\n executionId: turn.executionId ?? 'eid:serial:o0',\n });\n },\n onTurnComplete: (progress: TurnProgress) => {\n liveCollector.onTurnComplete(progress);\n },\n onToolStart: (call: { name: string; input: unknown; executionId: string }) => {\n cliCallbacks.onToolStart?.(call);\n liveCollector.onToolStart(call);\n },\n onToolEnd: (call: {\n name: string;\n output: unknown;\n durationMs: number;\n error?: string;\n executionId: string;\n }) => {\n cliCallbacks.onToolEnd?.(call);\n liveCollector.onToolEnd(call);\n },\n onLlmCallStart: (call: { model: string; executionId: string }) => {\n liveCollector.onLlmCallStart(call);\n },\n onLlmCallEnd: (call: {\n model: string;\n inputTokens: number;\n outputTokens: number;\n executionId: string;\n }) => {\n liveCollector.onLlmCallEnd(call);\n },\n onWebSearch: (info: {\n query: string;\n resultCount: number;\n provider: string;\n executionId: string;\n }) => {\n liveCollector.onWebSearch(info);\n },\n };\n\n // Pass first target role to agent (for instruction lookup)\n targetRole = targetRoles[0] === '*' ? AGENT_ROLE : (targetRoles[0] ?? AGENT_ROLE);\n\n const liveAgent = createLiveAgent({\n model,\n provider,\n systemPromptAddition: systemPrompt,\n targetRole,\n enableWebSearch: true,\n callbacks,\n });\n agent = liveAgent;\n\n // Log available tools\n const toolNames = liveAgent.getAvailableToolNames();\n logInfo(ctx, `Available tools: ${toolNames.join(', ')}`);\n logVerbose(ctx, `Using live agent with model: ${modelId}`);\n }\n\n logInfo(ctx, pc.cyan(`Filling form: ${filePath}`));\n logInfo(\n ctx,\n `Agent: ${options.mock ? 'mock' : 'live'}${options.model ? ` (${options.model})` : ''}`,\n );\n logVerbose(ctx, `Max turns: ${harnessConfig.maxTurns}`);\n logVerbose(ctx, `Max patches per turn: ${harnessConfig.maxPatchesPerTurn}`);\n logVerbose(ctx, `Max issues per turn: ${harnessConfig.maxIssuesPerTurn}`);\n logVerbose(\n ctx,\n `Target roles: ${targetRoles.includes('*') ? '*' : targetRoles.join(', ')}`,\n );\n logVerbose(ctx, `Fill mode: ${fillMode}`);\n\n // Run harness loop\n let stepResult = harness.step();\n // Track rejections for wire format context (helps LLM learn from mistakes)\n let previousRejections: PatchRejection[] | undefined;\n logInfo(\n ctx,\n `${pc.bold(`Turn ${stepResult.turnNumber}:`)} ${formatTurnIssues(stepResult.issues)}`,\n );\n\n // Record first turn start for FillRecord (fixes mf-mgxo: empty timeline bug)\n collector.onTurnStart({\n turnNumber: stepResult.turnNumber,\n issuesCount: stepResult.issues.length,\n order: 0,\n executionId: 'eid:serial:o0',\n });\n\n while (!stepResult.isComplete && !harness.hasReachedMaxTurns()) {\n // Create spinner for LLM call (only for live agent with TTY)\n let spinner: SpinnerHandle | null = null;\n if (\n !options.mock &&\n agentProvider &&\n agentModelName &&\n process.stdout.isTTY &&\n !ctx.quiet\n ) {\n spinner = createSpinner({\n type: 'api',\n provider: agentProvider,\n model: agentModelName,\n turnNumber: stepResult.turnNumber,\n });\n // Set mutable reference so tool callbacks can update spinner\n currentSpinner = spinner;\n }\n\n // Generate patches from agent\n let response;\n try {\n response = await agent.fillFormTool(\n stepResult.issues,\n harness.getForm(),\n harnessConfig.maxPatchesPerTurn,\n );\n spinner?.stop();\n currentSpinner = null; // Clear reference after spinner stops\n } catch (error) {\n spinner?.error('LLM call failed');\n currentSpinner = null; // Clear reference on error\n throw error;\n }\n const { patches, stats } = response;\n\n // Log patches with field id, type, and value (truncated)\n const tokenSuffix = stats\n ? ` ${pc.dim(`(tokens: ↓${stats.inputTokens ?? 0} ↑${stats.outputTokens ?? 0})`)}`\n : '';\n logInfo(ctx, ` → ${pc.yellow(String(patches.length))} patches${tokenSuffix}:`);\n for (const patch of patches) {\n const typeName = formatPatchType(patch);\n const value = formatPatchValue(patch);\n // Some patches (add_note, remove_note) don't have fieldId\n const fieldId =\n 'fieldId' in patch ? patch.fieldId : patch.op === 'add_note' ? patch.ref : '';\n if (fieldId) {\n logInfo(\n ctx,\n ` ${pc.cyan(fieldId)} ${pc.dim(`(${typeName})`)} = ${pc.green(value)}`,\n );\n } else {\n logInfo(ctx, ` ${pc.dim(`(${typeName})`)} = ${pc.green(value)}`);\n }\n }\n\n // Log stats and prompts in verbose mode\n if (stats) {\n logVerbose(\n ctx,\n ` Stats: tokens ↓${stats.inputTokens ?? 0} ↑${stats.outputTokens ?? 0}`,\n );\n if (stats.toolCalls && stats.toolCalls.length > 0) {\n const toolSummary = stats.toolCalls.map((t) => `${t.name}(${t.count})`).join(', ');\n logVerbose(ctx, ` Tools: ${toolSummary}`);\n }\n\n // Log full prompts in verbose mode\n if (stats.prompts) {\n logVerbose(ctx, ``);\n logVerbose(ctx, pc.dim(` ─── System Prompt ───`));\n for (const line of stats.prompts.system.split('\\n')) {\n logVerbose(ctx, pc.dim(` ${line}`));\n }\n logVerbose(ctx, ``);\n logVerbose(ctx, pc.dim(` ─── Context Prompt ───`));\n for (const line of stats.prompts.context.split('\\n')) {\n logVerbose(ctx, pc.dim(` ${line}`));\n }\n logVerbose(ctx, ``);\n }\n }\n\n // Convert TurnStats to SessionTurnStats for session logging\n let llmStats: SessionTurnStats | undefined;\n let context: SessionTurnContext | undefined;\n let wire: WireFormat | undefined;\n\n if (stats) {\n // Live agent - use stats from LLM call\n llmStats = {\n inputTokens: stats.inputTokens,\n outputTokens: stats.outputTokens,\n toolCalls:\n stats.toolCalls && stats.toolCalls.length > 0 ? stats.toolCalls : undefined,\n };\n // Get context and wire from live agent stats\n if (stats.prompts) {\n context = {\n systemPrompt: stats.prompts.system,\n contextPrompt: stats.prompts.context,\n };\n }\n wire = stats.wire;\n } else if (options.mock) {\n // Mock agent - build wire format for session logging\n wire = buildMockWireFormat(\n harness.getForm(),\n stepResult.issues,\n patches,\n harnessConfig.maxPatchesPerTurn,\n targetRole,\n previousRejections,\n );\n // Extract context from wire for convenience\n context = {\n systemPrompt: wire.request.system,\n contextPrompt: wire.request.prompt,\n };\n }\n\n // Apply patches (with wire format for comprehensive session logging)\n const prevTurnNumber = stepResult.turnNumber;\n const prevIssuesShown = stepResult.issues.length;\n stepResult = harness.apply(patches, stepResult.issues, llmStats, context, wire);\n\n // Record turn completion for FillRecord (fixes mf-mgxo: empty timeline bug)\n const rejectedPatches = stepResult.rejectedPatches ?? [];\n collector.onTurnComplete({\n turnNumber: prevTurnNumber,\n issuesShown: prevIssuesShown,\n patchesApplied: patches.length - rejectedPatches.length,\n requiredIssuesRemaining: stepResult.issues.filter((i) => i.severity === 'required')\n .length,\n isComplete: stepResult.isComplete,\n rejectedPatches,\n issues: stepResult.issues,\n patches,\n });\n\n // Track rejections for next turn's wire format context\n previousRejections = stepResult.rejectedPatches;\n\n if (stepResult.isComplete) {\n logInfo(ctx, pc.green(` ✓ Complete`));\n } else if (!harness.hasReachedMaxTurns()) {\n // Step for next turn (only if not at max turns)\n stepResult = harness.step();\n logInfo(\n ctx,\n `${pc.bold(`Turn ${stepResult.turnNumber}:`)} ${formatTurnIssues(stepResult.issues)}`,\n );\n\n // Record next turn start for FillRecord\n collector.onTurnStart({\n turnNumber: stepResult.turnNumber,\n issuesCount: stepResult.issues.length,\n order: 0,\n executionId: 'eid:serial:o0',\n });\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n // Check if completed\n if (stepResult.isComplete) {\n logSuccess(ctx, `Form completed in ${harness.getTurnNumber()} turn(s)`);\n } else if (harness.hasReachedMaxTurns()) {\n logWarn(ctx, `Max turns reached (${harnessConfig.maxTurns})`);\n }\n\n logTiming(ctx, 'Fill time', durationMs);\n\n // Write output file\n // Default to forms directory when --output is not specified\n let outputPath: string;\n if (options.output) {\n outputPath = resolve(options.output);\n } else {\n const formsDir = getFormsDir(ctx.formsDir);\n await ensureFormsDir(formsDir);\n outputPath = generateVersionedPathInFormsDir(filePath, formsDir);\n }\n const formMarkdown = serializeForm(harness.getForm(), {\n preserveContent: !options.normalize,\n });\n\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would write form to: ${outputPath}`);\n } else {\n await writeFile(outputPath, formMarkdown);\n logSuccess(ctx, `Form written to: ${outputPath}`);\n }\n\n // Always compute FillRecord for summary output\n // Get final form progress\n const finalInspect = inspect(harness.getForm(), { targetRoles });\n const progressSummary = computeProgressSummary(\n form.schema,\n harness.getForm().responsesByFieldId,\n harness.getForm().notes,\n finalInspect.issues,\n );\n\n // Set status and get record\n collector.setStatus(\n stepResult.isComplete ? 'completed' : 'partial',\n stepResult.isComplete ? undefined : 'max_turns',\n );\n const fillRecord = collector.getRecord(progressSummary.counts);\n\n // Print summary to stderr (unless quiet)\n if (!ctx.quiet) {\n console.log('');\n const summary = formatFillRecordSummary(fillRecord, { verbose: ctx.verbose });\n console.error(summary);\n }\n\n // Write FillRecord sidecar file if recordFill or recordFillStable is enabled\n if (options.recordFill || options.recordFillStable) {\n const sidecarPath = deriveFillRecordPath(outputPath);\n\n // Strip unstable fields for golden tests\n const recordToWrite = options.recordFillStable\n ? stripUnstableFillRecordFields(fillRecord)\n : fillRecord;\n\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would write fill record to: ${sidecarPath}`);\n } else {\n writeFileSync(sidecarPath, JSON.stringify(recordToWrite, null, 2));\n logSuccess(ctx, `Fill record written to: ${sidecarPath}`);\n }\n }\n\n // Build session transcript\n const transcript = buildSessionTranscript(\n filePath,\n options.mock ? 'mock' : 'live',\n mockPath,\n options.model,\n harnessConfig,\n harness.getTurns(),\n stepResult.isComplete,\n outputPath,\n );\n\n // Output or record session\n if (options.record) {\n const recordPath = resolve(options.record);\n // Always use YAML for recorded files (standard format)\n const yaml = serializeSession(transcript);\n\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would write session to: ${recordPath}`);\n console.log(yaml);\n } else {\n await writeFile(recordPath, yaml);\n logSuccess(ctx, `Session recorded to: ${recordPath}`);\n }\n } else if (!ctx.quiet) {\n // Output to stdout in requested format (unless quiet)\n const output = formatOutput(ctx, transcript, (data, useColors) =>\n formatConsoleSession(data as SessionTranscript, useColors),\n );\n console.log(output);\n }\n\n process.exit(stepResult.isComplete ? 0 : 1);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n\n // Write partial fill record if available (helps with debugging failures)\n if (\n (options.recordFill || options.recordFillStable) &&\n collector &&\n harness &&\n form &&\n options.output\n ) {\n try {\n // Get current form state and compute progress\n const currentForm = harness.getForm();\n const finalInspect = inspect(currentForm, { targetRoles });\n const progressSummary = computeProgressSummary(\n form.schema,\n currentForm.responsesByFieldId,\n currentForm.notes,\n finalInspect.issues,\n );\n\n // Set failed status with error message\n collector.setStatus('failed', message);\n const fillRecord = collector.getRecord(progressSummary.counts);\n\n // Write sidecar file\n const outputPath = resolve(options.output);\n const sidecarPath = deriveFillRecordPath(outputPath);\n const recordToWrite = options.recordFillStable\n ? stripUnstableFillRecordFields(fillRecord)\n : fillRecord;\n\n writeFileSync(sidecarPath, JSON.stringify(recordToWrite, null, 2));\n logWarn(ctx, `Partial fill record written to: ${sidecarPath}`);\n } catch {\n // Ignore errors writing partial record - the main error is more important\n }\n }\n\n process.exit(1);\n }\n },\n );\n}\n\n/**\n * Build a session transcript from harness execution.\n */\nfunction buildSessionTranscript(\n formPath: string,\n mockMode: MockMode,\n mockPath: string | undefined,\n modelId: string | undefined,\n harnessConfig: HarnessConfig,\n turns: SessionTranscript['turns'],\n expectComplete: boolean,\n outputPath: string,\n): SessionTranscript {\n const final: SessionFinal = {\n expectComplete,\n // For mock mode, use the mock source as expected; otherwise use actual output\n expectedCompletedForm: mockMode === 'mock' ? (mockPath ?? outputPath) : outputPath,\n };\n\n const transcript: SessionTranscript = {\n sessionVersion: '0.1.0',\n mode: mockMode,\n form: {\n path: formPath,\n },\n harness: harnessConfig,\n turns,\n final,\n };\n\n // Add mode-specific fields\n if (mockMode === 'mock' && mockPath) {\n transcript.mock = {\n completedMock: mockPath,\n };\n } else if (mockMode === 'live' && modelId) {\n transcript.live = {\n modelId,\n };\n }\n\n return transcript;\n}\n","/**\n * Inspect command - Display form structure, progress, and issues.\n *\n * Outputs a comprehensive report with:\n * - Form state and title\n * - Structure summary (field counts, types)\n * - Progress summary (filled/empty counts)\n * - Full form content (groups, fields, current values)\n * - Issues sorted by priority\n */\n\nimport type { Command } from 'commander';\n\nimport pc from 'picocolors';\n\nimport { inspect } from '../../engine/inspect.js';\nimport { parseForm } from '../../engine/parse.js';\nimport type {\n FieldValue,\n InspectIssue,\n ProgressState,\n AnswerState,\n Note,\n} from '../../engine/coreTypes.js';\nimport { parseRolesFlag } from '../../settings.js';\nimport { formatOutput, getCommandContext, logError, logVerbose, readFile } from '../lib/shared.js';\n\n/**\n * Format state badge for console output.\n */\nfunction formatState(state: ProgressState, useColors: boolean): string {\n const badges: Record<ProgressState, [string, (s: string) => string]> = {\n complete: ['✓ complete', pc.green],\n incomplete: ['○ incomplete', pc.yellow],\n empty: ['◌ empty', pc.dim],\n invalid: ['✗ invalid', pc.red],\n };\n const [text, colorFn] = badges[state] ?? [state, (s: string) => s];\n return useColors ? colorFn(text) : text;\n}\n\n/**\n * Format answer state badge for console output.\n */\nfunction formatAnswerState(state: AnswerState, useColors: boolean): string {\n const badges: Record<AnswerState, [string, (s: string) => string]> = {\n answered: ['answered', pc.green],\n skipped: ['skipped', pc.yellow],\n aborted: ['aborted', pc.red],\n unanswered: ['unanswered', pc.dim],\n };\n const [text, colorFn] = badges[state] ?? [state, (s: string) => s];\n return useColors ? colorFn(text) : text;\n}\n\n/**\n * Format priority badge for console output.\n *\n * Priority tiers and colors:\n * - P1: bold red (critical)\n * - P2: yellow (high)\n * - P3: cyan (medium)\n * - P4: blue (low)\n * - P5: dim/gray (minimal)\n */\nfunction formatPriority(priority: number, useColors: boolean): string {\n const label = `P${priority}`;\n if (!useColors) {\n return label;\n }\n switch (priority) {\n case 1:\n return pc.red(pc.bold(label));\n case 2:\n return pc.yellow(label);\n case 3:\n return pc.cyan(label);\n case 4:\n return pc.blue(label);\n case 5:\n default:\n return pc.dim(label);\n }\n}\n\n/**\n * Format severity badge for console output.\n */\nfunction formatSeverity(severity: 'required' | 'recommended', useColors: boolean): string {\n if (!useColors) {\n return severity;\n }\n return severity === 'required' ? pc.red(severity) : pc.yellow(severity);\n}\n\n/**\n * Format a field value for console display.\n */\nfunction formatFieldValue(value: FieldValue | undefined, useColors: boolean): string {\n const dim = useColors ? pc.dim : (s: string) => s;\n const green = useColors ? pc.green : (s: string) => s;\n\n if (!value) {\n return dim('(empty)');\n }\n\n switch (value.kind) {\n case 'string':\n return value.value ? green(`\"${value.value}\"`) : dim('(empty)');\n case 'number':\n return value.value !== null ? green(String(value.value)) : dim('(empty)');\n case 'string_list':\n return value.items.length > 0\n ? green(`[${value.items.map((i) => `\"${i}\"`).join(', ')}]`)\n : dim('(empty)');\n case 'single_select':\n return value.selected ? green(value.selected) : dim('(none selected)');\n case 'multi_select':\n return value.selected.length > 0\n ? green(`[${value.selected.join(', ')}]`)\n : dim('(none selected)');\n case 'checkboxes': {\n const entries = Object.entries(value.values);\n if (entries.length === 0) {\n return dim('(no entries)');\n }\n return entries.map(([k, v]) => `${k}:${v}`).join(', ');\n }\n case 'url':\n return value.value ? green(`\"${value.value}\"`) : dim('(empty)');\n case 'url_list':\n return value.items.length > 0\n ? green(`[${value.items.map((i) => `\"${i}\"`).join(', ')}]`)\n : dim('(empty)');\n case 'date':\n return value.value ? green(value.value) : dim('(empty)');\n case 'year':\n return value.value !== null ? green(String(value.value)) : dim('(empty)');\n case 'table': {\n const rowCount = value.rows?.length ?? 0;\n return rowCount > 0 ? green(`(${rowCount} rows)`) : dim('(empty)');\n }\n default: {\n // Exhaustiveness check - TypeScript will error if a case is missing\n const _exhaustive: never = value;\n throw new Error(`Unhandled field value kind: ${(_exhaustive as { kind: string }).kind}`);\n }\n }\n}\n\n/** Field info for console report */\ninterface ReportField {\n id: string;\n kind: string;\n label: string;\n required: boolean;\n role: string;\n}\n\n/** Group info for console report */\ninterface ReportGroup {\n id: string;\n title?: string;\n children: ReportField[];\n}\n\n/** Report structure for console/JSON output */\ninterface InspectReport {\n title?: string;\n structure: unknown;\n progress: unknown;\n form_state: ProgressState;\n groups: ReportGroup[];\n values: Record<string, FieldValue>;\n notes: Note[];\n issues: {\n ref: string;\n scope: string;\n reason: string;\n message: string;\n priority: number;\n severity: 'required' | 'recommended';\n blockedBy?: string;\n }[];\n}\n\n/**\n * Format inspect report for console output.\n */\nfunction formatConsoleReport(report: InspectReport, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n const yellow = useColors ? pc.yellow : (s: string) => s;\n\n // Header\n lines.push(bold(cyan('Form Inspection Report')));\n if (report.title) {\n lines.push(`${bold('Title:')} ${report.title}`);\n }\n lines.push('');\n\n // Form state\n lines.push(`${bold('Form State:')} ${formatState(report.form_state, useColors)}`);\n lines.push('');\n\n // Structure summary\n const structure = report.structure as {\n groupCount: number;\n fieldCount: number;\n optionCount: number;\n };\n lines.push(bold('Structure:'));\n lines.push(` Groups: ${structure.groupCount}`);\n lines.push(` Fields: ${structure.fieldCount}`);\n lines.push(` Options: ${structure.optionCount}`);\n lines.push('');\n\n // Progress summary\n const progress = report.progress as {\n counts: {\n totalFields: number;\n requiredFields: number;\n // Dimension 1: AnswerState\n unansweredFields: number;\n answeredFields: number;\n skippedFields: number;\n abortedFields: number;\n // Dimension 2: Validity\n validFields: number;\n invalidFields: number;\n // Dimension 3: Value presence\n emptyFields: number;\n filledFields: number;\n // Derived\n emptyRequiredFields: number;\n totalNotes: number;\n };\n fields: Record<\n string,\n {\n answerState: AnswerState;\n hasNotes: boolean;\n noteCount: number;\n }\n >;\n };\n lines.push(bold('Progress:'));\n lines.push(` Total fields: ${progress.counts.totalFields}`);\n lines.push(` Required: ${progress.counts.requiredFields}`);\n lines.push(\n ` AnswerState: answered=${progress.counts.answeredFields}, skipped=${progress.counts.skippedFields}, aborted=${progress.counts.abortedFields}, unanswered=${progress.counts.unansweredFields}`,\n );\n lines.push(\n ` Validity: valid=${progress.counts.validFields}, invalid=${progress.counts.invalidFields}`,\n );\n lines.push(\n ` Value: filled=${progress.counts.filledFields}, empty=${progress.counts.emptyFields}`,\n );\n lines.push(` Empty required: ${progress.counts.emptyRequiredFields}`);\n lines.push(` Total notes: ${progress.counts.totalNotes}`);\n lines.push('');\n\n // Form content (groups and fields with values)\n lines.push(bold('Form Content:'));\n for (const group of report.groups) {\n lines.push(` ${bold(group.title ?? group.id)}`);\n for (const field of group.children) {\n const reqBadge = field.required ? yellow('[required]') : dim('[optional]');\n const roleBadge = field.role !== 'agent' ? cyan(`[${field.role}]`) : '';\n const fieldProgress = progress.fields[field.id];\n const responseStateBadge = fieldProgress\n ? `[${formatAnswerState(fieldProgress.answerState, useColors)}]`\n : '';\n const notesBadge = fieldProgress?.hasNotes\n ? cyan(`[${fieldProgress.noteCount} note${fieldProgress.noteCount > 1 ? 's' : ''}]`)\n : '';\n const value = report.values[field.id];\n const valueStr = formatFieldValue(value, useColors);\n lines.push(\n ` ${field.label} ${dim(`(${field.kind})`)} ${reqBadge} ${roleBadge} ${responseStateBadge} ${notesBadge}`.trim(),\n );\n lines.push(` ${dim('→')} ${valueStr}`);\n }\n }\n lines.push('');\n\n // Notes summary\n if (report.notes.length > 0) {\n lines.push(bold(`Notes (${report.notes.length}):`));\n for (const note of report.notes) {\n const roleBadge = cyan(`[${note.role}]`);\n const refLabel = dim(`${note.ref}:`);\n lines.push(` ${note.id} ${roleBadge} ${refLabel} ${note.text}`.trim());\n }\n lines.push('');\n }\n\n // Issues\n if (report.issues.length > 0) {\n lines.push(bold(`Issues (${report.issues.length}):`));\n for (const issue of report.issues) {\n const priority = formatPriority(issue.priority, useColors);\n const severity = formatSeverity(issue.severity, useColors);\n const blockedInfo = issue.blockedBy ? ` ${dim(`(blocked by: ${issue.blockedBy})`)}` : '';\n lines.push(\n ` ${priority} (${severity}) ${dim(`[${issue.scope}]`)} ${dim(issue.ref)}: ${issue.message}${blockedInfo}`,\n );\n }\n } else {\n lines.push(dim('No issues found.'));\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Register the inspect command.\n */\nexport function registerInspectCommand(program: Command): void {\n program\n .command('inspect <file>')\n .description('Inspect a form and display its structure, progress, and issues')\n .option(\n '--roles <roles>',\n \"Filter issues by target roles (comma-separated, or '*' for all; default: all)\",\n )\n .action(async (file: string, options: { roles?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n // Parse and validate --roles\n let targetRoles: string[] | undefined;\n if (options.roles) {\n try {\n targetRoles = parseRolesFlag(options.roles);\n // '*' means all roles - pass undefined to not filter\n if (targetRoles.includes('*')) {\n targetRoles = undefined;\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(`Invalid --roles: ${message}`);\n process.exit(1);\n }\n }\n\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Running inspection...');\n const result = inspect(form, { targetRoles });\n\n // Extract values from responses for report\n const values: Record<string, FieldValue> = {};\n for (const [fieldId, response] of Object.entries(form.responsesByFieldId)) {\n if (response.state === 'answered' && response.value) {\n values[fieldId] = response.value;\n }\n }\n\n // Build the report structure\n const report: InspectReport = {\n title: form.schema.title,\n structure: result.structureSummary,\n progress: result.progressSummary,\n form_state: result.formState,\n groups: form.schema.groups.map((group) => ({\n id: group.id,\n title: group.title,\n children: group.children.map((field) => ({\n id: field.id,\n kind: field.kind,\n label: field.label,\n required: field.required,\n role: field.role,\n })),\n })),\n values,\n notes: form.notes,\n issues: result.issues.map((issue: InspectIssue) => ({\n ref: issue.ref,\n scope: issue.scope,\n reason: issue.reason,\n message: issue.message,\n priority: issue.priority,\n severity: issue.severity,\n blockedBy: issue.blockedBy,\n })),\n };\n\n // Output in requested format\n const output = formatOutput(ctx, report, (data, useColors) =>\n formatConsoleReport(data as typeof report, useColors),\n );\n console.log(output);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Readme command - Display the README documentation.\n *\n * Shows the package README.md, formatted for the terminal when interactive,\n * or as plain text when piped.\n */\n\nimport type { Command } from 'commander';\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport pc from 'picocolors';\n\nimport { getCommandContext, logError, stripHtmlComments } from '../lib/shared.js';\n\n/**\n * Get the path to the README.md file.\n * Works both during development and when installed as a package.\n */\nfunction getReadmePath(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const dirName = thisDir.split(/[/\\\\]/).pop();\n\n if (dirName === 'dist') {\n // Bundled: dist -> package root -> README.md\n return join(dirname(thisDir), 'README.md');\n }\n\n // Development: src/cli/commands -> src/cli -> src -> package root -> README.md\n return join(dirname(dirname(dirname(thisDir))), 'README.md');\n}\n\n/**\n * Load the README content.\n */\nfunction loadReadme(): string {\n const readmePath = getReadmePath();\n try {\n return readFileSync(readmePath, 'utf-8');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to load README from ${readmePath}: ${message}`);\n }\n}\n\n/**\n * Apply basic terminal formatting to markdown content.\n * Colorizes headers, code blocks, and other elements for better readability.\n */\nfunction formatMarkdown(content: string, useColors: boolean): string {\n if (!useColors) {\n return content;\n }\n\n const lines = content.split('\\n');\n const formatted: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n // Track code blocks\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n formatted.push(pc.dim(line));\n continue;\n }\n\n if (inCodeBlock) {\n formatted.push(pc.dim(line));\n continue;\n }\n\n // Headers\n if (line.startsWith('# ')) {\n formatted.push(pc.bold(pc.cyan(line)));\n continue;\n }\n if (line.startsWith('## ')) {\n formatted.push(pc.bold(pc.blue(line)));\n continue;\n }\n if (line.startsWith('### ')) {\n formatted.push(pc.bold(line));\n continue;\n }\n\n // Inline code (backticks)\n let formattedLine = line.replace(/`([^`]+)`/g, (_match, code: string) => {\n return pc.yellow(code);\n });\n\n // Bold text\n formattedLine = formattedLine.replace(/\\*\\*([^*]+)\\*\\*/g, (_match, text: string) => {\n return pc.bold(text);\n });\n\n // Links - show text in cyan, URL dimmed\n formattedLine = formattedLine.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_match, text: string, url: string) => {\n return `${pc.cyan(text)} ${pc.dim(`(${url})`)}`;\n },\n );\n\n formatted.push(formattedLine);\n }\n\n return formatted.join('\\n');\n}\n\n/**\n * Check if stdout is an interactive terminal.\n */\nfunction isInteractive(): boolean {\n return process.stdout.isTTY === true;\n}\n\n/**\n * Display content. In a future enhancement, could pipe to a pager for long output.\n */\nfunction displayContent(content: string): void {\n console.log(content);\n}\n\n/**\n * Register the readme command.\n */\nexport function registerReadmeCommand(program: Command): void {\n program\n .command('readme')\n .description('✨Display README documentation ← START HERE!')\n .option('--raw', 'Output raw markdown without formatting')\n .action((options: { raw?: boolean }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const rawReadme = loadReadme();\n // Strip HTML comments (license headers, etc.) for cleaner output\n const readme = stripHtmlComments(rawReadme);\n\n // Determine if we should colorize\n const shouldColorize = !options.raw && isInteractive() && !ctx.quiet;\n\n const formatted = formatMarkdown(readme, shouldColorize);\n displayContent(formatted);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Report command - Generate filtered markdown reports from forms.\n *\n * Produces clean, readable markdown suitable for sharing:\n * - Instructions blocks are excluded by default\n * - Fields/groups with report=false are excluded\n * - Output is plain markdown without directives\n */\n\nimport type { Command } from 'commander';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { serializeReport } from '../../engine/serialize.js';\nimport { REPORT_EXTENSION } from '../../settings.js';\nimport { getCommandContext, logError, logVerbose, readFile, writeFile } from '../lib/shared.js';\n\n/**\n * Register the report command.\n */\nexport function registerReportCommand(program: Command): void {\n program\n .command('report <file>')\n .description('Generate filtered markdown report (excludes instructions, report=false elements)')\n .option('-o, --output <file>', 'Output file path (default: stdout)')\n .action(async (file: string, options: { output?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Generating report...');\n const reportContent = serializeReport(form);\n\n if (options.output) {\n // Write to specified output file\n let outputPath = options.output;\n // Ensure it has the .report.md extension if it's a bare name\n if (!outputPath.endsWith(REPORT_EXTENSION) && !outputPath.endsWith('.md')) {\n outputPath = outputPath + REPORT_EXTENSION;\n }\n await writeFile(outputPath, reportContent);\n logVerbose(ctx, `Report written to: ${outputPath}`);\n } else {\n // Output to stdout\n console.log(reportContent);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Spec command - Display the Markform specification.\n *\n * Shows the SPEC.md file, formatted for the terminal when interactive,\n * or as plain text when piped.\n */\n\nimport type { Command } from 'commander';\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport pc from 'picocolors';\n\nimport { getCommandContext, logError, stripHtmlComments } from '../lib/shared.js';\n\n/**\n * Get the path to the markform-spec.md file.\n * Works both during development and when installed as a package.\n */\nfunction getSpecPath(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const dirName = thisDir.split(/[/\\\\]/).pop();\n\n if (dirName === 'dist') {\n // Bundled: dist -> package root -> docs/markform-spec.md\n return join(dirname(thisDir), 'docs', 'markform-spec.md');\n }\n\n // Development: src/cli/commands -> src/cli -> src -> package root -> docs/markform-spec.md\n return join(dirname(dirname(dirname(thisDir))), 'docs', 'markform-spec.md');\n}\n\n/**\n * Load the spec content.\n */\nfunction loadSpec(): string {\n const specPath = getSpecPath();\n try {\n return readFileSync(specPath, 'utf-8');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to load SPEC from ${specPath}: ${message}`);\n }\n}\n\n/**\n * Apply basic terminal formatting to markdown content.\n * Colorizes headers, code blocks, and other elements for better readability.\n */\nfunction formatMarkdown(content: string, useColors: boolean): string {\n if (!useColors) {\n return content;\n }\n\n const lines = content.split('\\n');\n const formatted: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n // Track code blocks\n if (line.startsWith('```')) {\n inCodeBlock = !inCodeBlock;\n formatted.push(pc.dim(line));\n continue;\n }\n\n if (inCodeBlock) {\n formatted.push(pc.dim(line));\n continue;\n }\n\n // Headers\n if (line.startsWith('# ')) {\n formatted.push(pc.bold(pc.cyan(line)));\n continue;\n }\n if (line.startsWith('## ')) {\n formatted.push(pc.bold(pc.blue(line)));\n continue;\n }\n if (line.startsWith('### ')) {\n formatted.push(pc.bold(line));\n continue;\n }\n\n // Inline code (backticks)\n let formattedLine = line.replace(/`([^`]+)`/g, (_match, code: string) => {\n return pc.yellow(code);\n });\n\n // Bold text\n formattedLine = formattedLine.replace(/\\*\\*([^*]+)\\*\\*/g, (_match, text: string) => {\n return pc.bold(text);\n });\n\n // Links - show text in cyan, URL dimmed\n formattedLine = formattedLine.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_match, text: string, url: string) => {\n return `${pc.cyan(text)} ${pc.dim(`(${url})`)}`;\n },\n );\n\n formatted.push(formattedLine);\n }\n\n return formatted.join('\\n');\n}\n\n/**\n * Check if stdout is an interactive terminal.\n */\nfunction isInteractive(): boolean {\n return process.stdout.isTTY === true;\n}\n\n/**\n * Display content. In a future enhancement, could pipe to a pager for long output.\n */\nfunction displayContent(content: string): void {\n console.log(content);\n}\n\n/**\n * Register the spec command.\n */\nexport function registerSpecCommand(program: Command): void {\n program\n .command('spec')\n .description('Display the Markform specification')\n .option('--raw', 'Output raw markdown without formatting')\n .action((options: { raw?: boolean }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const rawSpec = loadSpec();\n // Strip HTML comments (license headers, etc.) for cleaner output\n const spec = stripHtmlComments(rawSpec);\n\n // Determine if we should colorize\n const shouldColorize = !options.raw && isInteractive() && !ctx.quiet;\n\n const formatted = formatMarkdown(spec, shouldColorize);\n displayContent(formatted);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Models command - List available AI models and providers.\n *\n * Displays supported providers, their environment variables,\n * and example models for use with the fill command.\n */\n\nimport type { Command } from 'commander';\n\nimport pc from 'picocolors';\n\nimport {\n getProviderInfo,\n getProviderNames,\n type ProviderName,\n} from '../../harness/modelResolver.js';\nimport { SUGGESTED_LLMS } from '../../settings.js';\nimport { formatOutput, getCommandContext, logError } from '../lib/shared.js';\n\n/**\n * Model info for a single provider.\n */\ninterface ProviderModelInfo {\n provider: ProviderName;\n envVar: string;\n models: string[];\n}\n\n/**\n * Get model info for all providers or a specific one.\n */\nfunction getModelInfo(providerFilter?: string): ProviderModelInfo[] {\n const providers = getProviderNames();\n\n // Validate filter if provided\n if (providerFilter && !providers.includes(providerFilter as ProviderName)) {\n throw new Error(`Unknown provider: \"${providerFilter}\". Available: ${providers.join(', ')}`);\n }\n\n const filtered = providerFilter ? [providerFilter as ProviderName] : providers;\n\n return filtered.map((provider) => {\n const info = getProviderInfo(provider);\n return {\n provider,\n envVar: info.envVar,\n models: SUGGESTED_LLMS[provider] ?? [],\n };\n });\n}\n\n/**\n * Format model info for console output.\n */\nfunction formatConsoleOutput(info: ProviderModelInfo[], useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const green = useColors ? pc.green : (s: string) => s;\n\n for (const { provider, envVar, models } of info) {\n lines.push(bold(cyan(`${provider}/`)));\n lines.push(` ${dim('env:')} ${envVar}`);\n\n if (models.length > 0) {\n lines.push(` ${dim('models:')}`);\n for (const model of models) {\n lines.push(` ${green(`${provider}/${model}`)}`);\n }\n } else {\n lines.push(` ${dim('(no suggested models)')}`);\n }\n lines.push('');\n }\n\n // Remove trailing empty line\n if (lines.length > 0 && lines[lines.length - 1] === '') {\n lines.pop();\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Register the models command.\n */\nexport function registerModelsCommand(program: Command): void {\n program\n .command('models')\n .description('List available AI providers and example models')\n .option(\n '-p, --provider <name>',\n 'Filter by provider (anthropic, openai, google, xai, deepseek)',\n )\n .action((options: { provider?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n const info = getModelInfo(options.provider);\n\n const output = formatOutput(ctx, info, (data, useColors) =>\n formatConsoleOutput(data as ProviderModelInfo[], useColors),\n );\n console.log(output);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Plan command - Show the idealized execution plan for a form.\n *\n * Computes and displays the execution plan (order levels, parallel batches,\n * loose serial items) without actually filling anything. Shows only remaining\n * (unanswered) fields. The form must pass validation before planning.\n */\n\nimport type { Command } from 'commander';\n\nimport pc from 'picocolors';\n\nimport type { ExecutionPlanItem, FieldBase, ParsedForm } from '../../engine/coreTypes.js';\nimport { computeExecutionPlan } from '../../engine/executionPlan.js';\nimport { inspect } from '../../engine/inspect.js';\nimport { parseForm } from '../../engine/parse.js';\nimport { formatOutput, getCommandContext, logError, logVerbose, readFile } from '../lib/shared.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\ninterface PlanItemJson {\n itemId: string;\n itemType: 'field' | 'group';\n fields?: PlanFieldJson[];\n}\n\ninterface PlanFieldJson {\n fieldId: string;\n label?: string;\n status: string;\n required: boolean;\n}\n\ninterface PlanBatchJson {\n batchId: string;\n items: PlanItemJson[];\n}\n\ninterface PlanOrderLevelJson {\n order: number;\n looseSerial: PlanItemJson[];\n parallelBatches: PlanBatchJson[];\n}\n\ninterface PlanReport {\n formId: string;\n title?: string;\n orderLevels: PlanOrderLevelJson[];\n summary: {\n orderLevelCount: number;\n parallelBatchCount: number;\n totalItems: number;\n remainingFields: number;\n };\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/**\n * Get the response status string for a field.\n */\nfunction getFieldStatus(form: ParsedForm, fieldId: string): string {\n const response = form.responsesByFieldId[fieldId];\n if (!response) {\n return 'unanswered';\n }\n return response.state; // 'answered', 'skipped', 'aborted', 'unanswered'\n}\n\n/**\n * Check if a field still needs work (not yet answered).\n */\nfunction fieldNeedsWork(form: ParsedForm, fieldId: string): boolean {\n const response = form.responsesByFieldId[fieldId];\n if (!response) {\n return true;\n }\n return response.state !== 'answered';\n}\n\n/**\n * Get all field IDs for an execution plan item.\n */\nfunction getFieldIdsForItem(form: ParsedForm, item: ExecutionPlanItem): string[] {\n if (item.itemType === 'field') {\n return [item.itemId];\n }\n // Group: find matching group and return its children's IDs\n const group = form.schema.groups.find((g) => g.id === item.itemId);\n if (!group) {\n return [];\n }\n return group.children.map((f) => f.id);\n}\n\n/**\n * Get field metadata from the form schema.\n */\nfunction getFieldMeta(form: ParsedForm, fieldId: string): FieldBase | undefined {\n for (const group of form.schema.groups) {\n const field = group.children.find((f) => f.id === fieldId);\n if (field) {\n return field;\n }\n }\n return undefined;\n}\n\n/**\n * Build a PlanItemJson, including only fields that need work.\n * Returns undefined if no fields need work.\n */\nfunction buildPlanItem(form: ParsedForm, item: ExecutionPlanItem): PlanItemJson | undefined {\n const fieldIds = getFieldIdsForItem(form, item);\n const remainingFieldIds = fieldIds.filter((id) => fieldNeedsWork(form, id));\n\n if (remainingFieldIds.length === 0) {\n return undefined; // All fields answered\n }\n\n const planItem: PlanItemJson = {\n itemId: item.itemId,\n itemType: item.itemType,\n };\n\n if (item.itemType === 'group') {\n planItem.fields = remainingFieldIds.map((id) => {\n const meta = getFieldMeta(form, id);\n return {\n fieldId: id,\n label: meta?.label,\n status: getFieldStatus(form, id),\n required: meta?.required ?? false,\n };\n });\n }\n\n return planItem;\n}\n\n// =============================================================================\n// Console Formatting\n// =============================================================================\n\nfunction formatConsolePlan(report: PlanReport, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n const yellow = useColors ? pc.yellow : (s: string) => s;\n\n // Header\n const titlePart = report.title ? ` (${report.title})` : '';\n lines.push(bold(cyan(`Plan: ${report.formId}${titlePart}`)));\n lines.push('');\n\n if (report.orderLevels.length === 0) {\n lines.push(dim('No remaining work — all fields are complete.'));\n return lines.join('\\n');\n }\n\n for (const level of report.orderLevels) {\n const itemCount =\n level.looseSerial.length + level.parallelBatches.reduce((sum, b) => sum + b.items.length, 0);\n lines.push(bold(`Order level ${level.order} (${itemCount} items):`));\n\n // Loose serial\n if (level.looseSerial.length > 0) {\n lines.push(` Loose serial (primary agent):`);\n for (const item of level.looseSerial) {\n formatItem(lines, item, dim, yellow, ' ');\n }\n }\n\n // Parallel batches\n for (const batch of level.parallelBatches) {\n lines.push(\n ` Parallel batch \"${batch.batchId}\" (${batch.items.length} items, ${batch.items.length} agents):`,\n );\n for (const item of batch.items) {\n formatItem(lines, item, dim, yellow, ' ');\n }\n }\n\n lines.push('');\n }\n\n // Summary\n const s = report.summary;\n lines.push(\n dim(\n `Summary: ${s.orderLevelCount} order level${s.orderLevelCount !== 1 ? 's' : ''}, ` +\n `${s.parallelBatchCount} parallel batch${s.parallelBatchCount !== 1 ? 'es' : ''}, ` +\n `${s.remainingFields} remaining field${s.remainingFields !== 1 ? 's' : ''}`,\n ),\n );\n\n return lines.join('\\n');\n}\n\nfunction formatItem(\n lines: string[],\n item: PlanItemJson,\n dim: (s: string) => string,\n yellow: (s: string) => string,\n indent: string,\n): void {\n if (item.itemType === 'group' && item.fields) {\n lines.push(`${indent}- ${item.itemId} [group]`);\n for (const f of item.fields) {\n const label = f.label ? ` (${f.label})` : '';\n const req = f.required ? yellow('required') + ', ' : '';\n lines.push(`${indent} ${f.fieldId}${label} — ${req}${dim(f.status)}`);\n }\n } else {\n // Single field\n const meta = item;\n lines.push(`${indent}- ${meta.itemId}`);\n }\n}\n\n// =============================================================================\n// Command Registration\n// =============================================================================\n\n/**\n * Register the plan command.\n */\nexport function registerPlanCommand(program: Command): void {\n program\n .command('plan <file>')\n .description('Show the idealized execution plan for a form (parallel batches, order levels)')\n .action(async (file: string, _options: Record<string, unknown>, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing and validating form...');\n const form = parseForm(content);\n\n // Validate: inspect for issues\n const inspectResult = inspect(form);\n const parseErrors = inspectResult.issues.filter((i) => i.reason === 'validation_error');\n if (parseErrors.length > 0) {\n logError(\n `Form has validation errors. Fix them before planning:\\n` +\n parseErrors.map((e) => ` - ${e.message}`).join('\\n'),\n );\n process.exit(1);\n }\n\n logVerbose(ctx, 'Computing execution plan...');\n const executionPlan = computeExecutionPlan(form);\n\n // Build plan report grouped by order level, filtered to remaining work\n const orderLevels: PlanOrderLevelJson[] = [];\n let totalItems = 0;\n let totalRemainingFields = 0;\n let totalBatches = 0;\n\n for (const order of executionPlan.orderLevels) {\n // Filter loose serial items to only those with remaining work\n const looseItems: PlanItemJson[] = [];\n for (const item of executionPlan.looseSerial) {\n if (item.order !== order) continue;\n const planItem = buildPlanItem(form, item);\n if (planItem) {\n looseItems.push(planItem);\n totalItems++;\n totalRemainingFields += countRemainingFields(form, item);\n }\n }\n\n // Filter parallel batches\n const batches: PlanBatchJson[] = [];\n for (const batch of executionPlan.parallelBatches) {\n const batchItems: PlanItemJson[] = [];\n for (const item of batch.items) {\n if (item.order !== order) continue;\n const planItem = buildPlanItem(form, item);\n if (planItem) {\n batchItems.push(planItem);\n totalItems++;\n totalRemainingFields += countRemainingFields(form, item);\n }\n }\n if (batchItems.length > 0) {\n batches.push({ batchId: batch.batchId, items: batchItems });\n totalBatches++;\n }\n }\n\n if (looseItems.length > 0 || batches.length > 0) {\n orderLevels.push({\n order,\n looseSerial: looseItems,\n parallelBatches: batches,\n });\n }\n }\n\n const report: PlanReport = {\n formId: form.schema.id,\n title: form.schema.title,\n orderLevels,\n summary: {\n orderLevelCount: orderLevels.length,\n parallelBatchCount: totalBatches,\n totalItems,\n remainingFields: totalRemainingFields,\n },\n };\n\n const output = formatOutput(ctx, report, (data, useColors) =>\n formatConsolePlan(data as PlanReport, useColors),\n );\n console.log(output);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n\n/**\n * Count remaining fields for an execution plan item.\n */\nfunction countRemainingFields(form: ParsedForm, item: ExecutionPlanItem): number {\n const fieldIds = getFieldIdsForItem(form, item);\n return fieldIds.filter((id) => fieldNeedsWork(form, id)).length;\n}\n","/**\n * Serve command - Serve a form as a web page for browsing.\n *\n * Starts an HTTP server that renders the form as interactive HTML.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Command } from 'commander';\n\nimport { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readFile as readFileAsync } from 'node:fs/promises';\nimport { createServer } from 'node:http';\nimport { basename, resolve } from 'node:path';\n\nimport pc from 'picocolors';\nimport YAML from 'yaml';\n\nimport { applyPatches } from '../../engine/apply.js';\nimport { parseForm } from '../../engine/parse.js';\nimport { formToJsonSchema } from '../../engine/jsonSchema.js';\nimport { serializeForm, serializeReport } from '../../engine/serialize.js';\nimport type { FillRecord } from '../../harness/fillRecord.js';\nimport { toNotesArray, toStructuredValues } from '../lib/exportHelpers.js';\nimport {\n DEFAULT_PORT,\n deriveFillRecordPath,\n detectFileType,\n type FileType,\n} from '../../settings.js';\nimport type {\n CheckboxesField,\n CheckboxesValue,\n DateField,\n Field,\n FieldGroup,\n FieldValue,\n MultiSelectField,\n MultiSelectValue,\n NumberField,\n Patch,\n ParsedForm,\n SingleSelectField,\n SingleSelectValue,\n StringField,\n StringListField,\n TableField,\n TableValue,\n UrlField,\n UrlListField,\n YearField,\n} from '../../engine/coreTypes.js';\nimport {\n type CommandContext,\n getCommandContext,\n logError,\n logInfo,\n logVerbose,\n readFile,\n writeFile,\n} from '../lib/shared.js';\nimport { generateVersionedPath } from '../lib/versioning.js';\nimport { friendlyUrlAbbrev, formatBareUrlsAsHtmlLinks } from '../../utils/urlFormat.js';\n\n/**\n * Open a URL in the default browser (cross-platform).\n */\nfunction openBrowser(url: string): void {\n const platform = process.platform;\n\n let command: string;\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"\" \"${url}\"`;\n } else {\n // Linux and other Unix-like systems\n command = `xdg-open \"${url}\"`;\n }\n\n exec(command, (error) => {\n if (error) {\n // Silently ignore - user can still open URL manually\n }\n });\n}\n\n// =============================================================================\n// Tab Configuration\n// =============================================================================\n\n/** Represents a tab for navigation */\ninterface Tab {\n id: 'view' | 'form' | 'source' | 'report' | 'values' | 'schema' | 'fill-record';\n label: string;\n path: string | null; // Source file path (for source tab) or null for dynamically generated\n}\n\n/**\n * Build tabs for a form file.\n * All tabs are always present - content is generated dynamically from the form.\n * Tab order: View, Edit, Source, Report, Values, Schema, Fill Record (if sidecar exists)\n */\nfunction buildFormTabs(formPath: string): Tab[] {\n const tabs: Tab[] = [\n { id: 'view', label: 'View', path: null }, // Generated from form\n { id: 'form', label: 'Edit', path: formPath }, // Interactive editor\n { id: 'source', label: 'Source', path: formPath }, // Form source\n { id: 'report', label: 'Report', path: null }, // Generated from form\n { id: 'values', label: 'Values', path: null }, // Generated from form\n { id: 'schema', label: 'Schema', path: null }, // Generated from form\n ];\n\n // Add Fill Record tab if sidecar file exists\n const sidecarPath = deriveFillRecordPath(formPath);\n if (existsSync(sidecarPath)) {\n tabs.push({ id: 'fill-record', label: 'Fill Record', path: sidecarPath });\n }\n\n return tabs;\n}\n\n/**\n * Register the serve command.\n */\nexport function registerServeCommand(program: Command): void {\n program\n .command('serve <file>')\n .description('Serve a file as a web page (forms are interactive, others are read-only)')\n .option('-p, --port <port>', 'Port to serve on', String(DEFAULT_PORT))\n .option('--no-open', \"Don't open browser automatically\")\n .action(async (file: string, options: { port?: string; open?: boolean }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n const port = parseInt(options.port ?? String(DEFAULT_PORT), 10);\n const filePath = resolve(file);\n const fileType = detectFileType(filePath);\n\n try {\n logVerbose(ctx, `Reading file: ${filePath}`);\n const content = await readFile(filePath);\n\n // For form files, parse and track state\n let form: ParsedForm | null = null;\n if (fileType === 'form') {\n form = parseForm(content);\n }\n\n // Build tabs for form files (all tabs are generated dynamically)\n const tabs = fileType === 'form' ? buildFormTabs(filePath) : null;\n\n // Start the server\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n handleRequest(req, res, filePath, fileType, form, ctx, tabs, (updatedForm) => {\n form = updatedForm;\n }).catch((err) => {\n console.error('Request error:', err);\n res.writeHead(500);\n res.end('Internal Server Error');\n });\n });\n\n server.listen(port, () => {\n const url = `http://localhost:${port}`;\n const typeLabel =\n fileType === 'form' ? 'Form' : fileType === 'unknown' ? 'File' : fileType.toUpperCase();\n logInfo(ctx, pc.green(`\\n✓ ${typeLabel} server running at ${pc.bold(url)}\\n`));\n logInfo(ctx, pc.dim('Press Ctrl+C to stop\\n'));\n\n // Open browser by default unless --no-open is specified\n if (options.open !== false) {\n openBrowser(url);\n }\n });\n\n // Handle graceful shutdown\n process.on('SIGINT', () => {\n logInfo(ctx, '\\nShutting down server...');\n server.close();\n process.exit(0);\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n\n/**\n * Handle HTTP requests.\n * Dispatches to appropriate renderer based on file type.\n */\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n filePath: string,\n fileType: FileType,\n form: ParsedForm | null,\n ctx: CommandContext,\n tabs: Tab[] | null,\n updateForm: (form: ParsedForm) => void,\n): Promise<void> {\n const url = req.url ?? '/';\n\n // Handle tab content requests for form files with tabs\n if (req.method === 'GET' && url.startsWith('/tab/') && tabs && tabs.length > 1) {\n const tabId = url.slice(5) as Tab['id'];\n const tab = tabs.find((t) => t.id === tabId);\n\n // Handle special tabs that need the parsed form or source content\n if (tabId === 'view' && form) {\n const html = renderViewContent(form);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n return;\n }\n\n if (tabId === 'source' && tab?.path) {\n const content = await readFileAsync(tab.path, 'utf-8');\n const html = renderSourceContent(content);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n return;\n }\n\n // Report tab - generate dynamically from form\n if (tabId === 'report' && form) {\n const reportContent = serializeReport(form);\n const html = renderMarkdownContent(reportContent);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n return;\n }\n\n // Values tab - generate dynamically from form\n if (tabId === 'values' && form) {\n const values = toStructuredValues(form);\n const notes = toNotesArray(form);\n const exportData = {\n values,\n ...(notes.length > 0 && { notes }),\n };\n const yamlContent = YAML.stringify(exportData);\n const html = renderYamlContent(yamlContent);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n return;\n }\n\n // Schema tab - generate dynamically from form\n if (tabId === 'schema' && form) {\n const result = formToJsonSchema(form);\n const jsonContent = JSON.stringify(result.schema, null, 2);\n const html = renderJsonContent(jsonContent);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n return;\n }\n\n // Fill Record tab - load and render fill record sidecar\n if (tabId === 'fill-record' && tab?.path) {\n try {\n const content = await readFileAsync(tab.path, 'utf-8');\n const fillRecord = JSON.parse(content) as FillRecord;\n const html = renderFillRecordContent(fillRecord);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n return;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(`Error loading fill record: ${message}`);\n return;\n }\n }\n\n res.writeHead(404);\n res.end('Tab not found');\n return;\n }\n\n if (req.method === 'GET' && url === '/') {\n // Dispatch to appropriate renderer based on file type\n if (fileType === 'form' && form) {\n const html = renderFormHtml(form, tabs);\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n } else if (fileType === 'raw' || fileType === 'report') {\n const content = await readFileAsync(filePath, 'utf-8');\n const html = renderMarkdownHtml(content, basename(filePath));\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n } else if (fileType === 'yaml') {\n const content = await readFileAsync(filePath, 'utf-8');\n const html = renderYamlHtml(content, basename(filePath));\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n } else if (fileType === 'json' || fileType === 'schema') {\n const content = await readFileAsync(filePath, 'utf-8');\n const html = renderJsonHtml(content, basename(filePath));\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n } else {\n // Unknown file type - show as plain text\n const content = await readFileAsync(filePath, 'utf-8');\n const html = renderPlainTextHtml(content, basename(filePath));\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(html);\n }\n } else if (req.method === 'POST' && url === '/save' && fileType === 'form' && form) {\n // Save the form to a new versioned file\n await handleSave(req, res, form, filePath, ctx, updateForm);\n } else if (url === '/api/form' && form) {\n // API endpoint for form data\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ schema: form.schema }));\n } else {\n res.writeHead(404);\n res.end('Not Found');\n }\n}\n\n/**\n * Parse form body data.\n */\nfunction parseFormBody(body: string): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n const params = new URLSearchParams(body);\n\n for (const [key, value] of params) {\n const existing = result[key];\n if (existing !== undefined) {\n if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n result[key] = [existing, value];\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Convert form data to patches.\n */\nfunction formDataToPatches(formData: Record<string, string | string[]>, form: ParsedForm): Patch[] {\n const patches: Patch[] = [];\n const fields = form.schema.groups.flatMap((g) => g.children);\n\n for (const field of fields) {\n const fieldId = field.id;\n\n // Check if this field was explicitly skipped\n const skipKey = `__skip__${fieldId}`;\n if (formData[skipKey] === '1' && !field.required) {\n patches.push({ op: 'skip_field', fieldId, role: 'user' });\n continue; // Don't process other patches for this field\n }\n\n switch (field.kind) {\n case 'string': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n patches.push({ op: 'set_string', fieldId, value: value.trim() });\n } else if (!value || (typeof value === 'string' && value.trim() === '')) {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'number': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n const num = parseFloat(value);\n if (!isNaN(num)) {\n patches.push({ op: 'set_number', fieldId, value: num });\n }\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'string_list': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n const items = value\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s !== '');\n if (items.length > 0) {\n patches.push({ op: 'set_string_list', fieldId, value: items });\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'single_select': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value !== '') {\n patches.push({ op: 'set_single_select', fieldId, value });\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'multi_select': {\n const value = formData[fieldId];\n const selected = Array.isArray(value) ? value : value ? [value] : [];\n if (selected.length > 0 && selected[0] !== '') {\n patches.push({ op: 'set_multi_select', fieldId, value: selected });\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'checkboxes': {\n const mode = field.checkboxMode ?? 'multi';\n\n if (mode === 'simple') {\n // Simple mode: checkboxes send their value when checked\n const value = formData[fieldId];\n const checked = Array.isArray(value) ? value : value ? [value] : [];\n\n const checkboxValues: Record<string, 'done' | 'todo'> = {};\n for (const opt of field.options) {\n checkboxValues[opt.id] = checked.includes(opt.id) ? 'done' : 'todo';\n }\n patches.push({ op: 'set_checkboxes', fieldId, value: checkboxValues });\n } else {\n // Multi or explicit mode: each option has its own select\n const values: Record<string, string> = {};\n for (const opt of field.options) {\n const selectName = `${fieldId}.${opt.id}`;\n const selectValue = formData[selectName];\n if (typeof selectValue === 'string' && selectValue !== '') {\n values[opt.id] = selectValue;\n }\n }\n if (Object.keys(values).length > 0) {\n patches.push({\n op: 'set_checkboxes',\n fieldId,\n value: values as Record<\n string,\n 'todo' | 'done' | 'active' | 'incomplete' | 'na' | 'yes' | 'no' | 'unfilled'\n >,\n });\n }\n }\n break;\n }\n\n case 'url': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n patches.push({ op: 'set_url', fieldId, value: value.trim() });\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'url_list': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n const items = value\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s !== '');\n if (items.length > 0) {\n patches.push({ op: 'set_url_list', fieldId, value: items });\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'date': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n patches.push({ op: 'set_date', fieldId, value: value.trim() });\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'year': {\n const value = formData[fieldId];\n if (typeof value === 'string' && value.trim() !== '') {\n const num = parseInt(value, 10);\n if (!isNaN(num)) {\n patches.push({ op: 'set_year', fieldId, value: num });\n }\n } else {\n patches.push({ op: 'clear_field', fieldId });\n }\n break;\n }\n\n case 'table': {\n // Table fields are read-only in the web UI for now\n // Table editing would require a more complex UI (add/remove rows, cell editing)\n break;\n }\n\n default: {\n // Exhaustiveness check - TypeScript will error if a case is missing\n const _exhaustive: never = field;\n throw new Error(`Unhandled field kind: ${(_exhaustive as { kind: string }).kind}`);\n }\n }\n }\n\n return patches;\n}\n\n/**\n * Handle form save request.\n */\nasync function handleSave(\n req: IncomingMessage,\n res: ServerResponse,\n form: ParsedForm,\n filePath: string,\n ctx: CommandContext,\n updateForm: (form: ParsedForm) => void,\n): Promise<void> {\n try {\n // Read request body\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n const body = Buffer.concat(chunks).toString('utf-8');\n\n // Parse form data\n const formData = parseFormBody(body);\n\n // Convert to patches\n const patches = formDataToPatches(formData, form);\n\n // Apply patches (mutates form in place)\n applyPatches(form, patches);\n\n // Update the in-memory form reference\n updateForm(form);\n\n // Generate versioned filename\n const newPath = generateVersionedPath(filePath);\n\n // Serialize the form\n const content = serializeForm(form);\n\n if (ctx.dryRun) {\n logInfo(ctx, `[DRY RUN] Would save to: ${newPath}`);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ success: true, path: newPath, dryRun: true }));\n return;\n }\n\n // Write the file\n await writeFile(newPath, content);\n logInfo(ctx, pc.green(`Saved to: ${newPath}`));\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ success: true, path: newPath }));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ success: false, error: message }));\n }\n}\n\n/**\n * Render the form as HTML.\n * @public Exported for testing.\n */\nexport function renderFormHtml(form: ParsedForm, tabs?: Tab[] | null): string {\n const { schema, responsesByFieldId } = form;\n const formTitle = schema.title ?? schema.id;\n\n const groupsHtml = schema.groups\n .map((group) => renderGroup(group, responsesByFieldId))\n .join('\\n');\n\n // Build tab bar HTML if we have multiple tabs\n const showTabs = tabs && tabs.length > 1;\n const tabBarHtml = showTabs\n ? `<div class=\"tab-bar\">\n ${tabs\n .map(\n (tab, i) =>\n `<button class=\"tab-btn${i === 0 ? ' active' : ''}\" data-tab=\"${tab.id}\">${escapeHtml(tab.label)}</button>`,\n )\n .join('\\n ')}\n </div>`\n : '';\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(formTitle)} - Markform</title>\n <style>\n * { box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n line-height: 1.6;\n max-width: 800px;\n margin: 0 auto;\n padding: 2rem;\n background: #f8f9fa;\n color: #212529;\n }\n h1 { color: #495057; border-bottom: none; padding-bottom: 0.5rem; }\n /* Tab bar styles */\n .tab-bar {\n display: flex;\n gap: 0.25rem;\n margin-bottom: 1.5rem;\n border-bottom: 2px solid #dee2e6;\n padding-bottom: 0;\n }\n .tab-btn {\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: #6c757d;\n font-size: 0.95rem;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n margin-bottom: -2px;\n transition: all 0.15s;\n }\n .tab-btn:hover {\n color: #495057;\n }\n .tab-btn.active {\n color: #0d6efd;\n border-bottom-color: #0d6efd;\n font-weight: 500;\n }\n .tab-content {\n display: none;\n }\n .tab-content.active {\n display: block;\n }\n /* Light theme syntax highlighting for tab content */\n .tab-content pre {\n background: #f8f9fa;\n color: #24292e;\n padding: 1rem;\n border-radius: 6px;\n border: 1px solid #e1e4e8;\n overflow-x: auto;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: 0.9rem;\n line-height: 1.5;\n }\n .syn-key { color: #005cc5; }\n .syn-string { color: #22863a; }\n .syn-number { color: #005cc5; }\n .syn-bool { color: #d73a49; }\n .syn-null { color: #d73a49; }\n .syn-comment { color: #6a737d; font-style: italic; }\n /* Jinja/MarkDoc syntax highlighting */\n .syn-jinja-tag { color: #6f42c1; font-weight: 500; }\n .syn-jinja-keyword { color: #d73a49; }\n .syn-jinja-attr { color: #005cc5; }\n .syn-jinja-value { color: #22863a; }\n /* Markdown syntax highlighting */\n .syn-md-header { color: #005cc5; font-weight: 600; }\n .syn-md-bold { font-weight: 600; }\n .syn-md-italic { font-style: italic; }\n .syn-md-code { background: #f1f3f5; padding: 0.1em 0.3em; border-radius: 3px; }\n .syn-md-link { color: #0366d6; }\n .syn-md-list { color: #d73a49; }\n /* View tab styles */\n .view-content { padding: 0.5rem 0; }\n .view-group { background: white; border-radius: 8px; padding: 1.5rem; margin-bottom: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n .view-group h2 { color: #6c757d; font-size: 1.25rem; margin-top: 0; }\n .view-field { margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid #e9ecef; }\n .view-field:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }\n .view-field-label { font-weight: 600; color: #495057; margin-bottom: 0.25rem; }\n .view-field-value { color: #212529; }\n .view-field-empty { color: #adb5bd; font-style: italic; }\n /* Markdown content styles */\n .markdown-content { padding: 0.5rem 0; }\n .markdown-content h2 { font-size: 1.4rem; color: #24292e; margin: 1.5rem 0 0.75rem; }\n .markdown-content h3 { font-size: 1.2rem; color: #24292e; margin: 1.25rem 0 0.5rem; }\n .markdown-content h4 { font-size: 1.1rem; color: #24292e; margin: 1rem 0 0.5rem; }\n .markdown-content h5 { font-size: 1rem; color: #24292e; margin: 0.75rem 0 0.5rem; }\n .markdown-content p { margin: 0.75rem 0; line-height: 1.6; }\n .markdown-content li { margin: 0.25rem 0; margin-left: 1.5rem; line-height: 1.6; }\n .markdown-content li.checkbox-item { list-style: none; margin-left: 0; }\n .markdown-content code { background: #f1f3f5; padding: 0.2em 0.4em; border-radius: 3px; font-size: 0.9em; }\n .markdown-content pre { background: #f8f9fa; padding: 1rem; border-radius: 6px; border: 1px solid #e1e4e8; overflow-x: auto; }\n .markdown-content pre code { background: none; padding: 0; }\n .markdown-content a { color: #0366d6; text-decoration: none; }\n .markdown-content a:hover { text-decoration: underline; }\n .markdown-content strong { font-weight: 600; }\n /* URL link with hover copy */\n .url-link {\n color: #0366d6;\n text-decoration: none;\n position: relative;\n }\n .url-link:hover {\n text-decoration: underline;\n }\n .url-copy-tooltip {\n position: fixed;\n padding: 0.25rem 0.5rem;\n background: #6c757d;\n color: white;\n border-radius: 4px;\n font-size: 0.75rem;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transition: opacity 0.2s ease, visibility 0.2s ease, background 0.2s ease, transform 0.15s ease;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n z-index: 10000;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n }\n .url-copy-tooltip.visible {\n opacity: 1;\n visibility: visible;\n pointer-events: auto;\n }\n .url-copy-tooltip:hover {\n background: #343a40;\n transform: translateY(-50%) scale(1.02);\n }\n .url-copy-tooltip svg {\n width: 12px;\n height: 12px;\n transition: opacity 0.15s ease;\n }\n .url-copy-tooltip.copied {\n background: #28a745;\n }\n .url-copy-tooltip.copied:hover {\n background: #218838;\n }\n .url-copy-tooltip.transitioning {\n opacity: 0.7;\n }\n /* Checkbox and state styles */\n .checkbox { font-size: 1.1em; margin-right: 0.25em; }\n .checkbox.checked { color: #28a745; }\n .checkbox.unchecked { color: #6c757d; }\n .state-badge { display: inline-block; width: 1.1em; text-align: center; margin-right: 0.25em; font-weight: 600; }\n .state-badge.state-active { color: #0d6efd; }\n .state-badge.state-incomplete { color: #ffc107; }\n .state-badge.state-na { color: #6c757d; }\n .state-badge.state-unfilled { color: #adb5bd; }\n .checkbox-list { list-style: none; padding-left: 0; margin: 0.25rem 0; }\n .checkbox-list .checkbox-item { margin-left: 0; }\n .loading { text-align: center; padding: 2rem; color: #6c757d; }\n .error { text-align: center; padding: 2rem; color: #dc3545; }\n h2 { color: #6c757d; font-size: 1.25rem; }\n .group {\n background: white;\n border-radius: 8px;\n padding: 1.5rem;\n margin-bottom: 1.5rem;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n .field {\n margin-bottom: 1.5rem;\n padding-bottom: 1rem;\n border-bottom: 1px solid #e9ecef;\n }\n .field:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }\n .field-label {\n font-weight: 600;\n color: #495057;\n display: block;\n margin-bottom: 0.5rem;\n }\n .required { color: #dc3545; }\n .type-badge {\n font-size: 0.7rem;\n padding: 0.1rem 0.3rem;\n background: #e9ecef;\n border-radius: 3px;\n color: #6c757d;\n margin-left: 0.5rem;\n font-weight: normal;\n }\n input[type=\"text\"],\n input[type=\"number\"],\n input[type=\"url\"],\n input[type=\"date\"],\n textarea,\n select {\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 1rem;\n border: 1px solid #ced4da;\n border-radius: 4px;\n background: #fff;\n transition: border-color 0.15s ease-in-out;\n }\n input[type=\"url\"] {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: 0.9rem;\n }\n input[type=\"text\"]:focus,\n input[type=\"number\"]:focus,\n input[type=\"url\"]:focus,\n input[type=\"date\"]:focus,\n textarea:focus,\n select:focus {\n outline: none;\n border-color: #80bdff;\n box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);\n }\n textarea {\n min-height: 100px;\n resize: vertical;\n }\n .checkbox-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n .checkbox-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n .checkbox-item input[type=\"checkbox\"] {\n width: auto;\n margin: 0;\n }\n .checkbox-item label {\n margin: 0;\n font-weight: normal;\n cursor: pointer;\n }\n .checkbox-item select {\n width: auto;\n min-width: 120px;\n }\n .option-row {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin-bottom: 0.5rem;\n }\n .option-row:last-child { margin-bottom: 0; }\n .option-label {\n flex: 1;\n }\n .toolbar {\n position: fixed;\n bottom: 2rem;\n right: 2rem;\n display: flex;\n gap: 0.5rem;\n }\n .btn {\n padding: 0.75rem 1.5rem;\n border: none;\n border-radius: 6px;\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s;\n }\n .btn-primary {\n background: #0d6efd;\n color: white;\n }\n .btn-primary:hover { background: #0b5ed7; }\n .field-help {\n font-size: 0.85rem;\n color: #6c757d;\n margin-top: 0.25rem;\n }\n .field-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.5rem;\n }\n .btn-skip {\n padding: 0.25rem 0.75rem;\n font-size: 0.85rem;\n background: #f8f9fa;\n border: 1px solid #ced4da;\n border-radius: 4px;\n color: #6c757d;\n cursor: pointer;\n }\n .btn-skip:hover {\n background: #e9ecef;\n color: #495057;\n }\n .field-skipped {\n opacity: 0.6;\n }\n .field-skipped input,\n .field-skipped textarea,\n .field-skipped select {\n background: #f8f9fa;\n }\n .skipped-badge {\n font-size: 0.75rem;\n padding: 0.15rem 0.4rem;\n background: #6c757d;\n color: white;\n border-radius: 3px;\n margin-left: 0.5rem;\n }\n .table-container {\n overflow-x: auto;\n }\n .data-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.9rem;\n }\n .data-table th,\n .data-table td {\n padding: 0.5rem 0.75rem;\n text-align: left;\n border: 1px solid #dee2e6;\n }\n .data-table th {\n background: #f8f9fa;\n font-weight: 600;\n color: #495057;\n }\n .data-table tbody tr:hover {\n background: #f8f9fa;\n }\n /* Print styles */\n @media print {\n body {\n background: white;\n padding: 0;\n margin: 0;\n }\n h1 {\n margin-top: 0;\n padding-top: 0;\n }\n .tab-bar {\n display: none !important;\n }\n .tab-content {\n display: none !important;\n }\n .tab-content.active {\n display: block !important;\n }\n .group {\n box-shadow: none;\n border: 1px solid #dee2e6;\n break-inside: avoid;\n page-break-inside: avoid;\n }\n .url-link {\n color: #0d6efd;\n text-decoration: none;\n }\n .url-copy-tooltip {\n display: none !important;\n }\n a[href]:after {\n content: none;\n }\n }\n </style>\n</head>\n<body>\n <h1>${escapeHtml(formTitle)}</h1>\n ${tabBarHtml}\n <div id=\"tab-view\" class=\"tab-content active\">\n <div class=\"loading\">Loading...</div>\n </div>\n <div id=\"tab-form\" class=\"tab-content\">\n <form method=\"POST\" action=\"/save\" id=\"markform\">\n ${groupsHtml}\n <div class=\"toolbar\">\n <button type=\"submit\" class=\"btn btn-primary\">Save</button>\n </div>\n </form>\n </div>\n ${showTabs ? '<div id=\"tab-other\" class=\"tab-content\"><div class=\"loading\">Loading...</div></div>' : ''}\n <script>\n // Copy YAML content handler for Fill Record tab (must be global for dynamically loaded content)\n function frCopyYaml(btn) {\n const pre = btn.parentElement.querySelector('pre');\n navigator.clipboard.writeText(pre.textContent).then(() => {\n const orig = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => btn.textContent = orig, 1500);\n });\n }\n\n // Tooltip handlers for Fill Record visualizations (must be global for dynamically loaded content)\n function frShowTip(el) {\n var tip = document.getElementById('fr-tooltip');\n if (tip && el.dataset.tooltip) {\n tip.textContent = el.dataset.tooltip;\n // Position tooltip centered above the element\n var rect = el.getBoundingClientRect();\n tip.style.left = (rect.left + rect.width / 2) + 'px';\n tip.style.top = (rect.top - 8) + 'px';\n tip.style.transform = 'translate(-50%, -100%)';\n tip.classList.add('visible');\n }\n }\n function frHideTip() {\n var tip = document.getElementById('fr-tooltip');\n if (tip) tip.classList.remove('visible');\n }\n\n // Track fields marked for skip\n const skippedFields = new Set();\n\n // Handle skip button clicks\n document.querySelectorAll('.btn-skip').forEach(btn => {\n btn.addEventListener('click', (e) => {\n const fieldId = e.target.dataset.skipField;\n if (!fieldId) return;\n\n // Toggle skip state\n if (skippedFields.has(fieldId)) {\n skippedFields.delete(fieldId);\n e.target.textContent = 'Skip';\n e.target.classList.remove('btn-skip-active');\n // Re-enable the field input\n const fieldDiv = e.target.closest('.field');\n fieldDiv.classList.remove('field-skipped');\n fieldDiv.querySelectorAll('input, select, textarea').forEach(input => {\n input.disabled = false;\n });\n } else {\n skippedFields.add(fieldId);\n e.target.textContent = 'Unskip';\n e.target.classList.add('btn-skip-active');\n // Disable the field input to show it's skipped\n const fieldDiv = e.target.closest('.field');\n fieldDiv.classList.add('field-skipped');\n fieldDiv.querySelectorAll('input, select, textarea').forEach(input => {\n input.disabled = true;\n });\n }\n });\n });\n\n document.getElementById('markform').addEventListener('submit', async (e) => {\n e.preventDefault();\n const formData = new FormData(e.target);\n const params = new URLSearchParams();\n\n // Add skip markers for skipped fields\n for (const fieldId of skippedFields) {\n params.append('__skip__' + fieldId, '1');\n }\n\n for (const [key, value] of formData) {\n params.append(key, value);\n }\n try {\n const res = await fetch('/save', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: params.toString()\n });\n const data = await res.json();\n if (data.success) {\n alert('Saved to: ' + data.path);\n location.reload();\n } else {\n alert('Error: ' + data.error);\n }\n } catch (err) {\n alert('Save failed: ' + err.message);\n }\n });\n\n // Tab switching logic\n const tabButtons = document.querySelectorAll('.tab-btn');\n const tabViewContent = document.getElementById('tab-view');\n const tabFormContent = document.getElementById('tab-form');\n const tabOtherContent = document.getElementById('tab-other');\n const tabCache = {};\n\n // Function to show a specific tab\n async function showTab(tabId) {\n // Hide all tab content\n if (tabViewContent) tabViewContent.classList.remove('active');\n if (tabFormContent) tabFormContent.classList.remove('active');\n if (tabOtherContent) tabOtherContent.classList.remove('active');\n\n if (tabId === 'form') {\n // Show Edit (form) tab - pre-rendered content\n if (tabFormContent) tabFormContent.classList.add('active');\n } else if (tabId === 'view') {\n // Show View tab\n if (tabViewContent) {\n tabViewContent.classList.add('active');\n // Fetch content if not cached\n if (!tabCache[tabId]) {\n tabViewContent.innerHTML = '<div class=\"loading\">Loading...</div>';\n try {\n const response = await fetch('/tab/' + tabId);\n if (response.ok) {\n tabCache[tabId] = await response.text();\n } else {\n tabCache[tabId] = '<div class=\"error\">Failed to load content</div>';\n }\n } catch (err) {\n tabCache[tabId] = '<div class=\"error\">Failed to load content</div>';\n }\n }\n tabViewContent.innerHTML = tabCache[tabId];\n }\n } else {\n // Show other tab content (source, report, values, schema)\n if (tabOtherContent) {\n tabOtherContent.classList.add('active');\n // Fetch content if not cached\n if (!tabCache[tabId]) {\n tabOtherContent.innerHTML = '<div class=\"loading\">Loading...</div>';\n try {\n const response = await fetch('/tab/' + tabId);\n if (response.ok) {\n tabCache[tabId] = await response.text();\n } else {\n tabCache[tabId] = '<div class=\"error\">Failed to load content</div>';\n }\n } catch (err) {\n tabCache[tabId] = '<div class=\"error\">Failed to load content</div>';\n }\n }\n tabOtherContent.innerHTML = tabCache[tabId];\n }\n }\n }\n\n tabButtons.forEach(btn => {\n btn.addEventListener('click', async () => {\n const tabId = btn.dataset.tab;\n\n // Update active button\n tabButtons.forEach(b => b.classList.remove('active'));\n btn.classList.add('active');\n\n await showTab(tabId);\n });\n });\n\n // Load View tab on page load (it's the default tab)\n showTab('view');\n\n // URL copy tooltip functionality - initialize once\n (function initUrlCopyTooltip() {\n // Feather copy icon SVG (inline to avoid external dependency)\n const copyIconSvg = '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg>';\n\n // Shared state\n let activeLink = null;\n let hideTimeout = null;\n\n // Create tooltip element\n const tooltip = document.createElement('span');\n tooltip.id = 'url-copy-tooltip';\n tooltip.className = 'url-copy-tooltip';\n tooltip.innerHTML = copyIconSvg + ' Copy';\n document.body.appendChild(tooltip);\n\n function showTooltip(link) {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n hideTimeout = null;\n }\n activeLink = link;\n const rect = link.getBoundingClientRect();\n tooltip.style.left = (rect.right + 6) + 'px';\n tooltip.style.top = (rect.top + rect.height / 2) + 'px';\n tooltip.style.transform = 'translateY(-50%)';\n tooltip.classList.add('visible');\n }\n\n function hideTooltip() {\n hideTimeout = setTimeout(() => {\n tooltip.classList.remove('visible');\n activeLink = null;\n }, 100);\n }\n\n // Tooltip hover keeps it visible\n tooltip.addEventListener('mouseenter', () => {\n if (hideTimeout) {\n clearTimeout(hideTimeout);\n hideTimeout = null;\n }\n });\n\n tooltip.addEventListener('mouseleave', () => {\n hideTooltip();\n });\n\n // Handle click on tooltip\n tooltip.addEventListener('click', async (e) => {\n e.preventDefault();\n e.stopPropagation();\n if (!activeLink) return;\n const url = activeLink.getAttribute('data-url') || activeLink.getAttribute('href');\n if (!url) return;\n try {\n await navigator.clipboard.writeText(url);\n // Transition to copied state\n tooltip.classList.add('transitioning');\n setTimeout(() => {\n tooltip.innerHTML = 'Copied!';\n tooltip.classList.add('copied');\n tooltip.classList.remove('transitioning');\n }, 100);\n // Reset after delay\n setTimeout(() => {\n tooltip.classList.add('transitioning');\n setTimeout(() => {\n tooltip.innerHTML = copyIconSvg + ' Copy';\n tooltip.classList.remove('copied');\n tooltip.classList.remove('transitioning');\n }, 100);\n }, 1500);\n } catch (err) {\n tooltip.innerHTML = 'Failed';\n setTimeout(() => {\n tooltip.innerHTML = copyIconSvg + ' Copy';\n }, 1500);\n }\n });\n\n // Function to attach hover listeners to new links\n function attachLinkListeners() {\n document.querySelectorAll('.url-link').forEach(link => {\n if (link.hasAttribute('data-tooltip-setup')) return;\n link.setAttribute('data-tooltip-setup', 'true');\n link.addEventListener('mouseenter', () => showTooltip(link));\n link.addEventListener('mouseleave', () => hideTooltip());\n });\n }\n\n // Attach to links after tab content loads\n const originalShowTab = showTab;\n showTab = async function(tabId) {\n await originalShowTab(tabId);\n attachLinkListeners();\n };\n\n // Initial setup\n setTimeout(attachLinkListeners, 100);\n })();\n </script>\n</body>\n</html>`;\n}\n\n/**\n * Render a field group as HTML.\n */\nfunction renderGroup(group: FieldGroup, responses: ParsedForm['responsesByFieldId']): string {\n const groupTitle = group.title ?? group.id;\n const fieldsHtml = group.children\n .map((field) => {\n const response = responses[field.id];\n const value = response?.state === 'answered' ? response.value : undefined;\n const isSkipped = response?.state === 'skipped';\n return renderFieldHtml(field, value, isSkipped);\n })\n .join('\\n');\n\n return `\n <div class=\"group\">\n <h2>${escapeHtml(groupTitle)}</h2>\n ${fieldsHtml}\n </div>`;\n}\n\n/**\n * Render a field as HTML.\n * @public Exported for testing.\n */\nexport function renderFieldHtml(\n field: Field,\n value: FieldValue | undefined,\n isSkipped?: boolean,\n): string {\n const skipped = isSkipped === true;\n const requiredMark = field.required ? '<span class=\"required\">*</span>' : '';\n const typeLabel = `<span class=\"type-badge\">${field.kind}</span>`;\n const skippedBadge = skipped ? '<span class=\"skipped-badge\">Skipped</span>' : '';\n const fieldClass = skipped ? 'field field-skipped' : 'field';\n const disabledAttr = skipped ? ' disabled' : '';\n\n let inputHtml: string;\n\n switch (field.kind) {\n case 'string':\n inputHtml = renderStringInput(field, value, disabledAttr);\n break;\n case 'number':\n inputHtml = renderNumberInput(field, value, disabledAttr);\n break;\n case 'string_list':\n inputHtml = renderStringListInput(field, value, disabledAttr);\n break;\n case 'single_select':\n inputHtml = renderSingleSelectInput(\n field,\n value as SingleSelectValue | undefined,\n disabledAttr,\n );\n break;\n case 'multi_select':\n inputHtml = renderMultiSelectInput(\n field,\n value as MultiSelectValue | undefined,\n disabledAttr,\n );\n break;\n case 'checkboxes':\n inputHtml = renderCheckboxesInput(field, value as CheckboxesValue | undefined, disabledAttr);\n break;\n case 'url':\n inputHtml = renderUrlInput(field, value, disabledAttr);\n break;\n case 'url_list':\n inputHtml = renderUrlListInput(field, value, disabledAttr);\n break;\n case 'date':\n inputHtml = renderDateInput(field, value, disabledAttr);\n break;\n case 'year':\n inputHtml = renderYearInput(field, value, disabledAttr);\n break;\n case 'table':\n inputHtml = renderTableInput(field, value as TableValue | undefined, disabledAttr);\n break;\n default: {\n // Exhaustiveness check - TypeScript will error if a case is missing\n const _exhaustive: never = field;\n throw new Error(`Unhandled field kind: ${(_exhaustive as { kind: string }).kind}`);\n }\n }\n\n // Add skip button for optional, non-skipped fields\n const skipButton =\n !field.required && !skipped\n ? `<div class=\"field-actions\">\n <button type=\"button\" class=\"btn-skip\" data-skip-field=\"${field.id}\">Skip</button>\n </div>`\n : '';\n\n return `\n <div class=\"${fieldClass}\">\n <label class=\"field-label\" for=\"field-${field.id}\">\n ${escapeHtml(field.label)} ${requiredMark} ${typeLabel} ${skippedBadge}\n </label>\n ${inputHtml}\n ${skipButton}\n </div>`;\n}\n\n/**\n * Render a string field as text input.\n */\nfunction renderStringInput(\n field: StringField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const currentValue = value?.kind === 'string' && value.value !== null ? value.value : '';\n const requiredAttr = field.required ? ' required' : '';\n const minLengthAttr = field.minLength !== undefined ? ` minlength=\"${field.minLength}\"` : '';\n const maxLengthAttr = field.maxLength !== undefined ? ` maxlength=\"${field.maxLength}\"` : '';\n const placeholderAttr = field.placeholder\n ? ` placeholder=\"${escapeHtml(field.placeholder)}\"`\n : '';\n\n return `<input type=\"text\" id=\"field-${field.id}\" name=\"${field.id}\" value=\"${escapeHtml(currentValue)}\"${requiredAttr}${minLengthAttr}${maxLengthAttr}${placeholderAttr}${disabledAttr}>`;\n}\n\n/**\n * Render a number field as number input.\n */\nfunction renderNumberInput(\n field: NumberField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const currentValue = value?.kind === 'number' && value.value !== null ? String(value.value) : '';\n const requiredAttr = field.required ? ' required' : '';\n const minAttr = field.min !== undefined ? ` min=\"${field.min}\"` : '';\n const maxAttr = field.max !== undefined ? ` max=\"${field.max}\"` : '';\n const stepAttr = field.integer ? ' step=\"1\"' : '';\n const placeholderAttr = field.placeholder\n ? ` placeholder=\"${escapeHtml(field.placeholder)}\"`\n : '';\n\n return `<input type=\"number\" id=\"field-${field.id}\" name=\"${field.id}\" value=\"${escapeHtml(currentValue)}\"${requiredAttr}${minAttr}${maxAttr}${stepAttr}${placeholderAttr}${disabledAttr}>`;\n}\n\n/**\n * Render a string list field as textarea.\n */\nfunction renderStringListInput(\n field: StringListField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const items = value?.kind === 'string_list' ? value.items : [];\n const currentValue = items.join('\\n');\n const requiredAttr = field.required ? ' required' : '';\n // Use field placeholder or default\n const placeholderText = field.placeholder\n ? `${escapeHtml(field.placeholder)} (one item per line)`\n : 'Enter one item per line';\n\n return `<textarea id=\"field-${field.id}\" name=\"${field.id}\" placeholder=\"${placeholderText}\"${requiredAttr}${disabledAttr}>${escapeHtml(currentValue)}</textarea>`;\n}\n\n/**\n * Render a URL field as url input.\n */\nfunction renderUrlInput(\n field: UrlField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const currentValue = value?.kind === 'url' && value.value !== null ? value.value : '';\n const requiredAttr = field.required ? ' required' : '';\n // Use field placeholder or default\n const placeholderText = field.placeholder ?? 'https://example.com';\n\n return `<input type=\"url\" id=\"field-${field.id}\" name=\"${field.id}\" value=\"${escapeHtml(currentValue)}\" placeholder=\"${escapeHtml(placeholderText)}\"${requiredAttr}${disabledAttr}>`;\n}\n\n/**\n * Render a URL list field as textarea.\n */\nfunction renderUrlListInput(\n field: UrlListField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const items = value?.kind === 'url_list' ? value.items : [];\n const currentValue = items.join('\\n');\n const requiredAttr = field.required ? ' required' : '';\n // Use field placeholder or default\n const placeholderText = field.placeholder\n ? `${escapeHtml(field.placeholder)} (one URL per line)`\n : 'Enter one URL per line';\n\n return `<textarea id=\"field-${field.id}\" name=\"${field.id}\" placeholder=\"${placeholderText}\"${requiredAttr}${disabledAttr}>${escapeHtml(currentValue)}</textarea>`;\n}\n\n/**\n * Render a date field as date input.\n */\nfunction renderDateInput(\n field: DateField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const currentValue = value?.kind === 'date' && value.value !== null ? value.value : '';\n const requiredAttr = field.required ? ' required' : '';\n const minAttr = field.min !== undefined ? ` min=\"${field.min}\"` : '';\n const maxAttr = field.max !== undefined ? ` max=\"${field.max}\"` : '';\n\n return `<input type=\"date\" id=\"field-${field.id}\" name=\"${field.id}\" value=\"${escapeHtml(currentValue)}\"${requiredAttr}${minAttr}${maxAttr}${disabledAttr}>`;\n}\n\n/**\n * Render a year field as number input.\n */\nfunction renderYearInput(\n field: YearField,\n value: FieldValue | undefined,\n disabledAttr: string,\n): string {\n const currentValue = value?.kind === 'year' && value.value !== null ? String(value.value) : '';\n const requiredAttr = field.required ? ' required' : '';\n const minAttr = field.min !== undefined ? ` min=\"${field.min}\"` : ' min=\"1000\"';\n const maxAttr = field.max !== undefined ? ` max=\"${field.max}\"` : ' max=\"2500\"';\n\n return `<input type=\"number\" id=\"field-${field.id}\" name=\"${field.id}\" value=\"${escapeHtml(currentValue)}\" step=\"1\" placeholder=\"YYYY\"${requiredAttr}${minAttr}${maxAttr}${disabledAttr}>`;\n}\n\n/**\n * Render a single-select field as select element.\n */\nfunction renderSingleSelectInput(\n field: SingleSelectField,\n value: SingleSelectValue | undefined,\n disabledAttr: string,\n): string {\n const selected = value?.selected ?? null;\n const requiredAttr = field.required ? ' required' : '';\n\n const options = field.options\n .map((opt) => {\n const isSelected = selected === opt.id;\n const selectedAttr = isSelected ? ' selected' : '';\n return `<option value=\"${escapeHtml(opt.id)}\"${selectedAttr}>${escapeHtml(opt.label)}</option>`;\n })\n .join('\\n ');\n\n return `<select id=\"field-${field.id}\" name=\"${field.id}\"${requiredAttr}${disabledAttr}>\n <option value=\"\">-- Select --</option>\n ${options}\n </select>`;\n}\n\n/**\n * Render a multi-select field as checkboxes.\n */\nfunction renderMultiSelectInput(\n field: MultiSelectField,\n value: MultiSelectValue | undefined,\n disabledAttr: string,\n): string {\n const selected = value?.selected ?? [];\n\n const checkboxes = field.options\n .map((opt) => {\n const isChecked = selected.includes(opt.id);\n const checkedAttr = isChecked ? ' checked' : '';\n const checkboxId = `field-${field.id}-${opt.id}`;\n return `<div class=\"checkbox-item\">\n <input type=\"checkbox\" id=\"${checkboxId}\" name=\"${field.id}\" value=\"${escapeHtml(opt.id)}\"${checkedAttr}${disabledAttr}>\n <label for=\"${checkboxId}\">${escapeHtml(opt.label)}</label>\n </div>`;\n })\n .join('\\n ');\n\n return `<div class=\"checkbox-group\">\n ${checkboxes}\n </div>`;\n}\n\n/**\n * Render checkboxes field based on mode.\n */\nfunction renderCheckboxesInput(\n field: CheckboxesField,\n value: CheckboxesValue | undefined,\n disabledAttr: string,\n): string {\n const checkboxValues = value?.values ?? {};\n const mode = field.checkboxMode ?? 'multi';\n\n if (mode === 'simple') {\n // Simple mode: render as HTML checkboxes\n const checkboxes = field.options\n .map((opt) => {\n const state = checkboxValues[opt.id];\n const isChecked = state === 'done';\n const checkedAttr = isChecked ? ' checked' : '';\n const checkboxId = `field-${field.id}-${opt.id}`;\n return `<div class=\"checkbox-item\">\n <input type=\"checkbox\" id=\"${checkboxId}\" name=\"${field.id}\" value=\"${escapeHtml(opt.id)}\"${checkedAttr}${disabledAttr}>\n <label for=\"${checkboxId}\">${escapeHtml(opt.label)}</label>\n </div>`;\n })\n .join('\\n ');\n\n return `<div class=\"checkbox-group\">\n ${checkboxes}\n </div>`;\n }\n\n if (mode === 'explicit') {\n // Explicit mode: render as select with yes/no/unfilled options\n const rows = field.options\n .map((opt) => {\n const state = checkboxValues[opt.id] ?? 'unfilled';\n const selectId = `field-${field.id}-${opt.id}`;\n const selectName = `${field.id}.${opt.id}`;\n\n return `<div class=\"option-row\">\n <span class=\"option-label\">${escapeHtml(opt.label)}</span>\n <select id=\"${selectId}\" name=\"${selectName}\"${disabledAttr}>\n <option value=\"unfilled\"${state === 'unfilled' ? ' selected' : ''}>-- Select --</option>\n <option value=\"yes\"${state === 'yes' ? ' selected' : ''}>Yes</option>\n <option value=\"no\"${state === 'no' ? ' selected' : ''}>No</option>\n </select>\n </div>`;\n })\n .join('\\n ');\n\n return `<div class=\"checkbox-group\">\n ${rows}\n </div>`;\n }\n\n // Multi mode: render as select with multiple state options\n const rows = field.options\n .map((opt) => {\n const state = checkboxValues[opt.id] ?? 'todo';\n const selectId = `field-${field.id}-${opt.id}`;\n const selectName = `${field.id}.${opt.id}`;\n\n return `<div class=\"option-row\">\n <span class=\"option-label\">${escapeHtml(opt.label)}</span>\n <select id=\"${selectId}\" name=\"${selectName}\"${disabledAttr}>\n <option value=\"todo\"${state === 'todo' ? ' selected' : ''}>To Do</option>\n <option value=\"active\"${state === 'active' ? ' selected' : ''}>Active</option>\n <option value=\"done\"${state === 'done' ? ' selected' : ''}>Done</option>\n <option value=\"incomplete\"${state === 'incomplete' ? ' selected' : ''}>Incomplete</option>\n <option value=\"na\"${state === 'na' ? ' selected' : ''}>N/A</option>\n </select>\n </div>`;\n })\n .join('\\n ');\n\n return `<div class=\"checkbox-group\">\n ${rows}\n </div>`;\n}\n\n/**\n * Render a table field as an HTML table.\n * Currently read-only display; editing requires more complex UI.\n */\nfunction renderTableInput(\n field: TableField,\n value: TableValue | undefined,\n _disabledAttr: string,\n): string {\n const rows = value?.rows ?? [];\n\n if (rows.length === 0) {\n return '<div class=\"field-help\">(no data)</div>';\n }\n\n // Build header row\n const headerHtml = field.columns.map((col) => `<th>${escapeHtml(col.label)}</th>`).join('');\n\n // Build data rows\n const dataRowsHtml = rows\n .map((row) => {\n const cellsHtml = field.columns\n .map((col) => {\n const cell = row[col.id];\n let cellValue = '';\n if (cell?.state === 'answered' && cell.value !== undefined && cell.value !== null) {\n cellValue = String(cell.value);\n } else if (cell?.state === 'skipped') {\n cellValue = cell.reason ? `[skipped: ${cell.reason}]` : '[skipped]';\n } else if (cell?.state === 'aborted') {\n cellValue = cell.reason ? `[aborted: ${cell.reason}]` : '[aborted]';\n }\n return `<td>${escapeHtml(cellValue)}</td>`;\n })\n .join('');\n return `<tr>${cellsHtml}</tr>`;\n })\n .join('\\n ');\n\n return `<div class=\"table-container\">\n <table class=\"data-table\">\n <thead>\n <tr>${headerHtml}</tr>\n </thead>\n <tbody>\n ${dataRowsHtml}\n </tbody>\n </table>\n <div class=\"field-help\">(table fields are currently read-only in the web UI)</div>\n </div>`;\n}\n\n/**\n * Escape HTML special characters.\n * @public Exported for testing.\n */\nexport function escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\n// =============================================================================\n// Read-only Renderers for non-form file types\n// =============================================================================\n\n/** Common styles for read-only viewers */\nconst READ_ONLY_STYLES = `\n * { box-sizing: border-box; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n line-height: 1.6;\n max-width: 900px;\n margin: 0 auto;\n padding: 2rem;\n background: #f8f9fa;\n color: #212529;\n }\n h1 { color: #495057; border-bottom: 2px solid #dee2e6; padding-bottom: 0.5rem; font-size: 1.5rem; }\n .content {\n background: white;\n border-radius: 8px;\n padding: 1.5rem;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n pre {\n background: #f8f9fa;\n color: #24292e;\n padding: 1rem;\n border-radius: 6px;\n border: 1px solid #e1e4e8;\n overflow-x: auto;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: 0.9rem;\n line-height: 1.5;\n }\n /* Light theme syntax highlighting */\n .syn-key { color: #005cc5; }\n .syn-string { color: #22863a; }\n .syn-number { color: #005cc5; }\n .syn-bool { color: #d73a49; }\n .syn-null { color: #d73a49; }\n .syn-comment { color: #6a737d; font-style: italic; }\n .badge {\n font-size: 0.75rem;\n padding: 0.2rem 0.5rem;\n background: #e9ecef;\n border-radius: 4px;\n color: #6c757d;\n margin-left: 0.75rem;\n font-weight: normal;\n }\n`;\n\n/**\n * Render markdown content as read-only HTML.\n * Simple rendering without full markdown parsing.\n */\nfunction renderMarkdownHtml(content: string, filename: string): string {\n // Simple markdown-to-html conversion (headers and paragraphs)\n const lines = content.split('\\n');\n let html = '';\n let inParagraph = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (trimmed.startsWith('# ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n html += `<h2>${escapeHtml(trimmed.slice(2))}</h2>`;\n } else if (trimmed.startsWith('## ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n html += `<h3>${escapeHtml(trimmed.slice(3))}</h3>`;\n } else if (trimmed.startsWith('### ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n html += `<h4>${escapeHtml(trimmed.slice(4))}</h4>`;\n } else if (trimmed === '') {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n } else {\n if (!inParagraph) {\n html += '<p>';\n inParagraph = true;\n } else {\n html += '<br>';\n }\n html += escapeHtml(trimmed);\n }\n }\n\n if (inParagraph) {\n html += '</p>';\n }\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(filename)} - Markform Viewer</title>\n <style>${READ_ONLY_STYLES}\n h2 { color: #495057; font-size: 1.3rem; margin-top: 1.5rem; }\n h3 { color: #6c757d; font-size: 1.1rem; margin-top: 1.25rem; }\n h4 { color: #6c757d; font-size: 1rem; margin-top: 1rem; }\n p { margin: 0.75rem 0; }\n </style>\n</head>\n<body>\n <h1>${escapeHtml(filename)}<span class=\"badge\">Markdown</span></h1>\n <div class=\"content\">\n ${html}\n </div>\n</body>\n</html>`;\n}\n\n/**\n * Render YAML content with syntax highlighting.\n */\nfunction renderYamlHtml(content: string, filename: string): string {\n // YAML syntax highlighting using CSS classes\n const highlighted = content\n .split('\\n')\n .map((line) => {\n // Highlight comments\n if (line.trim().startsWith('#')) {\n return `<span class=\"syn-comment\">${escapeHtml(line)}</span>`;\n }\n // Highlight keys (before colon)\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0 && !line.trim().startsWith('-')) {\n const key = escapeHtml(line.slice(0, colonIndex));\n const afterColon = line.slice(colonIndex + 1).trim();\n const colonAndSpace = escapeHtml(line.slice(colonIndex, colonIndex + 1));\n // Highlight the value based on type\n if (afterColon === '') {\n return `<span class=\"syn-key\">${key}</span>${colonAndSpace}`;\n }\n const valueStart = line.indexOf(afterColon, colonIndex);\n const beforeValue = escapeHtml(line.slice(colonIndex, valueStart));\n const value = highlightYamlValue(afterColon);\n return `<span class=\"syn-key\">${key}</span>${beforeValue}${value}`;\n }\n // List items\n if (line.trim().startsWith('-')) {\n const dashIndex = line.indexOf('-');\n const beforeDash = escapeHtml(line.slice(0, dashIndex));\n const afterDash = line.slice(dashIndex + 1).trim();\n if (afterDash === '') {\n return `${beforeDash}-`;\n }\n return `${beforeDash}- ${highlightYamlValue(afterDash)}`;\n }\n return escapeHtml(line);\n })\n .join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(filename)} - Markform Viewer</title>\n <style>${READ_ONLY_STYLES}</style>\n</head>\n<body>\n <h1>${escapeHtml(filename)}<span class=\"badge\">YAML</span></h1>\n <div class=\"content\">\n <pre>${highlighted}</pre>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * Highlight a YAML value based on its type.\n */\nfunction highlightYamlValue(value: string): string {\n const trimmed = value.trim();\n // Booleans\n if (trimmed === 'true' || trimmed === 'false') {\n return `<span class=\"syn-bool\">${escapeHtml(value)}</span>`;\n }\n // Null\n if (trimmed === 'null' || trimmed === '~') {\n return `<span class=\"syn-null\">${escapeHtml(value)}</span>`;\n }\n // Numbers\n if (/^-?\\d+\\.?\\d*$/.test(trimmed)) {\n return `<span class=\"syn-number\">${escapeHtml(value)}</span>`;\n }\n // Quoted strings\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return `<span class=\"syn-string\">${escapeHtml(value)}</span>`;\n }\n // Unquoted strings (treat as string)\n return `<span class=\"syn-string\">${escapeHtml(value)}</span>`;\n}\n\n/**\n * Render JSON content with syntax highlighting and formatting.\n */\nfunction renderJsonHtml(content: string, filename: string): string {\n // Try to pretty-print JSON\n let formatted: string;\n try {\n const parsed = JSON.parse(content) as unknown;\n formatted = JSON.stringify(parsed, null, 2);\n } catch {\n formatted = content;\n }\n\n // JSON syntax highlighting using CSS classes\n const highlighted = formatted\n .replace(/\"([^\"]+)\":/g, '<span class=\"syn-key\">\"$1\"</span>:')\n .replace(/: \"([^\"]*)\"/g, ': <span class=\"syn-string\">\"$1\"</span>')\n .replace(/: (-?\\d+\\.?\\d*)/g, ': <span class=\"syn-number\">$1</span>')\n .replace(/: (true|false)/g, ': <span class=\"syn-bool\">$1</span>')\n .replace(/: (null)/g, ': <span class=\"syn-null\">$1</span>');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(filename)} - Markform Viewer</title>\n <style>${READ_ONLY_STYLES}</style>\n</head>\n<body>\n <h1>${escapeHtml(filename)}<span class=\"badge\">JSON</span></h1>\n <div class=\"content\">\n <pre>${highlighted}</pre>\n </div>\n</body>\n</html>`;\n}\n\n/**\n * Render plain text content.\n */\nfunction renderPlainTextHtml(content: string, filename: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(filename)} - Markform Viewer</title>\n <style>${READ_ONLY_STYLES}</style>\n</head>\n<body>\n <h1>${escapeHtml(filename)}<span class=\"badge\">Text</span></h1>\n <div class=\"content\">\n <pre>${escapeHtml(content)}</pre>\n </div>\n</body>\n</html>`;\n}\n\n// =============================================================================\n// Content-only Renderers (for tab content)\n// =============================================================================\n\n/**\n * Render form view content (read-only display of form fields).\n * Used for View tab content.\n * @public Exported for testing.\n */\nexport function renderViewContent(form: ParsedForm): string {\n const { schema, responsesByFieldId } = form;\n let html = '<div class=\"view-content\">';\n\n for (const group of schema.groups) {\n const groupTitle = group.title ?? group.id;\n html += `<div class=\"view-group\"><h2>${escapeHtml(groupTitle)}</h2>`;\n\n for (const field of group.children) {\n const response = responsesByFieldId[field.id];\n const value = response?.state === 'answered' ? response.value : undefined;\n const isSkipped = response?.state === 'skipped';\n\n html += '<div class=\"view-field\">';\n html += `<div class=\"view-field-label\">${escapeHtml(field.label)}`;\n html += ` <span class=\"type-badge\">${field.kind}</span>`;\n if (field.required) {\n html += ' <span class=\"required\">*</span>';\n }\n if (isSkipped) {\n html += ' <span class=\"skipped-badge\">Skipped</span>';\n }\n html += '</div>';\n\n // Render value based on field type\n html += renderViewFieldValue(field, value, isSkipped);\n html += '</div>';\n }\n\n html += '</div>';\n }\n\n html += '</div>';\n return html;\n}\n\n/**\n * Format a checkbox state for display.\n */\nfunction formatCheckboxState(state: string): string {\n switch (state) {\n case 'done':\n return '<span class=\"checkbox checked\">☑</span>';\n case 'todo':\n return '<span class=\"checkbox unchecked\">☐</span>';\n case 'active':\n return '<span class=\"state-badge state-active\">●</span>';\n case 'incomplete':\n return '<span class=\"state-badge state-incomplete\">○</span>';\n case 'na':\n return '<span class=\"state-badge state-na\">—</span>';\n case 'yes':\n return '<span class=\"checkbox checked\">☑</span>';\n case 'no':\n return '<span class=\"checkbox unchecked\">☐</span>';\n case 'unfilled':\n return '<span class=\"state-badge state-unfilled\">?</span>';\n default:\n return `<span class=\"state-badge\">${escapeHtml(state)}</span>`;\n }\n}\n\n/**\n * Render a field value for the View tab.\n */\nfunction renderViewFieldValue(\n field: Field,\n value: FieldValue | undefined,\n isSkipped: boolean,\n): string {\n if (isSkipped) {\n return '<div class=\"view-field-empty\">(skipped)</div>';\n }\n\n if (value === undefined) {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n\n switch (field.kind) {\n case 'string': {\n const v = value.kind === 'string' ? value.value : null;\n if (v === null || v === '') {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n // Auto-link bare URLs in string content for consistency with URL fields\n const formatted = formatBareUrlsAsHtmlLinks(v, escapeHtml);\n return `<div class=\"view-field-value\">${formatted}</div>`;\n }\n case 'number': {\n const v = value.kind === 'number' ? value.value : null;\n if (v === null) {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n return `<div class=\"view-field-value\">${v}</div>`;\n }\n case 'string_list': {\n const items = value.kind === 'string_list' ? value.items : [];\n if (items.length === 0) {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n // Auto-link bare URLs in string list items\n return `<div class=\"view-field-value\"><ul>${items.map((i) => `<li>${formatBareUrlsAsHtmlLinks(i, escapeHtml)}</li>`).join('')}</ul></div>`;\n }\n case 'single_select': {\n const selected = value.kind === 'single_select' ? value.selected : null;\n if (selected === null) {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n const opt = field.options.find((o) => o.id === selected);\n return `<div class=\"view-field-value\">${escapeHtml(opt?.label ?? selected)}</div>`;\n }\n case 'multi_select': {\n const selected = value.kind === 'multi_select' ? value.selected : [];\n // Show all options with selection state\n const items = field.options.map((opt) => {\n const isSelected = selected.includes(opt.id);\n const checkbox = isSelected\n ? '<span class=\"checkbox checked\">☑</span>'\n : '<span class=\"checkbox unchecked\">☐</span>';\n return `<li class=\"checkbox-item\">${checkbox} ${escapeHtml(opt.label)}</li>`;\n });\n return `<div class=\"view-field-value\"><ul class=\"checkbox-list\">${items.join('')}</ul></div>`;\n }\n case 'checkboxes': {\n const values = value.kind === 'checkboxes' ? value.values : {};\n const mode = field.checkboxMode ?? 'multi';\n // Show all options with their state\n const items = field.options.map((opt) => {\n const state = values[opt.id] ?? (mode === 'explicit' ? 'unfilled' : 'todo');\n // For simple mode, use checkbox symbols\n if (mode === 'simple') {\n const checkbox =\n state === 'done'\n ? '<span class=\"checkbox checked\">☑</span>'\n : '<span class=\"checkbox unchecked\">☐</span>';\n return `<li class=\"checkbox-item\">${checkbox} ${escapeHtml(opt.label)}</li>`;\n }\n // For multi/explicit modes, show state text since there are multiple states\n const stateDisplay = formatCheckboxState(state);\n return `<li class=\"checkbox-item\">${stateDisplay} ${escapeHtml(opt.label)}</li>`;\n });\n return `<div class=\"view-field-value\"><ul class=\"checkbox-list\">${items.join('')}</ul></div>`;\n }\n case 'url': {\n const v = value.kind === 'url' ? value.value : null;\n if (v === null || v === '') {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n const domain = friendlyUrlAbbrev(v);\n return `<div class=\"view-field-value\"><a href=\"${escapeHtml(v)}\" target=\"_blank\" class=\"url-link\" data-url=\"${escapeHtml(v)}\">${escapeHtml(domain)}</a></div>`;\n }\n case 'url_list': {\n const items = value.kind === 'url_list' ? value.items : [];\n if (items.length === 0) {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n return `<div class=\"view-field-value\"><ul>${items\n .map((u) => {\n const domain = friendlyUrlAbbrev(u);\n return `<li><a href=\"${escapeHtml(u)}\" target=\"_blank\" class=\"url-link\" data-url=\"${escapeHtml(u)}\">${escapeHtml(domain)}</a></li>`;\n })\n .join('')}</ul></div>`;\n }\n case 'date': {\n const v = value.kind === 'date' ? value.value : null;\n if (v === null || v === '') {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n return `<div class=\"view-field-value\">${escapeHtml(v)}</div>`;\n }\n case 'year': {\n const v = value.kind === 'year' ? value.value : null;\n if (v === null) {\n return '<div class=\"view-field-empty\">(not filled)</div>';\n }\n return `<div class=\"view-field-value\">${v}</div>`;\n }\n case 'table': {\n const rows = value.kind === 'table' ? value.rows : [];\n if (rows.length === 0) {\n return '<div class=\"view-field-empty\">(no data)</div>';\n }\n let tableHtml = '<div class=\"table-container\"><table class=\"data-table\">';\n tableHtml += '<thead><tr>';\n for (const col of field.columns) {\n tableHtml += `<th>${escapeHtml(col.label)}</th>`;\n }\n tableHtml += '</tr></thead><tbody>';\n for (const row of rows) {\n tableHtml += '<tr>';\n for (const col of field.columns) {\n const cell = row[col.id];\n let cellValue = '';\n let cellHtml = '';\n if (cell?.state === 'answered' && cell.value !== undefined && cell.value !== null) {\n cellValue = String(cell.value);\n // Format URL columns as domain links\n if (col.type === 'url' && cellValue) {\n const domain = friendlyUrlAbbrev(cellValue);\n cellHtml = `<a href=\"${escapeHtml(cellValue)}\" target=\"_blank\" class=\"url-link\" data-url=\"${escapeHtml(cellValue)}\">${escapeHtml(domain)}</a>`;\n } else {\n // Auto-link bare URLs in non-URL columns for consistency\n cellHtml = formatBareUrlsAsHtmlLinks(cellValue, escapeHtml);\n }\n }\n tableHtml += `<td>${cellHtml}</td>`;\n }\n tableHtml += '</tr>';\n }\n tableHtml += '</tbody></table></div>';\n return tableHtml;\n }\n default: {\n const _exhaustive: never = field;\n throw new Error(`Unhandled field kind: ${(_exhaustive as { kind: string }).kind}`);\n }\n }\n}\n\n/**\n * Render source content with Markdown and Jinja syntax highlighting.\n * Used for Source tab content.\n * @public Exported for testing.\n */\nexport function renderSourceContent(content: string): string {\n const lines = content.split('\\n');\n const highlighted = lines.map((line) => highlightSourceLine(line)).join('\\n');\n return `<pre>${highlighted}</pre>`;\n}\n\n/**\n * Highlight a single line of source code (Markdown + Jinja).\n */\nfunction highlightSourceLine(line: string): string {\n // First escape HTML\n let result = escapeHtml(line);\n\n // Highlight Jinja tags: {% tag %}, {% /tag %}, {# comment #}\n // Match {% ... %} patterns\n result = result.replace(\n /(\\{%\\s*)([a-zA-Z_/]+)(\\s+[^%]*)?(%\\})/g,\n (_: string, open: string, keyword: string, attrs: string | undefined, close: string) => {\n let attrHtml = '';\n if (attrs) {\n // Highlight attributes within the tag\n attrHtml = attrs.replace(\n /([a-zA-Z_]+)(=)(\"[^\"]*\"|&#039;[^&#]*&#039;|[^\\s%]+)?/g,\n (_m: string, attrName: string, eq: string, attrValue: string) => {\n const valueHtml = attrValue ? `<span class=\"syn-jinja-value\">${attrValue}</span>` : '';\n return `<span class=\"syn-jinja-attr\">${attrName}</span>${eq}${valueHtml}`;\n },\n );\n }\n return `<span class=\"syn-jinja-tag\">${open}</span><span class=\"syn-jinja-keyword\">${keyword}</span>${attrHtml}<span class=\"syn-jinja-tag\">${close}</span>`;\n },\n );\n\n // Highlight Jinja comments: {# ... #}\n result = result.replace(/(\\{#)(.*?)(#\\})/g, `<span class=\"syn-comment\">$1$2$3</span>`);\n\n // Highlight Markdown headers\n result = result.replace(/^(#{1,6}\\s.*)$/gm, '<span class=\"syn-md-header\">$1</span>');\n\n // Highlight YAML frontmatter markers\n if (result === '---') {\n result = '<span class=\"syn-comment\">---</span>';\n }\n\n return result;\n}\n\n/**\n * Render markdown content (content only, no page wrapper).\n * Used for tab content.\n * @public Exported for testing.\n */\nexport function renderMarkdownContent(content: string): string {\n const lines = content.split('\\n');\n let html = '<div class=\"markdown-content\">';\n let inParagraph = false;\n let inCodeBlock = false;\n let codeBlockContent = '';\n let inUnorderedList = false;\n let inOrderedList = false;\n let inTable = false;\n let tableHeaderDone = false;\n\n // Helper to close any open list\n const closeList = () => {\n if (inUnorderedList) {\n html += '</ul>';\n inUnorderedList = false;\n }\n if (inOrderedList) {\n html += '</ol>';\n inOrderedList = false;\n }\n };\n\n // Helper to close table\n const closeTable = () => {\n if (inTable) {\n html += '</tbody></table></div>';\n inTable = false;\n tableHeaderDone = false;\n }\n };\n\n // Helper to detect if a line is a table row\n const isTableRow = (line: string): boolean => {\n const trimmed = line.trim();\n return trimmed.startsWith('|') && trimmed.endsWith('|') && trimmed.includes('|');\n };\n\n // Helper to detect table separator line (| --- | --- |)\n const isTableSeparator = (line: string): boolean => {\n const trimmed = line.trim();\n return /^\\|[\\s-:|]+\\|$/.test(trimmed);\n };\n\n // Helper to parse table cells\n const parseTableCells = (line: string): string[] => {\n const trimmed = line.trim();\n // Remove leading and trailing pipes, then split by pipes\n const content = trimmed.slice(1, -1);\n return content.split('|').map((cell) => cell.trim());\n };\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Handle fenced code blocks\n if (trimmed.startsWith('```')) {\n if (inCodeBlock) {\n // End code block\n html += `<pre><code>${escapeHtml(codeBlockContent.trim())}</code></pre>`;\n codeBlockContent = '';\n inCodeBlock = false;\n } else {\n // Start code block\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n closeTable();\n inCodeBlock = true;\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeBlockContent += line + '\\n';\n continue;\n }\n\n // Handle table rows\n if (isTableRow(trimmed)) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n\n // Skip separator line but mark header as done\n if (isTableSeparator(trimmed)) {\n tableHeaderDone = true;\n continue;\n }\n\n const cells = parseTableCells(trimmed);\n\n if (!inTable) {\n // Start new table with header\n html += '<div class=\"table-container\"><table class=\"data-table\"><thead><tr>';\n for (const cell of cells) {\n html += `<th>${formatInlineMarkdown(cell)}</th>`;\n }\n html += '</tr></thead><tbody>';\n inTable = true;\n } else if (tableHeaderDone) {\n // Regular table row\n html += '<tr>';\n for (const cell of cells) {\n html += `<td>${formatInlineMarkdown(cell)}</td>`;\n }\n html += '</tr>';\n }\n continue;\n }\n\n // Close table if we hit a non-table line\n if (inTable && !isTableRow(trimmed)) {\n closeTable();\n }\n\n // Handle headers\n if (trimmed.startsWith('# ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n html += `<h2>${formatInlineMarkdown(trimmed.slice(2))}</h2>`;\n } else if (trimmed.startsWith('## ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n html += `<h3>${formatInlineMarkdown(trimmed.slice(3))}</h3>`;\n } else if (trimmed.startsWith('### ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n html += `<h4>${formatInlineMarkdown(trimmed.slice(4))}</h4>`;\n } else if (trimmed.startsWith('#### ')) {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n html += `<h5>${formatInlineMarkdown(trimmed.slice(5))}</h5>`;\n } else if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {\n // Unordered list item\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n if (inOrderedList) {\n html += '</ol>';\n inOrderedList = false;\n }\n if (!inUnorderedList) {\n html += '<ul>';\n inUnorderedList = true;\n }\n const itemContent = trimmed.slice(2);\n // If item starts with checkbox, use no-bullet class\n const hasCheckbox = /^\\[[ xX]\\]/.test(itemContent);\n const liClass = hasCheckbox ? ' class=\"checkbox-item\"' : '';\n html += `<li${liClass}>${formatInlineMarkdown(itemContent)}</li>`;\n } else if (/^\\d+\\.\\s/.test(trimmed)) {\n // Ordered list item\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n if (inUnorderedList) {\n html += '</ul>';\n inUnorderedList = false;\n }\n if (!inOrderedList) {\n html += '<ol>';\n inOrderedList = true;\n }\n const text = trimmed.replace(/^\\d+\\.\\s/, '');\n html += `<li>${formatInlineMarkdown(text)}</li>`;\n } else if (trimmed === '') {\n if (inParagraph) {\n html += '</p>';\n inParagraph = false;\n }\n closeList();\n } else {\n closeList();\n if (!inParagraph) {\n html += '<p>';\n inParagraph = true;\n } else {\n html += '<br>';\n }\n html += formatInlineMarkdown(trimmed);\n }\n }\n\n if (inParagraph) {\n html += '</p>';\n }\n closeList();\n closeTable();\n\n html += '</div>';\n return html;\n}\n\n/**\n * Format inline markdown (bold, italic, code, links, checkboxes).\n * Also auto-links bare URLs for consistency.\n */\nfunction formatInlineMarkdown(text: string): string {\n let result = escapeHtml(text);\n // Checkboxes - render before other formatting to avoid conflicts\n // Checked checkbox [x] or [X]\n result = result.replace(/\\[x\\]/gi, '<span class=\"checkbox checked\">☑</span>');\n // Unchecked checkbox [ ]\n result = result.replace(/\\[ \\]/g, '<span class=\"checkbox unchecked\">☐</span>');\n // Inline code\n result = result.replace(/`([^`]+)`/g, '<code>$1</code>');\n // Bold\n result = result.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n // Italic\n result = result.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n // Links - need to unescape the URL first\n // Add url-link class and data-url for copy tooltip support\n result = result.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_: string, linkText: string, url: string) => {\n const cleanUrl = url.replace(/&amp;/g, '&');\n return `<a href=\"${cleanUrl}\" target=\"_blank\" class=\"url-link\" data-url=\"${cleanUrl}\">${linkText}</a>`;\n },\n );\n // Auto-link bare URLs (not already in <a> tags or markdown links)\n // Uses negative lookbehind to skip URLs that are:\n // - Inside href=\"\" or data-url=\"\" attributes\n // - Inside anchor tag content (preceded by \">)\n // - Part of markdown link syntax ](\n result = result.replace(\n /(?<!href=\"|data-url=\"|\">|\\]\\()(?:https?:\\/\\/|www\\.)[^\\s<>\"]+(?<![.,;:!?'\")])/g,\n (url: string) => {\n // Unescape &amp; back to & for the URL\n const cleanUrl = url.replace(/&amp;/g, '&');\n const fullUrl = cleanUrl.startsWith('www.') ? `https://${cleanUrl}` : cleanUrl;\n const display = friendlyUrlAbbrev(fullUrl);\n return `<a href=\"${escapeHtml(fullUrl)}\" target=\"_blank\" class=\"url-link\" data-url=\"${escapeHtml(fullUrl)}\">${escapeHtml(display)}</a>`;\n },\n );\n return result;\n}\n\n/**\n * Render YAML content (content only, no page wrapper).\n * Used for tab content.\n * @public Exported for testing.\n */\nexport function renderYamlContent(content: string): string {\n const highlighted = content\n .split('\\n')\n .map((line) => {\n if (line.trim().startsWith('#')) {\n return `<span class=\"syn-comment\">${escapeHtml(line)}</span>`;\n }\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0 && !line.trim().startsWith('-')) {\n const key = escapeHtml(line.slice(0, colonIndex));\n const afterColon = line.slice(colonIndex + 1).trim();\n const colonAndSpace = escapeHtml(line.slice(colonIndex, colonIndex + 1));\n if (afterColon === '') {\n return `<span class=\"syn-key\">${key}</span>${colonAndSpace}`;\n }\n const valueStart = line.indexOf(afterColon, colonIndex);\n const beforeValue = escapeHtml(line.slice(colonIndex, valueStart));\n const value = highlightYamlValue(afterColon);\n return `<span class=\"syn-key\">${key}</span>${beforeValue}${value}`;\n }\n if (line.trim().startsWith('-')) {\n const dashIndex = line.indexOf('-');\n const beforeDash = escapeHtml(line.slice(0, dashIndex));\n const afterDash = line.slice(dashIndex + 1).trim();\n if (afterDash === '') {\n return `${beforeDash}-`;\n }\n return `${beforeDash}- ${highlightYamlValue(afterDash)}`;\n }\n return escapeHtml(line);\n })\n .join('\\n');\n\n return `<pre>${highlighted}</pre>`;\n}\n\n/**\n * Render JSON content (content only, no page wrapper).\n * Used for tab content.\n * @public Exported for testing.\n */\nexport function renderJsonContent(content: string): string {\n let formatted: string;\n try {\n const parsed = JSON.parse(content) as unknown;\n formatted = JSON.stringify(parsed, null, 2);\n } catch {\n formatted = content;\n }\n\n const highlighted = formatted\n .replace(/\"([^\"]+)\":/g, '<span class=\"syn-key\">\"$1\"</span>:')\n .replace(/: \"([^\"]*)\"/g, ': <span class=\"syn-string\">\"$1\"</span>')\n .replace(/: (-?\\d+\\.?\\d*)/g, ': <span class=\"syn-number\">$1</span>')\n .replace(/: (true|false)/g, ': <span class=\"syn-bool\">$1</span>')\n .replace(/: (null)/g, ': <span class=\"syn-null\">$1</span>');\n\n return `<pre>${highlighted}</pre>`;\n}\n\n/**\n * Format milliseconds as human-readable duration.\n * @public Exported for reuse in other visualizations.\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${ms.toFixed(0)}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n const minutes = Math.floor(ms / 60000);\n const seconds = ((ms % 60000) / 1000).toFixed(0);\n return `${minutes}m ${seconds}s`;\n}\n\n/**\n * Format token count with K suffix for large numbers.\n * @public Exported for reuse in other visualizations.\n */\nexport function formatTokens(count: number): string {\n if (count >= 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count >= 1000) return `${(count / 1000).toFixed(1)}k`;\n return count.toLocaleString();\n}\n\n/**\n * Format a patch value for display.\n * Shows full content - the container has max-height with scroll for long values.\n */\nfunction formatPatchValue(value: unknown): string {\n if (value === null || value === undefined) {\n return '<em class=\"fr-turn__patch-value--clear\">(cleared)</em>';\n }\n if (typeof value === 'string') {\n return escapeHtml(value);\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n // Arrays and objects - show full JSON\n return escapeHtml(JSON.stringify(value, null, 2));\n}\n\n/**\n * Render patches from a fill_form tool call input.\n * Returns HTML for the patch details section.\n */\nfunction renderPatchDetails(input: Record<string, unknown>): string {\n const patches = input.patches;\n if (!Array.isArray(patches) || patches.length === 0) {\n return '';\n }\n\n const patchHtml = patches\n .map((patch: unknown) => {\n if (!patch || typeof patch !== 'object') return '';\n const p = patch as Record<string, unknown>;\n const op = typeof p.op === 'string' ? p.op : 'unknown';\n const fieldId =\n typeof p.fieldId === 'string' ? p.fieldId : typeof p.noteId === 'string' ? p.noteId : '';\n\n // Determine the display based on operation type\n const opLabel = op.replace(/_/g, ' ');\n let valueHtml = '';\n\n if (op === 'skip_field') {\n valueHtml = '<em class=\"fr-turn__patch-value--skip\">(skipped)</em>';\n } else if (op === 'abort_field') {\n valueHtml = '<em class=\"fr-turn__patch-value--skip\">(aborted)</em>';\n } else if (op === 'clear_field') {\n valueHtml = '<em class=\"fr-turn__patch-value--clear\">(cleared)</em>';\n } else if ('value' in p) {\n valueHtml = formatPatchValue(p.value);\n } else if ('values' in p) {\n valueHtml = formatPatchValue(p.values);\n } else if ('rows' in p) {\n valueHtml = formatPatchValue(p.rows);\n }\n\n return `\n <div class=\"fr-turn__patch\">\n <span class=\"fr-turn__patch-field\">${escapeHtml(fieldId)}</span>\n <span class=\"fr-turn__patch-op\">${escapeHtml(opLabel)}</span>\n <span class=\"fr-turn__patch-value\">${valueHtml}</span>\n </div>\n `;\n })\n .filter(Boolean)\n .join('');\n\n return `<div class=\"fr-turn__patches\">${patchHtml}</div>`;\n}\n\n/**\n * Render a single tool call with enhanced details.\n * Shows query for web_search, patch details for fill_form.\n */\nfunction renderToolCall(tc: {\n tool: string;\n success: boolean;\n durationMs: number;\n input: Record<string, unknown>;\n result?: { error?: string; resultCount?: number };\n}): string {\n const hasError = !!tc.result?.error;\n const icon = tc.success ? '✓' : '✕';\n const errorClass = hasError ? ' fr-turn__tool--error' : '';\n\n // Build result summary\n let resultSummary = '';\n if (hasError) {\n resultSummary = `Error: ${escapeHtml(tc.result?.error ?? '')}`;\n } else if (tc.result?.resultCount !== undefined) {\n resultSummary = `${tc.result.resultCount} results`;\n } else {\n resultSummary = 'OK';\n }\n\n // Build tool-specific details\n let detailHtml = '';\n if (tc.tool === 'web_search' && typeof tc.input.query === 'string') {\n const query = escapeHtml(tc.input.query);\n detailHtml = ` <span class=\"fr-turn__query\">\"${query}\"</span>`;\n }\n\n // Base tool call line\n const toolLine = `<li class=\"fr-turn__tool${errorClass}\">${icon} <strong>${escapeHtml(tc.tool)}</strong>${detailHtml}: ${resultSummary} (${formatDuration(tc.durationMs)})</li>`;\n\n // For fill_form, add patch details\n if (tc.tool === 'fill_form' && tc.input.patches) {\n const patchDetails = renderPatchDetails(tc.input);\n if (patchDetails) {\n return toolLine + patchDetails;\n }\n }\n\n return toolLine;\n}\n\n/**\n * CSS styles for fill record visualization.\n * Uses CSS custom properties for theming (supports dark mode via prefers-color-scheme).\n * Designed to be lightweight, reusable, and embeddable.\n */\nconst FILL_RECORD_STYLES = `\n<style>\n .fr-dashboard {\n --fr-bg: #ffffff;\n --fr-bg-muted: #f9fafb;\n --fr-bg-subtle: #f3f4f6;\n --fr-border: #e5e7eb;\n --fr-text: #111827;\n --fr-text-muted: #6b7280;\n --fr-primary: #3b82f6;\n --fr-success: #22c55e;\n --fr-warning: #f59e0b;\n --fr-error: #ef4444;\n --fr-info: #6b7280;\n\n /* Typography - consolidated to fewer sizes */\n --fr-font-sm: 13px;\n --fr-font-base: 14px;\n --fr-font-lg: 20px;\n\n font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n padding: 20px;\n max-width: 900px;\n margin: 0 auto;\n color: var(--fr-text);\n line-height: 1.5;\n }\n\n @media (prefers-color-scheme: dark) {\n .fr-dashboard {\n --fr-bg: #1f2937;\n --fr-bg-muted: #374151;\n --fr-bg-subtle: #4b5563;\n --fr-border: #4b5563;\n --fr-text: #f9fafb;\n --fr-text-muted: #9ca3af;\n }\n }\n\n .fr-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n padding-bottom: 12px;\n border-bottom: 1px solid var(--fr-border);\n }\n .fr-header__model {\n font-weight: 600;\n font-size: var(--fr-font-base);\n color: var(--fr-text);\n }\n .fr-header__time {\n font-weight: 600;\n font-size: var(--fr-font-base);\n color: var(--fr-text);\n }\n\n .fr-banner {\n border-radius: 8px;\n padding: 12px 16px;\n margin-bottom: 20px;\n font-size: var(--fr-font-base);\n }\n .fr-banner--error {\n background: color-mix(in srgb, var(--fr-error) 10%, var(--fr-bg));\n border: 1px solid var(--fr-error);\n }\n .fr-banner--warning {\n background: color-mix(in srgb, var(--fr-warning) 10%, var(--fr-bg));\n border: 1px solid var(--fr-warning);\n }\n\n .fr-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n margin-bottom: 24px;\n }\n\n .fr-card {\n padding: 16px;\n background: var(--fr-bg-muted);\n border-radius: 8px;\n text-align: center;\n }\n .fr-card__label {\n font-size: var(--fr-font-sm);\n color: var(--fr-text-muted);\n margin-bottom: 4px;\n }\n .fr-card__value {\n font-size: var(--fr-font-lg);\n font-weight: 600;\n }\n .fr-card__sub {\n font-size: var(--fr-font-sm);\n color: var(--fr-text-muted);\n margin-top: 2px;\n }\n\n .fr-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border-radius: 4px;\n font-weight: 600;\n font-size: var(--fr-font-sm);\n }\n .fr-badge--completed { background: color-mix(in srgb, var(--fr-success) 15%, transparent); color: var(--fr-success); }\n .fr-badge--partial { background: color-mix(in srgb, var(--fr-warning) 15%, transparent); color: var(--fr-warning); }\n .fr-badge--cancelled { background: color-mix(in srgb, var(--fr-info) 15%, transparent); color: var(--fr-info); }\n .fr-badge--failed { background: color-mix(in srgb, var(--fr-error) 15%, transparent); color: var(--fr-error); }\n\n .fr-section {\n margin-bottom: 24px;\n }\n .fr-section__title {\n font-size: var(--fr-font-base);\n font-weight: 500;\n color: var(--fr-text);\n margin-bottom: 8px;\n }\n\n .fr-progress {\n background: var(--fr-border);\n border-radius: 4px;\n height: 20px;\n overflow: hidden;\n }\n .fr-progress__bar {\n background: var(--fr-primary);\n height: 100%;\n transition: width 0.3s ease;\n }\n .fr-progress__text {\n font-size: var(--fr-font-sm);\n color: var(--fr-text-muted);\n margin-top: 4px;\n }\n\n .fr-progress__segments {\n display: flex;\n height: 100%;\n width: 100%;\n }\n .fr-progress-segment {\n height: 100%;\n min-width: 2px;\n border-right: 2px solid var(--fr-bg);\n cursor: pointer;\n }\n .fr-progress-segment:last-child {\n border-right: none;\n }\n .fr-progress-segment--filled {\n background: var(--fr-primary);\n }\n .fr-progress-segment--filled:hover {\n background: color-mix(in srgb, var(--fr-primary) 70%, white);\n }\n .fr-progress-segment--prefilled {\n background: #8b5cf6;\n }\n .fr-progress-segment--prefilled:hover {\n background: color-mix(in srgb, #8b5cf6 70%, white);\n }\n .fr-progress-segment--skipped {\n background: var(--fr-warning);\n }\n .fr-progress-segment--skipped:hover {\n background: color-mix(in srgb, var(--fr-warning) 70%, white);\n }\n .fr-progress-segment--empty {\n background: var(--fr-border);\n }\n\n /* Gantt chart - each call on its own row */\n .fr-gantt {\n margin-bottom: 8px;\n }\n .fr-gantt__row {\n display: flex;\n align-items: center;\n height: 20px;\n margin-bottom: 3px;\n }\n .fr-gantt__label {\n width: 90px;\n flex-shrink: 0;\n font-size: 11px;\n color: var(--fr-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-right: 8px;\n text-align: right;\n }\n .fr-gantt__track {\n flex: 1;\n background: var(--fr-bg-subtle);\n border-radius: 3px;\n height: 14px;\n position: relative;\n }\n .fr-gantt__bar {\n position: absolute;\n top: 2px;\n height: calc(100% - 4px);\n min-width: 6px;\n border-radius: 2px;\n cursor: pointer;\n }\n .fr-gantt__bar:hover {\n filter: brightness(1.15);\n }\n .fr-gantt__bar--llm {\n background: var(--fr-primary);\n }\n .fr-gantt__bar--tool {\n background: var(--fr-success);\n }\n .fr-gantt__legend {\n display: flex;\n gap: 16px;\n font-size: var(--fr-font-sm);\n color: var(--fr-text-muted);\n margin-top: 12px;\n padding-top: 8px;\n border-top: 1px solid var(--fr-border);\n }\n .fr-gantt__legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .fr-gantt__legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 2px;\n }\n .fr-gantt__legend-dot--llm { background: var(--fr-primary); }\n .fr-gantt__legend-dot--tool { background: var(--fr-success); }\n\n /* Tooltip container */\n .fr-tooltip {\n position: fixed;\n background: #1f2937;\n color: #f9fafb;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: var(--fr-font-sm);\n white-space: pre-line;\n pointer-events: none;\n z-index: 1000;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.05s ease-out, visibility 0.05s ease-out;\n }\n .fr-tooltip.visible {\n opacity: 1;\n visibility: visible;\n transition: opacity 0.2s ease-in, visibility 0.2s ease-in;\n }\n\n .fr-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--fr-font-sm);\n }\n .fr-table th {\n padding: 8px 12px;\n text-align: left;\n font-weight: 600;\n background: var(--fr-bg-subtle);\n }\n .fr-table th:not(:first-child) { text-align: center; }\n .fr-table td {\n padding: 8px 12px;\n border-bottom: 1px solid var(--fr-border);\n }\n .fr-table td:not(:first-child) { text-align: center; }\n\n .fr-details {\n border: none;\n background: none;\n }\n .fr-details > summary {\n cursor: pointer;\n font-size: var(--fr-font-base);\n font-weight: 500;\n color: var(--fr-text);\n padding: 8px 0;\n list-style: none;\n }\n .fr-details > summary::-webkit-details-marker { display: none; }\n .fr-details > summary::before {\n content: '▶';\n display: inline-block;\n margin-right: 8px;\n transition: transform 0.2s;\n font-size: 11px;\n }\n .fr-details[open] > summary::before {\n transform: rotate(90deg);\n }\n .fr-details__content {\n background: var(--fr-bg-muted);\n border-radius: 8px;\n padding: 16px;\n margin-top: 8px;\n }\n\n .fr-turn {\n margin-bottom: 8px;\n background: var(--fr-bg-muted);\n border-radius: 4px;\n }\n .fr-turn summary {\n cursor: pointer;\n padding: 12px;\n font-size: var(--fr-font-sm);\n list-style: none;\n }\n .fr-turn summary::-webkit-details-marker { display: none; }\n .fr-turn summary::before {\n content: '▶';\n display: inline-block;\n margin-right: 8px;\n transition: transform 0.2s;\n font-size: 11px;\n }\n .fr-turn[open] summary::before {\n transform: rotate(90deg);\n }\n .fr-turn__content {\n padding: 0 12px 12px;\n }\n .fr-turn__tools {\n margin: 0;\n padding-left: 20px;\n list-style: none;\n }\n .fr-turn__tool {\n margin: 4px 0;\n font-size: var(--fr-font-sm);\n color: var(--fr-text-muted);\n }\n .fr-turn__tool--error { color: var(--fr-error); }\n\n .fr-turn__query {\n color: var(--fr-primary);\n font-style: italic;\n }\n\n .fr-turn__patches {\n margin: 4px 0 8px 20px;\n padding: 8px 12px;\n background: var(--fr-bg-subtle);\n border-radius: 4px;\n font-size: var(--fr-font-sm);\n }\n .fr-turn__patch {\n margin: 4px 0;\n padding: 4px 0;\n border-bottom: 1px solid var(--fr-border);\n }\n .fr-turn__patch:last-child {\n border-bottom: none;\n margin-bottom: 0;\n padding-bottom: 0;\n }\n .fr-turn__patch-field {\n font-weight: 600;\n color: var(--fr-text);\n }\n .fr-turn__patch-op {\n font-size: 11px;\n padding: 1px 4px;\n border-radius: 2px;\n background: var(--fr-bg-muted);\n color: var(--fr-text-muted);\n margin-left: 6px;\n }\n .fr-turn__patch-value {\n display: block;\n margin-top: 2px;\n color: var(--fr-text-muted);\n font-family: ui-monospace, 'SF Mono', Menlo, monospace;\n word-break: break-word;\n white-space: pre-wrap;\n max-height: 200px;\n overflow: auto;\n }\n .fr-turn__patch-value--skip {\n color: var(--fr-warning);\n font-style: italic;\n }\n .fr-turn__patch-value--clear {\n color: var(--fr-info);\n font-style: italic;\n }\n\n .fr-raw {\n position: relative;\n }\n .fr-copy-btn {\n position: absolute;\n top: 8px;\n right: 8px;\n padding: 4px 8px;\n font-size: var(--fr-font-sm);\n background: var(--fr-bg-subtle);\n border: 1px solid var(--fr-border);\n border-radius: 4px;\n cursor: pointer;\n color: var(--fr-text-muted);\n transition: all 0.15s;\n }\n .fr-copy-btn:hover {\n background: var(--fr-border);\n color: var(--fr-text);\n }\n .fr-copy-btn:active {\n transform: scale(0.95);\n }\n\n /* Scoped pre styles to override parent .tab-content pre */\n .fr-dashboard pre {\n background: var(--fr-bg-muted);\n color: var(--fr-text);\n padding: 1rem;\n border-radius: 6px;\n border: 1px solid var(--fr-border);\n overflow-x: auto;\n font-family: ui-monospace, 'SF Mono', Menlo, monospace;\n font-size: 0.85rem;\n line-height: 1.5;\n margin: 0;\n }\n\n /* Override syntax highlighting colors for dark mode compatibility */\n .fr-dashboard .syn-key { color: var(--fr-primary); }\n .fr-dashboard .syn-string { color: var(--fr-success); }\n .fr-dashboard .syn-number { color: var(--fr-primary); }\n .fr-dashboard .syn-bool { color: var(--fr-warning); }\n .fr-dashboard .syn-null { color: var(--fr-error); }\n\n @media (max-width: 600px) {\n .fr-dashboard { padding: 12px; }\n .fr-cards { grid-template-columns: repeat(2, 1fr); gap: 12px; }\n .fr-card { padding: 12px; }\n .fr-card__value { font-size: 18px; }\n .fr-table { font-size: var(--fr-font-sm); }\n .fr-table th, .fr-table td { padding: 6px 8px; }\n }\n</style>\n`;\n\n/**\n * Render fill record content (dashboard-style visualization).\n * Uses CSS custom properties for theming with automatic dark mode support.\n * Mobile responsive with grid-based layout.\n *\n * @public Exported for testing and reuse.\n */\nexport function renderFillRecordContent(record: FillRecord): string {\n const { status, statusDetail, startedAt, durationMs, llm, formProgress, toolSummary, timeline } =\n record;\n\n // Format start time for display\n const startDate = new Date(startedAt);\n const formattedDate = startDate.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n const formattedTime = startDate.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n });\n\n // Header with model and timestamp\n const headerInfo = `\n <div class=\"fr-header\">\n <div class=\"fr-header__model\">${escapeHtml(llm.model)}</div>\n <div class=\"fr-header__time\">${formattedDate} at ${formattedTime}</div>\n </div>\n `;\n\n // Status banner for non-completed fills\n let statusBanner = '';\n if (status !== 'completed') {\n const bannerClass = status === 'failed' ? 'fr-banner--error' : 'fr-banner--warning';\n const icon = status === 'failed' ? '✕' : '⚠';\n const title = status === 'failed' ? 'FAILED' : status === 'cancelled' ? 'CANCELLED' : 'PARTIAL';\n const msg = statusDetail ?? (status === 'partial' ? 'Did not complete all fields' : '');\n statusBanner = `<div class=\"fr-banner ${bannerClass}\"><strong>${icon} ${title}${msg ? ':' : ''}</strong>${msg ? ` ${escapeHtml(msg)}` : ''}</div>`;\n }\n\n // Summary cards\n const totalTokens = llm.inputTokens + llm.outputTokens;\n const badgeClass = `fr-badge fr-badge--${status}`;\n const badgeIcon = { completed: '✓', partial: '⚠', cancelled: '⊘', failed: '✕' }[status] ?? '?';\n const badgeLabel = status.charAt(0).toUpperCase() + status.slice(1);\n\n const summaryCards = `\n <div class=\"fr-cards\">\n <div class=\"fr-card\">\n <div class=\"fr-card__label\">Status</div>\n <div><span class=\"${badgeClass}\">${badgeIcon} ${badgeLabel}</span></div>\n </div>\n <div class=\"fr-card\">\n <div class=\"fr-card__label\">Duration</div>\n <div class=\"fr-card__value\">${formatDuration(durationMs)}</div>\n </div>\n <div class=\"fr-card\">\n <div class=\"fr-card__label\">Turns</div>\n <div class=\"fr-card__value\">${timeline.length}</div>\n </div>\n <div class=\"fr-card\">\n <div class=\"fr-card__label\">Tokens</div>\n <div class=\"fr-card__value\">${formatTokens(totalTokens)}</div>\n <div class=\"fr-card__sub\">${formatTokens(llm.inputTokens)} in / ${formatTokens(llm.outputTokens)} out</div>\n </div>\n </div>\n `;\n\n // Progress bar\n // Extract filled fields from timeline to show individual segments\n // Use Map to deduplicate by fieldId, keeping only the last (final) state for each field\n const fieldsMap = new Map<string, { fieldId: string; op: string; turnNumber: number }>();\n for (const turn of timeline) {\n for (const tc of turn.toolCalls) {\n if (tc.tool === 'fill_form' && tc.input.patches) {\n const patches = tc.input.patches as { op?: string; fieldId?: string }[];\n for (const patch of patches) {\n if (patch.fieldId && patch.op) {\n fieldsMap.set(patch.fieldId, {\n fieldId: patch.fieldId,\n op: patch.op,\n turnNumber: turn.turnNumber,\n });\n }\n }\n }\n }\n }\n const fieldsFilled = Array.from(fieldsMap.values());\n\n const totalFields = formProgress.totalFields;\n const filledFields = formProgress.filledFields;\n const skippedFields = formProgress.skippedFields;\n const abortedFields = formProgress.abortedFields ?? 0;\n const progressPercent = totalFields > 0 ? Math.round((filledFields / totalFields) * 100) : 0;\n\n // Build progress segments\n const segmentWidth = totalFields > 0 ? 100 / totalFields : 0;\n\n // AI-filled fields (from timeline patches, excluding skip/abort)\n const aiFilledFields = fieldsFilled.filter(\n (f) => f.op !== 'skip_field' && f.op !== 'abort_field',\n );\n const aiFilledSegmentsHtml = aiFilledFields\n .map((f) => {\n const opLabel = f.op.replace(/_/g, ' ');\n const tooltip = `${f.fieldId}\\n${opLabel}\\nTurn ${f.turnNumber}`;\n return `<div class=\"fr-progress-segment fr-progress-segment--filled\" style=\"width: ${segmentWidth}%\" data-tooltip=\"${escapeHtml(tooltip)}\" onmouseenter=\"frShowTip(this)\" onmouseleave=\"frHideTip()\"></div>`;\n })\n .join('');\n\n // Pre-filled fields (filled before AI started, not in timeline)\n const prefilledCount = Math.max(0, filledFields - aiFilledFields.length);\n const prefilledSegmentsHtml =\n prefilledCount > 0\n ? `<div class=\"fr-progress-segment fr-progress-segment--prefilled\" style=\"width: ${segmentWidth * prefilledCount}%\" data-tooltip=\"Pre-filled (${prefilledCount} field${prefilledCount !== 1 ? 's' : ''})\" onmouseenter=\"frShowTip(this)\" onmouseleave=\"frHideTip()\"></div>`\n : '';\n\n // Skipped/aborted fields\n const skippedSegmentsHtml = fieldsFilled\n .filter((f) => f.op === 'skip_field' || f.op === 'abort_field')\n .map((f) => {\n const opLabel = f.op === 'skip_field' ? 'skipped' : 'aborted';\n const tooltip = `${f.fieldId}\\n${opLabel}\\nTurn ${f.turnNumber}`;\n return `<div class=\"fr-progress-segment fr-progress-segment--skipped\" style=\"width: ${segmentWidth}%\" data-tooltip=\"${escapeHtml(tooltip)}\" onmouseenter=\"frShowTip(this)\" onmouseleave=\"frHideTip()\"></div>`;\n })\n .join('');\n\n // Empty segments for unfilled fields\n const unfilledCount = totalFields - filledFields - skippedFields - abortedFields;\n const unfilledSegmentsHtml =\n unfilledCount > 0\n ? `<div class=\"fr-progress-segment fr-progress-segment--empty\" style=\"width: ${segmentWidth * unfilledCount}%\"></div>`\n : '';\n\n // Build progress text with details\n const progressDetails: string[] = [];\n if (prefilledCount > 0) progressDetails.push(`${prefilledCount} pre-filled`);\n if (skippedFields > 0) progressDetails.push(`${skippedFields} skipped`);\n const progressDetailsText = progressDetails.length > 0 ? ` • ${progressDetails.join(' • ')}` : '';\n\n const progressBar = `\n <div class=\"fr-section\">\n <div class=\"fr-section__title\">Progress</div>\n <div class=\"fr-progress\">\n <div class=\"fr-progress__segments\">\n ${prefilledSegmentsHtml}${aiFilledSegmentsHtml}${skippedSegmentsHtml}${unfilledSegmentsHtml}\n </div>\n </div>\n <div class=\"fr-progress__text\">\n ${filledFields}/${totalFields} fields filled (${progressPercent}%)${progressDetailsText}\n </div>\n </div>\n `;\n\n // Gantt-style timeline visualization\n // Calculate actual start/end times for each call\n const totalMs = durationMs;\n const llmCallCount = llm.totalCalls;\n const toolCallCount = toolSummary.totalCalls;\n\n // Build timeline events with actual positions\n // For each turn: LLM call happens first, then tool calls sequentially\n interface TimelineEvent {\n type: 'llm' | 'tool';\n startMs: number;\n durationMs: number;\n turnNumber: number;\n label: string;\n tokens?: { input: number; output: number; total: number };\n }\n\n const timelineEvents: TimelineEvent[] = [];\n\n for (const turn of timeline) {\n const toolTimeInTurn = turn.toolCalls.reduce((sum, tc) => sum + tc.durationMs, 0);\n const llmTimeInTurn = Math.max(0, turn.durationMs - toolTimeInTurn);\n\n // LLM call for this turn - starts at turn.startMs\n if (llmTimeInTurn > 0) {\n timelineEvents.push({\n type: 'llm',\n startMs: turn.startMs,\n durationMs: llmTimeInTurn,\n turnNumber: turn.turnNumber,\n label: `Turn ${turn.turnNumber}`,\n tokens: {\n input: turn.tokens.input,\n output: turn.tokens.output,\n total: turn.tokens.input + turn.tokens.output,\n },\n });\n }\n\n // Tool calls for this turn - use pre-computed startMs\n for (const tc of turn.toolCalls) {\n timelineEvents.push({\n type: 'tool',\n startMs: tc.startMs,\n durationMs: tc.durationMs,\n turnNumber: turn.turnNumber,\n label: tc.tool,\n });\n }\n }\n\n // Render Gantt chart rows - each event gets its own row\n const ganttRowsHtml = timelineEvents\n .map((e) => {\n const leftPct = totalMs > 0 ? (e.startMs / totalMs) * 100 : 0;\n const widthPct = totalMs > 0 ? (e.durationMs / totalMs) * 100 : 0;\n const barClass = e.type === 'llm' ? 'fr-gantt__bar--llm' : 'fr-gantt__bar--tool';\n const startTime = `Start: ${formatDuration(e.startMs)}`;\n const tooltip =\n e.type === 'llm'\n ? `${e.label}&#10;${startTime}&#10;Duration: ${formatDuration(e.durationMs)}&#10;${formatTokens(e.tokens?.total ?? 0)} tokens (${formatTokens(e.tokens?.input ?? 0)} in / ${formatTokens(e.tokens?.output ?? 0)} out)`\n : `${e.label}&#10;${startTime}&#10;Duration: ${formatDuration(e.durationMs)}&#10;Turn ${e.turnNumber}`;\n\n return `\n <div class=\"fr-gantt__row\">\n <div class=\"fr-gantt__label\">${escapeHtml(e.label)}</div>\n <div class=\"fr-gantt__track\">\n <div class=\"fr-gantt__bar ${barClass}\" style=\"left: ${leftPct}%; width: ${widthPct}%\" data-tooltip=\"${tooltip}\" onmouseenter=\"frShowTip(this)\" onmouseleave=\"frHideTip()\"></div>\n </div>\n </div>`;\n })\n .join('');\n\n const llmTotalMs = timelineEvents\n .filter((e) => e.type === 'llm')\n .reduce((sum, e) => sum + e.durationMs, 0);\n const toolTotalMs = timelineEvents\n .filter((e) => e.type === 'tool')\n .reduce((sum, e) => sum + e.durationMs, 0);\n\n const timingSection = `\n <details class=\"fr-details fr-section\" open>\n <summary>Timeline (${formatDuration(totalMs)} total)</summary>\n <div class=\"fr-details__content\">\n <div class=\"fr-gantt\">\n ${ganttRowsHtml}\n <div class=\"fr-gantt__legend\">\n <div class=\"fr-gantt__legend-item\">\n <div class=\"fr-gantt__legend-dot fr-gantt__legend-dot--llm\"></div>\n <span>LLM (${llmCallCount} call${llmCallCount !== 1 ? 's' : ''}, ${formatDuration(llmTotalMs)})</span>\n </div>\n <div class=\"fr-gantt__legend-item\">\n <div class=\"fr-gantt__legend-dot fr-gantt__legend-dot--tool\"></div>\n <span>Tools (${toolCallCount} call${toolCallCount !== 1 ? 's' : ''}, ${formatDuration(toolTotalMs)})</span>\n </div>\n </div>\n </div>\n </div>\n </details>\n `;\n\n // Tool summary table\n let toolSection = '';\n if (toolSummary.byTool.length > 0) {\n const toolRows = toolSummary.byTool\n .map(\n (t) => `\n <tr>\n <td>${escapeHtml(t.toolName)}</td>\n <td>${t.callCount}</td>\n <td>${t.successCount === t.callCount ? '100%' : `${Math.round((t.successCount / t.callCount) * 100)}%`}</td>\n <td>${formatDuration(t.timing.avgMs)}</td>\n <td>${formatDuration(t.timing.p95Ms)}</td>\n </tr>\n `,\n )\n .join('');\n\n toolSection = `\n <details class=\"fr-details fr-section\" open>\n <summary>Tool Summary</summary>\n <div style=\"overflow-x: auto; margin-top: 8px;\">\n <table class=\"fr-table\">\n <thead><tr><th>Tool</th><th>Calls</th><th>Success</th><th>Avg</th><th>p95</th></tr></thead>\n <tbody>${toolRows}</tbody>\n </table>\n </div>\n </details>\n `;\n }\n\n // Turn Details accordion\n let timelineSection = '';\n if (timeline.length > 0) {\n const timelineItems = timeline\n .map((turn) => {\n const turnTokens = turn.tokens.input + turn.tokens.output;\n const toolCallsList = turn.toolCalls.map((tc) => renderToolCall(tc)).join('');\n\n const patchInfo = turn.patchesApplied > 0 ? ` • ${turn.patchesApplied} patches` : '';\n const rejectedInfo =\n turn.patchesRejected > 0\n ? ` <span style=\"color: var(--fr-error)\">(${turn.patchesRejected} rejected)</span>`\n : '';\n\n return `\n <details class=\"fr-turn\">\n <summary><strong>Turn ${turn.turnNumber}</strong> • Order ${turn.order} • ${formatDuration(turn.durationMs)} • ${formatTokens(turnTokens)} tokens${patchInfo}${rejectedInfo}</summary>\n <div class=\"fr-turn__content\">\n ${turn.toolCalls.length > 0 ? `<ul class=\"fr-turn__tools\">${toolCallsList}</ul>` : '<span class=\"fr-turn__tool\">No tool calls</span>'}\n </div>\n </details>\n `;\n })\n .join('');\n\n timelineSection = `\n <details class=\"fr-details fr-section\">\n <summary>Turn Details (${timeline.length} turns)</summary>\n <div style=\"margin-top: 8px;\">${timelineItems}</div>\n </details>\n `;\n }\n\n // Raw YAML section with copy functionality (handler defined in main page script)\n const yamlContent = YAML.stringify(record, { lineWidth: 0 });\n\n const rawSection = `\n <details class=\"fr-details fr-section\">\n <summary>Raw YAML</summary>\n <div class=\"fr-raw\" style=\"margin-top: 8px;\">\n <button class=\"fr-copy-btn\" onclick=\"frCopyYaml(this)\">Copy</button>\n ${renderYamlContent(yamlContent)}\n </div>\n </details>\n `;\n\n // Tooltip element - functions are defined in main page script\n const tooltipHtml = `<div id=\"fr-tooltip\" class=\"fr-tooltip\"></div>`;\n\n return `\n ${FILL_RECORD_STYLES}\n ${tooltipHtml}\n <div class=\"fr-dashboard\">\n ${headerInfo}\n ${statusBanner}\n ${summaryCards}\n ${progressBar}\n ${timingSection}\n ${toolSection}\n ${timelineSection}\n ${rawSection}\n </div>\n `;\n}\n","/**\n * Render command - Render a form as static HTML output.\n *\n * Generates the same HTML as the serve command but writes to a file\n * instead of serving via HTTP.\n */\n\nimport type { Command } from 'commander';\n\nimport { basename, dirname, resolve } from 'node:path';\n\nimport pc from 'picocolors';\n\nimport { parseForm } from '../../engine/parse.js';\nimport {\n getCommandContext,\n logDryRun,\n logError,\n logSuccess,\n logVerbose,\n readFile,\n writeFile,\n} from '../lib/shared.js';\nimport { renderFormHtml } from './serve.js';\n\n/**\n * Generate default output path by replacing .form.md with .form.html.\n */\nfunction getDefaultOutputPath(inputPath: string): string {\n const dir = dirname(inputPath);\n const base = basename(inputPath);\n\n // Replace .form.md extension with .form.html\n const newBase = base.replace(/\\.form\\.md$/i, '.form.html');\n\n if (newBase === base) {\n // No .form.md extension found, append .html\n return `${inputPath}.html`;\n }\n\n return resolve(dir, newBase);\n}\n\n/**\n * Register the render command.\n */\nexport function registerRenderCommand(program: Command): void {\n program\n .command('render <file>')\n .description('Render a form as static HTML output')\n .option('-o, --output <path>', 'Output file path (default: same stem + .html)')\n .action(async (file: string, options: { output?: string }, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n const filePath = resolve(file);\n const outputPath = options.output ? resolve(options.output) : getDefaultOutputPath(filePath);\n\n try {\n logVerbose(ctx, `Reading file: ${filePath}`);\n const content = await readFile(filePath);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Rendering HTML...');\n const html = renderFormHtml(form);\n\n if (ctx.dryRun) {\n logDryRun(`Would write HTML to: ${outputPath}`);\n return;\n }\n\n await writeFile(outputPath, html);\n logSuccess(ctx, pc.green(`✓ Rendered to ${outputPath}`));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Initial values helper for CLI commands.\n *\n * Parses --input flags and converts them to field patches.\n */\n\nimport type { Patch } from '../../engine/coreTypes.js';\n\n/**\n * Parse initial value inputs from CLI flags.\n *\n * Supports formats:\n * - fieldId=value (string values)\n * - fieldId:number=123 (explicit number)\n * - fieldId:list=a,b,c (comma-separated list)\n *\n * @param inputs Array of input strings in \"fieldId=value\" format\n * @returns Array of patches to apply as initial values\n */\nexport function parseInitialValues(inputs: string[]): Patch[] {\n const patches: Patch[] = [];\n\n for (const input of inputs) {\n const equalsIndex = input.indexOf('=');\n if (equalsIndex === -1) {\n throw new Error(`Invalid input format: \"${input}\" (expected \"fieldId=value\")`);\n }\n\n const fieldSpec = input.slice(0, equalsIndex);\n const value = input.slice(equalsIndex + 1);\n\n // Check for type specifier (fieldId:type)\n const colonIndex = fieldSpec.indexOf(':');\n let fieldId: string;\n let type: string | null = null;\n\n if (colonIndex !== -1) {\n fieldId = fieldSpec.slice(0, colonIndex);\n type = fieldSpec.slice(colonIndex + 1).toLowerCase();\n } else {\n fieldId = fieldSpec;\n }\n\n // Create patch based on type\n if (type === 'number') {\n const numValue = parseFloat(value);\n if (isNaN(numValue)) {\n throw new Error(`Invalid number value for \"${fieldId}\": \"${value}\"`);\n }\n patches.push({ op: 'set_number', fieldId, value: numValue });\n } else if (type === 'list') {\n const items = value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n patches.push({ op: 'set_string_list', fieldId, value: items });\n } else {\n // Default to string\n patches.push({ op: 'set_string', fieldId, value });\n }\n }\n\n return patches;\n}\n\n/**\n * Validate that all initial values reference valid field IDs.\n *\n * @param patches Patches to validate\n * @param validFieldIds Set of valid field IDs from the form\n * @returns Array of invalid field IDs (empty if all valid)\n */\nexport function validateInitialValueFields(patches: Patch[], validFieldIds: Set<string>): string[] {\n const invalid: string[] = [];\n\n for (const patch of patches) {\n if ('fieldId' in patch && patch.fieldId && !validFieldIds.has(patch.fieldId)) {\n invalid.push(patch.fieldId);\n }\n }\n\n return invalid;\n}\n","/**\n * Research command - Fill forms using web-search-enabled models.\n *\n * The research command provides a streamlined workflow for filling forms\n * with information gathered from web searches.\n */\n\nimport type { Command } from 'commander';\n\nimport { resolve } from 'node:path';\n\nimport pc from 'picocolors';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { applyPatches } from '../../engine/apply.js';\nimport { runResearch } from '../../research/runResearch.js';\nimport {\n formatSuggestedLlms,\n hasWebSearchSupport,\n parseModelIdForDisplay,\n WEB_SEARCH_CONFIG,\n} from '../../llms.js';\nimport {\n AGENT_ROLE,\n DEFAULT_MAX_TURNS,\n DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN,\n DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN,\n} from '../../settings.js';\nimport { getFormsDir } from '../lib/paths.js';\nimport {\n createSpinner,\n getCommandContext,\n logError,\n logInfo,\n logSuccess,\n logTiming,\n logVerbose,\n logWarn,\n readFile,\n} from '../lib/shared.js';\nimport { exportMultiFormat } from '../lib/exportHelpers.js';\nimport { generateVersionedPathInFormsDir } from '../lib/versioning.js';\nimport { parseInitialValues, validateInitialValueFields } from '../lib/initialValues.js';\n\n/**\n * Register the research command.\n */\nexport function registerResearchCommand(program: Command): void {\n program\n .command('research <input>')\n .description('Fill a form using a web-search-enabled model')\n .option(\n '--model <provider/model>',\n 'LLM model to use (e.g., google/gemini-2.5-flash). Required.',\n )\n .option(\n '--output <path>',\n 'Output path for filled form (default: auto-generated in forms directory)',\n )\n .option(\n '--input <fieldId=value>',\n 'Set initial field value (can be used multiple times)',\n (value: string, previous: string[]) => previous.concat([value]),\n [] as string[],\n )\n .option(\n '--max-turns <n>',\n `Maximum turns (default: ${DEFAULT_MAX_TURNS})`,\n String(DEFAULT_MAX_TURNS),\n )\n .option(\n '--max-patches <n>',\n `Maximum patches per turn (default: ${DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN})`,\n String(DEFAULT_RESEARCH_MAX_PATCHES_PER_TURN),\n )\n .option(\n '--max-issues <n>',\n `Maximum issues per turn (default: ${DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN})`,\n String(DEFAULT_RESEARCH_MAX_ISSUES_PER_TURN),\n )\n .option('--transcript', 'Save session transcript')\n .action(async (input: string, options: Record<string, unknown>, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n const startTime = Date.now();\n\n try {\n // Validate model is provided\n if (!options.model) {\n logError('--model is required');\n console.log('');\n console.log(formatSuggestedLlms());\n process.exit(1);\n }\n\n // Validate model supports web search\n const modelId = options.model as string;\n const { provider, model: modelName } = parseModelIdForDisplay(modelId);\n\n if (!hasWebSearchSupport(provider)) {\n const webSearchProviders = Object.entries(WEB_SEARCH_CONFIG)\n .filter(([, config]) => config.supported)\n .map(([p]) => p);\n\n logError(`Model \"${modelId}\" does not support web search.`);\n console.log('');\n console.log(pc.yellow('Research forms require web search capabilities.'));\n console.log(`Use a model from: ${webSearchProviders.join(', ')}`);\n console.log('');\n console.log('Examples:');\n console.log(' --model openai/gpt-5-mini');\n console.log(' --model anthropic/claude-sonnet-4-5');\n console.log(' --model google/gemini-2.5-flash');\n console.log(' --model xai/grok-4');\n process.exit(1);\n }\n\n // Resolve input path\n const inputPath = resolve(input);\n logVerbose(ctx, `Input: ${inputPath}`);\n\n // Read and parse form\n const content = await readFile(inputPath);\n const form = parseForm(content);\n logVerbose(ctx, `Parsed form: ${form.schema.id}`);\n\n // Parse and apply initial values if provided\n const initialInputs = (options.input as string[]) ?? [];\n if (initialInputs.length > 0) {\n const patches = parseInitialValues(initialInputs);\n\n // Validate field IDs\n const validFieldIds = new Set(form.orderIndex);\n const invalidFields = validateInitialValueFields(patches, validFieldIds);\n\n if (invalidFields.length > 0) {\n logWarn(ctx, `Unknown field IDs: ${invalidFields.join(', ')}`);\n }\n\n // Apply initial values\n applyPatches(form, patches);\n logInfo(ctx, `Applied ${patches.length} initial value(s)`);\n }\n\n // Resolve output path\n const formsDir = getFormsDir(ctx.formsDir);\n let outputPath: string;\n\n if (options.output) {\n outputPath = resolve(options.output as string);\n } else {\n // Auto-generate output path in forms directory\n outputPath = generateVersionedPathInFormsDir(inputPath, formsDir);\n }\n\n logVerbose(ctx, `Output: ${outputPath}`);\n\n // Parse harness config from options\n const maxTurns = parseInt(options.maxTurns as string, 10);\n const maxPatchesPerTurn = parseInt(options.maxPatches as string, 10);\n const maxIssuesPerTurn = parseInt(options.maxIssues as string, 10);\n\n // Log research start\n logInfo(ctx, `Research fill with model: ${modelId}`);\n logVerbose(ctx, `Max turns: ${maxTurns}`);\n logVerbose(ctx, `Max patches/turn: ${maxPatchesPerTurn}`);\n logVerbose(ctx, `Max issues/turn: ${maxIssuesPerTurn}`);\n\n // Create spinner for research operation (only for TTY, not quiet mode)\n // Note: provider and modelName already extracted via parseModelIdForDisplay above\n const spinner =\n process.stdout.isTTY && !ctx.quiet\n ? createSpinner({\n type: 'api',\n provider,\n model: modelName,\n })\n : null;\n\n // Run research fill\n let result;\n try {\n result = await runResearch(form, {\n model: modelId,\n enableWebSearch: true,\n captureWireFormat: false,\n recordFill: false,\n maxTurnsTotal: maxTurns,\n maxPatchesPerTurn,\n maxIssuesPerTurn,\n targetRoles: [AGENT_ROLE],\n fillMode: 'continue',\n });\n spinner?.stop();\n } catch (error) {\n spinner?.error('Research failed');\n throw error;\n }\n\n // Log tools used\n if (result.availableTools) {\n logInfo(ctx, `Tools: ${result.availableTools.join(', ')}`);\n }\n\n // Log result\n const statusColor =\n result.status === 'completed'\n ? pc.green\n : result.status === 'max_turns_reached'\n ? pc.yellow\n : pc.red;\n\n logInfo(ctx, `Status: ${statusColor(result.status)}`);\n logInfo(ctx, `Turns: ${result.totalTurns}`);\n\n if (result.inputTokens || result.outputTokens) {\n logVerbose(ctx, `Tokens: ${result.inputTokens ?? 0} in, ${result.outputTokens ?? 0} out`);\n }\n\n // Export filled form\n const { reportPath, yamlPath, formPath, schemaPath } = await exportMultiFormat(\n result.form,\n outputPath,\n );\n\n logSuccess(ctx, 'Outputs:');\n console.log(` ${reportPath} ${pc.dim('(output report)')}`);\n console.log(` ${yamlPath} ${pc.dim('(output values)')}`);\n console.log(` ${formPath} ${pc.dim('(filled markform source)')}`);\n console.log(` ${schemaPath} ${pc.dim('(JSON Schema)')}`);\n\n // Save transcript if requested\n if (options.transcript && result.transcript) {\n const { serializeSession } = await import('../../engine/session.js');\n const transcriptPath = outputPath.replace(/\\.form\\.md$/, '.session.yaml');\n const { writeFile } = await import('../lib/shared.js');\n await writeFile(transcriptPath, serializeSession(result.transcript));\n logInfo(ctx, `Transcript: ${transcriptPath}`);\n }\n\n logTiming(ctx, 'Research fill', Date.now() - startTime);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Schema command - Export form structure as JSON Schema.\n *\n * Converts Markform form structure to JSON Schema format for:\n * - Validation in other systems\n * - Code generation (TypeScript types, API clients)\n * - LLM tooling (function calling schemas)\n * - Documentation and interoperability\n */\n\nimport type { Command } from 'commander';\n\nimport YAML from 'yaml';\n\nimport { parseForm } from '../../engine/parse.js';\nimport { formToJsonSchema, type JsonSchemaDraft } from '../../engine/jsonSchema.js';\nimport { getCommandContext, logError, logVerbose, readFile } from '../lib/shared.js';\n\nconst VALID_DRAFTS: JsonSchemaDraft[] = ['2020-12', '2019-09', 'draft-07'];\n\n/**\n * Register the schema command.\n */\nexport function registerSchemaCommand(program: Command): void {\n program\n .command('schema <file>')\n .description('Export form structure as JSON Schema')\n .option('--pure', 'Exclude x-markform extension properties')\n .option('--draft <version>', `JSON Schema draft version: ${VALID_DRAFTS.join(', ')}`, '2020-12')\n .option('--compact', 'Output compact JSON (no formatting)')\n .action(\n async (\n file: string,\n options: { pure?: boolean; draft?: string; compact?: boolean },\n cmd: Command,\n ) => {\n const ctx = getCommandContext(cmd);\n\n try {\n // Validate draft option\n const draft = (options.draft ?? '2020-12') as JsonSchemaDraft;\n if (!VALID_DRAFTS.includes(draft)) {\n throw new Error(\n `Invalid draft version: ${options.draft}. Valid options: ${VALID_DRAFTS.join(', ')}`,\n );\n }\n\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Generating JSON Schema...');\n const result = formToJsonSchema(form, {\n includeExtensions: !options.pure,\n draft,\n });\n\n // Determine output format\n const format = ctx.format;\n\n if (format === 'yaml') {\n console.log(YAML.stringify(result.schema));\n } else {\n // JSON output (default for this command)\n if (options.compact) {\n console.log(JSON.stringify(result.schema));\n } else {\n console.log(JSON.stringify(result.schema, null, 2));\n }\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n },\n );\n}\n","/**\n * Status command - Display form fill status with per-role breakdown.\n *\n * Provides:\n * - Overall progress counts\n * - Per-role fill statistics\n * - Run mode (explicit or inferred)\n * - Suggested next command\n */\n\nimport { basename } from 'node:path';\n\nimport type { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport type { Field, ParsedForm, RunMode } from '../../engine/coreTypes.js';\nimport { getAllFields } from '../../engine/inspect.js';\nimport { parseForm } from '../../engine/parse.js';\nimport { AGENT_ROLE, USER_ROLE } from '../../settings.js';\nimport { determineRunMode, getFieldRoles } from '../lib/runMode.js';\nimport { formatOutput, getCommandContext, logError, logVerbose, readFile } from '../lib/shared.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Statistics for a set of fields */\ninterface FieldStats {\n total: number;\n answered: number;\n skipped: number;\n aborted: number;\n unanswered: number;\n}\n\n/** Report structure for status command */\nexport interface StatusReport {\n path: string;\n runMode: RunMode | null;\n runModeSource: 'explicit' | 'inferred' | 'unknown';\n overall: FieldStats;\n byRole: Record<string, FieldStats>;\n suggestedCommand: string | null;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Compute field statistics from a list of fields.\n */\nfunction computeFieldStats(form: ParsedForm, fields: Field[]): FieldStats {\n let answered = 0;\n let skipped = 0;\n let aborted = 0;\n let unanswered = 0;\n\n for (const field of fields) {\n const response = form.responsesByFieldId[field.id];\n const state = response?.state ?? 'unanswered';\n\n switch (state) {\n case 'answered':\n answered++;\n break;\n case 'skipped':\n skipped++;\n break;\n case 'aborted':\n aborted++;\n break;\n case 'unanswered':\n default:\n unanswered++;\n break;\n }\n }\n\n return {\n total: fields.length,\n answered,\n skipped,\n aborted,\n unanswered,\n };\n}\n\n/**\n * Compute statistics grouped by role.\n */\nfunction computeStatsByRole(form: ParsedForm): Record<string, FieldStats> {\n const allFields = getAllFields(form);\n const roles = getFieldRoles(form);\n const result: Record<string, FieldStats> = {};\n\n for (const role of roles) {\n const roleFields = allFields.filter((f) => f.role === role);\n result[role] = computeFieldStats(form, roleFields);\n }\n\n return result;\n}\n\n/**\n * Format percentage with one decimal place.\n */\nfunction formatPercent(numerator: number, denominator: number): string {\n if (denominator === 0) return '0%';\n return `${Math.round((numerator / denominator) * 100)}%`;\n}\n\n/**\n * Format status report for console output.\n */\nfunction formatConsoleReport(report: StatusReport, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n const green = useColors ? pc.green : (s: string) => s;\n const yellow = useColors ? pc.yellow : (s: string) => s;\n const red = useColors ? pc.red : (s: string) => s;\n\n // Header\n lines.push(bold(cyan(`Form Status: ${basename(report.path)}`)));\n lines.push('');\n\n // Overall stats\n const overall = report.overall;\n const overallPercent = formatPercent(overall.answered, overall.total);\n lines.push(\n `${bold('Overall:')} ${overall.answered}/${overall.total} fields filled (${overallPercent})`,\n );\n lines.push(` ${green('✓')} Complete: ${overall.answered}`);\n lines.push(` ${dim('○')} Empty: ${overall.unanswered}`);\n if (overall.skipped > 0) {\n lines.push(` ${yellow('⊘')} Skipped: ${overall.skipped}`);\n }\n if (overall.aborted > 0) {\n lines.push(` ${red('✗')} Aborted: ${overall.aborted}`);\n }\n lines.push('');\n\n // Per-role stats\n lines.push(bold('By Role:'));\n const roles = Object.keys(report.byRole).sort((a, b) => {\n // Sort user role first, then agent, then alphabetically\n if (a === USER_ROLE) return -1;\n if (b === USER_ROLE) return 1;\n if (a === AGENT_ROLE) return -1;\n if (b === AGENT_ROLE) return 1;\n return a.localeCompare(b);\n });\n\n for (const role of roles) {\n const stats = report.byRole[role];\n if (!stats) continue;\n const percent = formatPercent(stats.answered, stats.total);\n const needsAttention =\n role === USER_ROLE && stats.unanswered > 0 ? yellow(' ← needs attention') : '';\n lines.push(` ${role}: ${stats.answered}/${stats.total} filled (${percent})${needsAttention}`);\n }\n lines.push('');\n\n // Run mode\n if (report.runMode) {\n const source = report.runModeSource === 'explicit' ? 'explicit' : 'inferred';\n lines.push(`${bold('Run Mode:')} ${report.runMode} (${source})`);\n } else {\n lines.push(`${bold('Run Mode:')} ${dim('unknown')}`);\n }\n\n // Suggested command\n if (report.suggestedCommand) {\n lines.push(`${bold('Suggested:')} ${cyan(report.suggestedCommand)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Generate a suggested command based on status.\n */\nfunction getSuggestedCommand(report: StatusReport): string | null {\n const { overall, byRole, runMode, path } = report;\n const filename = basename(path);\n\n // If complete, no suggestion\n if (overall.total > 0 && overall.answered === overall.total) {\n return null;\n }\n\n // If user role has unfilled fields, suggest interactive\n const userStats = byRole[USER_ROLE];\n if (userStats && userStats.unanswered > 0) {\n return `markform fill ${filename} --interactive`;\n }\n\n // Otherwise suggest based on run mode\n if (runMode === 'research') {\n return `markform research ${filename}`;\n }\n\n return `markform run ${filename}`;\n}\n\n// =============================================================================\n// Command Registration\n// =============================================================================\n\n/**\n * Register the status command.\n */\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status <file>')\n .description('Display form fill status with per-role breakdown')\n .action(async (file: string, _options: Record<string, unknown>, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Computing status...');\n\n // Compute overall stats\n const allFields = getAllFields(form);\n const overall = computeFieldStats(form, allFields);\n\n // Compute per-role stats\n const byRole = computeStatsByRole(form);\n\n // Determine run mode\n const runModeResult = determineRunMode(form);\n let runMode: RunMode | null = null;\n let runModeSource: 'explicit' | 'inferred' | 'unknown' = 'unknown';\n\n if (runModeResult.success) {\n runMode = runModeResult.runMode;\n runModeSource = runModeResult.source;\n }\n\n // Build report\n const report: StatusReport = {\n path: file,\n runMode,\n runModeSource,\n overall,\n byRole,\n suggestedCommand: null, // Will be computed below\n };\n\n report.suggestedCommand = getSuggestedCommand(report);\n\n // Output in requested format\n const output = formatOutput(ctx, report, (data, useColors) =>\n formatConsoleReport(data as StatusReport, useColors),\n );\n console.log(output);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * Validate command - Display form summary and validation issues.\n *\n * A streamlined version of inspect that shows:\n * - Form state\n * - Structure summary (field counts, types)\n * - Progress summary (filled/empty counts)\n * - Issues sorted by priority\n *\n * Does NOT include full form content (use inspect for that).\n */\n\nimport type { Command } from 'commander';\n\nimport pc from 'picocolors';\n\nimport { inspect } from '../../engine/inspect.js';\nimport { parseForm } from '../../engine/parse.js';\nimport { validateSyntaxConsistency, type SyntaxViolation } from '../../engine/preprocess.js';\nimport type { InspectIssue, ProgressState } from '../../engine/coreTypes.js';\nimport {\n formatOutput,\n getCommandContext,\n logError,\n logVerbose,\n readFile,\n shouldUseColors,\n} from '../lib/shared.js';\n\n/** CLI syntax option type - matches SyntaxStyle */\ntype SyntaxOption = 'comments' | 'tags';\n\n/**\n * Format syntax violations for console output.\n */\nfunction formatSyntaxViolations(\n violations: SyntaxViolation[],\n expectedSyntax: SyntaxOption,\n useColors: boolean,\n): string {\n const lines: string[] = [];\n const red = useColors ? pc.red : (s: string) => s;\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n\n lines.push(red(bold(`Syntax violations found (expected: ${expectedSyntax}):`)));\n lines.push('');\n\n for (const v of violations) {\n const syntaxName = v.foundSyntax === 'tags' ? 'Markdoc tag' : 'HTML comment';\n lines.push(` Line ${v.line}: ${syntaxName} found`);\n lines.push(` ${dim(v.pattern.length > 60 ? v.pattern.slice(0, 60) + '...' : v.pattern)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Format state badge for console output.\n */\nfunction formatState(state: ProgressState, useColors: boolean): string {\n const badges: Record<ProgressState, [string, (s: string) => string]> = {\n complete: ['✓ complete', pc.green],\n incomplete: ['○ incomplete', pc.yellow],\n empty: ['◌ empty', pc.dim],\n invalid: ['✗ invalid', pc.red],\n };\n const [text, colorFn] = badges[state] ?? [state, (s: string) => s];\n return useColors ? colorFn(text) : text;\n}\n\n/**\n * Format priority badge for console output.\n */\nfunction formatPriority(priority: number, useColors: boolean): string {\n const label = `P${priority}`;\n if (!useColors) {\n return label;\n }\n switch (priority) {\n case 1:\n return pc.red(pc.bold(label));\n case 2:\n return pc.yellow(label);\n case 3:\n return pc.cyan(label);\n case 4:\n return pc.blue(label);\n case 5:\n default:\n return pc.dim(label);\n }\n}\n\n/**\n * Format severity badge for console output.\n */\nfunction formatSeverity(severity: 'required' | 'recommended', useColors: boolean): string {\n if (!useColors) {\n return severity;\n }\n return severity === 'required' ? pc.red(severity) : pc.yellow(severity);\n}\n\n/** Report structure for validate command */\ninterface ValidateReport {\n title?: string;\n structure: unknown;\n progress: unknown;\n form_state: ProgressState;\n issues: {\n ref: string;\n scope: string;\n reason: string;\n message: string;\n priority: number;\n severity: 'required' | 'recommended';\n }[];\n}\n\n/**\n * Format validate report for console output.\n */\nfunction formatConsoleReport(report: ValidateReport, useColors: boolean): string {\n const lines: string[] = [];\n const bold = useColors ? pc.bold : (s: string) => s;\n const dim = useColors ? pc.dim : (s: string) => s;\n const cyan = useColors ? pc.cyan : (s: string) => s;\n\n // Header\n lines.push(bold(cyan('Form Validation Report')));\n if (report.title) {\n lines.push(`${bold('Title:')} ${report.title}`);\n }\n lines.push('');\n\n // Form state\n lines.push(`${bold('Form State:')} ${formatState(report.form_state, useColors)}`);\n lines.push('');\n\n // Structure summary\n const structure = report.structure as {\n groupCount: number;\n fieldCount: number;\n optionCount: number;\n };\n lines.push(bold('Structure:'));\n lines.push(` Groups: ${structure.groupCount}`);\n lines.push(` Fields: ${structure.fieldCount}`);\n lines.push(` Options: ${structure.optionCount}`);\n lines.push('');\n\n // Progress summary\n const progress = report.progress as {\n counts: {\n totalFields: number;\n requiredFields: number;\n unansweredFields: number;\n answeredFields: number;\n skippedFields: number;\n abortedFields: number;\n validFields: number;\n invalidFields: number;\n emptyFields: number;\n filledFields: number;\n emptyRequiredFields: number;\n totalNotes: number;\n };\n };\n lines.push(bold('Progress:'));\n lines.push(` Total fields: ${progress.counts.totalFields}`);\n lines.push(` Required: ${progress.counts.requiredFields}`);\n lines.push(\n ` AnswerState: answered=${progress.counts.answeredFields}, skipped=${progress.counts.skippedFields}, aborted=${progress.counts.abortedFields}, unanswered=${progress.counts.unansweredFields}`,\n );\n lines.push(\n ` Validity: valid=${progress.counts.validFields}, invalid=${progress.counts.invalidFields}`,\n );\n lines.push(\n ` Value: filled=${progress.counts.filledFields}, empty=${progress.counts.emptyFields}`,\n );\n lines.push(` Empty required: ${progress.counts.emptyRequiredFields}`);\n lines.push('');\n\n // Issues\n if (report.issues.length > 0) {\n lines.push(bold(`Issues (${report.issues.length}):`));\n for (const issue of report.issues) {\n const priority = formatPriority(issue.priority, useColors);\n const severity = formatSeverity(issue.severity, useColors);\n lines.push(\n ` ${priority} (${severity}) ${dim(`[${issue.scope}]`)} ${dim(issue.ref)}: ${issue.message}`,\n );\n }\n } else {\n lines.push(dim('No issues found.'));\n }\n\n return lines.join('\\n');\n}\n\n/** Options for validate command */\ninterface ValidateOptions {\n syntax?: SyntaxOption;\n}\n\n/**\n * Register the validate command.\n */\nexport function registerValidateCommand(program: Command): void {\n program\n .command('validate <file>')\n .description('Validate a form and display summary and issues (no form content)')\n .option(\n '--syntax <style>',\n 'Enforce syntax style (comments or tags). Fails if file uses the other syntax.',\n (value: string) => {\n if (value !== 'comments' && value !== 'tags') {\n throw new Error(`Invalid syntax value: ${value}. Must be 'comments' or 'tags'.`);\n }\n return value as SyntaxOption;\n },\n )\n .action(async (file: string, options: ValidateOptions, cmd: Command) => {\n const ctx = getCommandContext(cmd);\n\n try {\n logVerbose(ctx, `Reading file: ${file}`);\n const content = await readFile(file);\n\n // If --syntax is specified, validate syntax consistency first\n if (options.syntax) {\n logVerbose(ctx, `Checking syntax consistency (expected: ${options.syntax})...`);\n const violations = validateSyntaxConsistency(content, options.syntax);\n\n if (violations.length > 0) {\n const useColors = shouldUseColors(ctx);\n if (ctx.format === 'json') {\n console.log(\n JSON.stringify(\n {\n error: 'syntax_violation',\n expected: options.syntax,\n violations: violations.map((v) => ({\n line: v.line,\n pattern: v.pattern,\n foundSyntax: v.foundSyntax,\n })),\n },\n null,\n 2,\n ),\n );\n } else {\n console.error(formatSyntaxViolations(violations, options.syntax, useColors));\n }\n process.exit(1);\n }\n logVerbose(ctx, 'Syntax consistency check passed.');\n }\n\n logVerbose(ctx, 'Parsing form...');\n const form = parseForm(content);\n\n logVerbose(ctx, 'Running validation...');\n const result = inspect(form);\n\n // Build the report structure (without form content)\n const report: ValidateReport = {\n title: form.schema.title,\n structure: result.structureSummary,\n progress: result.progressSummary,\n form_state: result.formState,\n issues: result.issues.map((issue: InspectIssue) => ({\n ref: issue.ref,\n scope: issue.scope,\n reason: issue.reason,\n message: issue.message,\n priority: issue.priority,\n severity: issue.severity,\n })),\n };\n\n // Output in requested format\n const output = formatOutput(ctx, report, (data, useColors) =>\n formatConsoleReport(data as ValidateReport, useColors),\n );\n console.log(output);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logError(message);\n process.exit(1);\n }\n });\n}\n","/**\n * CLI implementation for markform.\n *\n * Provides commands for inspecting, applying patches, exporting,\n * serving, and running harness loops on .form.md files.\n */\n\nimport { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport { CLI_VERSION } from './lib/cliVersion.js';\nimport { DEFAULT_FORMS_DIR } from './lib/paths.js';\nimport { registerApisCommand } from './commands/apis.js';\nimport { registerApplyCommand } from './commands/apply.js';\nimport { registerBrowseCommand } from './commands/browse.js';\nimport { registerDocsCommand } from './commands/docs.js';\nimport { registerDumpCommand } from './commands/dump.js';\nimport { registerExamplesCommand } from './commands/examples.js';\nimport { registerExportCommand } from './commands/export.js';\nimport { registerFillCommand } from './commands/fill.js';\nimport { registerInspectCommand } from './commands/inspect.js';\nimport { registerReadmeCommand } from './commands/readme.js';\nimport { registerReportCommand } from './commands/report.js';\nimport { registerRunCommand } from './commands/run.js';\nimport { registerSpecCommand } from './commands/spec.js';\nimport { registerModelsCommand } from './commands/models.js';\nimport { registerPlanCommand } from './commands/plan.js';\nimport { registerRenderCommand } from './commands/render.js';\nimport { registerResearchCommand } from './commands/research.js';\nimport { registerSchemaCommand } from './commands/schema.js';\nimport { registerServeCommand } from './commands/serve.js';\nimport { registerStatusCommand } from './commands/status.js';\nimport { registerValidateCommand } from './commands/validate.js';\nimport { OUTPUT_FORMATS } from './lib/shared.js';\n\n/**\n * Configure Commander with colored help text and global options display.\n */\nfunction withColoredHelp<T extends Command>(cmd: T): T {\n cmd.configureHelp({\n styleTitle: (str) => pc.bold(pc.cyan(str)),\n styleCommandText: (str) => pc.green(str),\n styleOptionText: (str) => pc.yellow(str),\n showGlobalOptions: true,\n });\n return cmd;\n}\n\n/**\n * Create and configure the CLI program.\n */\nfunction createProgram(): Command {\n const program = withColoredHelp(new Command());\n\n program\n .name('markform')\n .description('Agent-friendly, human-readable, editable forms')\n .version(CLI_VERSION, '--version', 'output the version number')\n .showHelpAfterError()\n .option('--verbose', 'Enable verbose output')\n .option('--quiet', 'Suppress non-essential output')\n .option('--dry-run', 'Show what would be done without making changes')\n .option('--format <format>', `Output format: ${OUTPUT_FORMATS.join(', ')}`, 'console')\n .option('--forms-dir <dir>', `Directory for form output (default: ${DEFAULT_FORMS_DIR})`)\n .option('--overwrite', 'Overwrite existing field values (default: continue/skip filled)');\n\n // Register commands\n // Help/docs first\n registerReadmeCommand(program);\n registerDocsCommand(program);\n registerSpecCommand(program);\n registerApisCommand(program);\n // Rest alphabetical for help display\n registerApplyCommand(program);\n registerBrowseCommand(program);\n registerDumpCommand(program);\n registerExamplesCommand(program);\n registerExportCommand(program);\n registerFillCommand(program);\n registerInspectCommand(program);\n registerModelsCommand(program);\n registerPlanCommand(program);\n registerRenderCommand(program);\n registerReportCommand(program);\n registerResearchCommand(program);\n registerRunCommand(program);\n registerSchemaCommand(program);\n registerServeCommand(program);\n registerStatusCommand(program);\n registerValidateCommand(program);\n\n return program;\n}\n\n/**\n * Run the CLI.\n */\nexport async function runCli(): Promise<void> {\n const program = createProgram();\n await program.parseAsync(process.argv);\n}\n"],"mappings":"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"}