artifact-editor/cmdforge/artifact-export/config.yaml

157 lines
5.4 KiB
YAML

# artifact-export - Render artifacts to binary formats
# Usage: cat diagram.puml | artifact-export --format plantuml --to /tmp/diagram.svg
# Usage: cat model.scad | artifact-export --format openscad --to /tmp/model.png
name: artifact-export
description: Render artifact source code to binary formats (PNG, SVG, PDF)
category: Artifact
arguments:
- flag: --format
variable: format
required: true
description: "Source format: plantuml, mermaid, openscad, svg, excalidraw, code"
- flag: --to
variable: output_path
required: true
description: Output file path (extension determines output format, e.g. .png, .svg, .pdf)
steps:
- type: code
output_var: result
code: |
import subprocess
import json
import os
from pathlib import Path
source_code = input.strip()
output = Path(output_path)
output_ext = output.suffix.lower()
# Ensure output directory exists
output.parent.mkdir(parents=True, exist_ok=True)
success = False
message = ""
if format == 'plantuml':
# Write to temp file
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.puml', delete=False) as f:
f.write(source_code)
temp_path = f.name
format_flag = {'.svg': '-tsvg', '.png': '-tpng', '.eps': '-teps', '.pdf': '-tpdf'}.get(output_ext, '-tsvg')
try:
result = subprocess.run(
['plantuml', format_flag, '-o', str(output.parent), temp_path],
capture_output=True, text=True, timeout=30
)
if result.returncode == 0:
# PlantUML outputs to same name with different extension
temp_base = Path(temp_path)
generated = output.parent / (temp_base.stem + output_ext)
if generated.exists():
import shutil
shutil.move(str(generated), str(output))
success = True
message = str(output)
else:
message = f"Generated file not found: {generated}"
else:
message = f"PlantUML error: {result.stderr}"
finally:
os.unlink(temp_path)
elif format == 'mermaid':
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.mmd', delete=False) as f:
f.write(source_code)
temp_path = f.name
try:
result = subprocess.run(
['mmdc', '-i', temp_path, '-o', str(output)],
capture_output=True, text=True, timeout=30
)
if result.returncode == 0 and output.exists():
success = True
message = str(output)
else:
message = f"Mermaid error: {result.stderr}"
finally:
os.unlink(temp_path)
elif format == 'openscad':
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.scad', delete=False) as f:
f.write(source_code)
temp_path = f.name
try:
result = subprocess.run(
['openscad', '-o', str(output), temp_path],
capture_output=True, text=True, timeout=60
)
if result.returncode == 0 and output.exists():
success = True
message = str(output)
else:
message = f"OpenSCAD error: {result.stderr}"
finally:
os.unlink(temp_path)
elif format == 'svg':
if output_ext == '.svg':
output.write_text(source_code)
success = True
message = str(output)
elif output_ext == '.png':
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.svg', delete=False) as f:
f.write(source_code)
temp_path = f.name
try:
for cmd in [
['inkscape', temp_path, '-o', str(output)],
['rsvg-convert', temp_path, '-o', str(output)],
]:
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0 and output.exists():
success = True
message = str(output)
break
except FileNotFoundError:
continue
if not success:
message = "SVG to PNG requires inkscape or rsvg-convert"
finally:
os.unlink(temp_path)
else:
message = f"Unsupported output format: {output_ext}"
elif format == 'code':
output.write_text(source_code)
success = True
message = str(output)
elif format == 'excalidraw':
if output_ext == '.json':
output.write_text(source_code)
success = True
message = str(output)
else:
message = "Excalidraw export currently only supports .json output"
else:
message = f"Unknown format: {format}"
print(json.dumps({'success': success, 'path' if success else 'error': message}))