---
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