/** * MCP App Review Views — generated at runtime from shared boilerplate * + per-view configuration via `buildMcpView()`. * * Each function returns a self-contained HTML page that uses the * `App` class from `@modelcontextprotocol/ext-apps` (loaded via * the `app-with-deps` bundle that includes its own dependencies). * * These Views are served as `ui://` resources and rendered inline * in MCP hosts that support MCP Apps (Claude, ChatGPT, VS Code, etc.). */ import { buildMcpView } from './mcp-view-builder'; /* ── Review Post ────────────────────────────────────────────────────── */ export function reviewPostHtml(): string { return buildMcpView({ title: 'Review Post', waitingMessage: 'Waiting for post data...', acceptLabel: 'Publish', discardLabel: 'Discard Draft', renderBody: `\ const post = data.post || {}; const wc = (post.content || "").split(/\\s+/).filter(Boolean).length; document.getElementById("review").innerHTML = \`

\${esc(post.title || "Untitled")}

Draft \${wc} words

\${post.categories?.length ? '

Categories: ' + post.categories.map(c => esc(c)).join(", ") + '

' : ''} \${post.tags?.length ? '

Tags: ' + post.tags.map(t => esc(t)).join(", ") + '

' : ''} \${post.excerpt ? '

Excerpt

' + esc(post.excerpt) + '

' : ''}

Content

\${esc(post.content || "")}
\`;`, }); } /* ── Review Script ──────────────────────────────────────────────────── */ export function reviewScriptHtml(): string { return buildMcpView({ title: 'Review Script', waitingMessage: 'Waiting for script data...', acceptLabel: 'Create Script', discardLabel: 'Discard', renderBody: `\ const p = data.preview || data; document.getElementById("review").innerHTML = \`

\${esc(p.title || "Untitled Script")}

\${esc(p.kind || "script")}

Python Code

\${esc(p.content || "(code not included in preview)")}
\`;`, }); } /* ── Review Template ────────────────────────────────────────────────── */ export function reviewTemplateHtml(): string { return buildMcpView({ title: 'Review Template', waitingMessage: 'Waiting for template data...', acceptLabel: 'Create Template', discardLabel: 'Discard', renderBody: `\ const p = data.preview || data; document.getElementById("review").innerHTML = \`

\${esc(p.title || "Untitled Template")}

\${esc(p.kind || "template")}

Liquid Template

\${esc(p.content || "(template not included in preview)")}
\`;`, }); } /* ── Review Metadata ────────────────────────────────────────────────── */ export function reviewMetadataHtml(): string { return buildMcpView({ title: 'Review Metadata', waitingMessage: 'Waiting for metadata...', acceptLabel: 'Apply Changes', discardLabel: 'Discard', extraCss: `\ .diff-table { width: 100%; border-collapse: collapse; margin: 8px 0; } .diff-table th, .diff-table td { padding: 6px 10px; border: 1px solid #dee2e6; text-align: left; font-size: 0.85rem; } .diff-table th { background: #f1f3f5; font-weight: 600; } .diff-old { background: #ffeef0; } .diff-new { background: #e6ffed; }`, extraJsHelpers: `function fmt(v) { if (v == null) return "(empty)"; if (Array.isArray(v)) return v.join(", "); return String(v); }`, renderBody: `\ const current = data.current || {}; const proposed = data.proposed || {}; const fields = Object.keys(proposed); let rows = fields.map(f => \` \${esc(f)} \${esc(fmt(current[f]))} \${esc(fmt(proposed[f]))} \`).join(""); document.getElementById("review").innerHTML = \`

Metadata Changes

\${rows}
FieldCurrentProposed
\`;`, }); }