--- phase: 42-wallpapers-social-format-conversion-voice plan: 01 type: execute wave: 1 depends_on: [] files_modified: - server/src/services/renderers/types.ts - server/src/services/content-job-runner.ts - server/src/services/converter-capabilities.ts - server/src/services/renderers/wallpaper-renderer.ts - server/src/services/renderers/social-renderer.ts - server/src/services/renderers/convert-renderer.ts - server/package.json autonomous: true requirements: [CONV-08] must_haves: truths: - "New npm dependencies (file-type, xlsx, csv-parse) are installed and importable" - "Bundle types (WallpaperBundle, SocialPostBundle, ConvertBundle) exist with correct shapes" - "content-job-runner switch handles wallpaper, social-post, and convert job types" - "Converter capabilities service probes pandoc/libreoffice at startup and caches result" artifacts: - path: "server/src/services/renderers/types.ts" provides: "WallpaperBundle, SocialPostBundle, ConvertBundle type definitions" contains: "WallpaperBundle" - path: "server/src/services/content-job-runner.ts" provides: "wallpaper, social-post, convert cases in renderContent switch" contains: "case \"wallpaper\"" - path: "server/src/services/converter-capabilities.ts" provides: "Startup probe for pandoc/libreoffice, cached capability map" contains: "converterCapabilitiesService" key_links: - from: "server/src/services/content-job-runner.ts" to: "server/src/services/renderers/wallpaper-renderer.ts" via: "dynamic import in case wallpaper" pattern: "wallpaper-renderer" - from: "server/src/services/content-job-runner.ts" to: "server/src/services/renderers/social-renderer.ts" via: "dynamic import in case social-post" pattern: "social-renderer" - from: "server/src/services/content-job-runner.ts" to: "server/src/services/renderers/convert-renderer.ts" via: "dynamic import in case convert" pattern: "convert-renderer" --- Install Phase 42 dependencies, define shared bundle types, wire content-job-runner switch for three new job types, and create the converter capabilities probe service. Purpose: Every subsequent plan depends on these types, job runner cases, and dependency availability. This is the foundation layer. Output: Updated types.ts, content-job-runner.ts, new converter-capabilities.ts, installed packages. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/42-wallpapers-social-format-conversion-voice/42-RESEARCH.md @server/src/services/renderers/types.ts @server/src/services/content-job-runner.ts @server/package.json From server/src/services/renderers/types.ts: ```typescript export interface RenderResult { filename: string; contentType: string; buffer: Buffer; } export type ContentBundle = DiagramBundle | IconSetBundle | ThemePaletteBundle; ``` From server/src/services/content-job-runner.ts: ```typescript export async function renderContent(jobType: string, input: Record): Promise { switch (jobType) { case "diagram": { ... } case "icon-set": { ... } case "theme-palette": { ... } } } ``` Task 1: Install dependencies and define bundle types server/package.json, server/src/services/renderers/types.ts server/src/services/renderers/types.ts, server/package.json 1. Install new dependencies in server/: ```bash cd /opt/nexus/server && pnpm add file-type@22.0.0 xlsx@0.18.5 csv-parse@6.2.1 ``` Do NOT install @types/xlsx — xlsx ships its own types. 2. Add these new bundle types to server/src/services/renderers/types.ts AFTER the existing ThemePaletteBundle: ```typescript export interface WallpaperBundle { type: "wallpaper-bundle"; platform: string; width: number; height: number; pngBase64: string; prompt: string; } export interface AppIconBundle { type: "app-icon-bundle"; sizes: Array<{ size: number; pngBase64: string }>; prompt: string; } export interface SocialPostBundle { type: "social-post-bundle"; platform: string; post: string; hashtags: string[]; slides?: string[]; charLimit: number; } export interface ConvertBundle { type: "convert-bundle"; outputFilename: string; outputMime: string; outputBase64: string; method: "direct" | "ai-bridge"; } ``` 3. Update the ContentBundle union type to include the new bundles: ```typescript export type ContentBundle = DiagramBundle | IconSetBundle | ThemePaletteBundle | WallpaperBundle | AppIconBundle | SocialPostBundle | ConvertBundle; ``` cd /opt/nexus/server && npx tsc --noEmit 2>&1 | head -20 - grep "WallpaperBundle" server/src/services/renderers/types.ts - grep "SocialPostBundle" server/src/services/renderers/types.ts - grep "ConvertBundle" server/src/services/renderers/types.ts - grep "AppIconBundle" server/src/services/renderers/types.ts - grep "file-type" server/package.json - grep "xlsx" server/package.json - grep "csv-parse" server/package.json All four bundle types exported from types.ts. file-type, xlsx, csv-parse installed in server/package.json. Task 2: Wire content-job-runner switch and create converter capabilities service server/src/services/content-job-runner.ts, server/src/services/converter-capabilities.ts, server/src/services/renderers/wallpaper-renderer.ts, server/src/services/renderers/social-renderer.ts, server/src/services/renderers/convert-renderer.ts server/src/services/content-job-runner.ts, server/src/utils/execFileNoThrow.ts 1. Add three new cases to the `renderContent` switch in content-job-runner.ts, following the exact existing pattern (dynamic import of renderer, call render function, return result). For now, create stub renderer imports that will be implemented in Plans 02-04: ```typescript case "wallpaper": { const { renderWallpaper } = await import("./renderers/wallpaper-renderer.js"); return renderWallpaper(input); } case "social-post": { const { renderSocialPost } = await import("./renderers/social-renderer.js"); return renderSocialPost(input); } case "convert": { const { renderConvert } = await import("./renderers/convert-renderer.js"); return renderConvert(input); } ``` 2. Create stub renderer files so tsc resolves the imports (Plans 02-04 replace with real implementations): - server/src/services/renderers/wallpaper-renderer.ts: export async function renderWallpaper that throws "Not implemented" - server/src/services/renderers/social-renderer.ts: export async function renderSocialPost that throws "Not implemented" - server/src/services/renderers/convert-renderer.ts: export async function renderConvert that throws "Not implemented" Each stub must import and return RenderResult type. 3. Create server/src/services/converter-capabilities.ts implementing the startup probe pattern: - Export interface ConverterCapabilities { imageConverter: boolean; audioVideoConverter: boolean; docConverter: boolean; dataConverter: boolean } - Export function converterCapabilitiesService() with a get() method - Use execFileNoThrow from src/utils/execFileNoThrow.ts (project standard — do NOT use child_process.exec directly) to probe "pandoc" and "libreoffice" with ["--version"] argument - imageConverter, audioVideoConverter, dataConverter always true (npm deps) - docConverter true only if pandoc or libreoffice binary responds with status 0 - Cache result after first probe in module-level variable cd /opt/nexus/server && npx tsc --noEmit 2>&1 | head -20 - grep "case \"wallpaper\"" server/src/services/content-job-runner.ts - grep "case \"social-post\"" server/src/services/content-job-runner.ts - grep "case \"convert\"" server/src/services/content-job-runner.ts - grep "converterCapabilitiesService" server/src/services/converter-capabilities.ts - grep "ConverterCapabilities" server/src/services/converter-capabilities.ts - grep "execFileNoThrow" server/src/services/converter-capabilities.ts - grep "renderWallpaper" server/src/services/renderers/wallpaper-renderer.ts - grep "renderSocialPost" server/src/services/renderers/social-renderer.ts - grep "renderConvert" server/src/services/renderers/convert-renderer.ts content-job-runner handles wallpaper, social-post, convert job types. Stub renderers satisfy tsc. Converter capabilities service probes and caches binary availability using execFileNoThrow. - `cd /opt/nexus/server && npx tsc --noEmit` passes with zero errors - All new types are exported from types.ts - Three new cases exist in content-job-runner switch - Three new bundle type interfaces exported from types.ts - Three new job type cases in content-job-runner.ts switch - Stub renderer files exist for wallpaper, social, convert - converter-capabilities.ts probes pandoc/libreoffice using execFileNoThrow and caches - tsc compiles cleanly After completion, create `.planning/phases/42-wallpapers-social-format-conversion-voice/42-01-SUMMARY.md`