Plugin API Reference

Complete reference for the Structure Creator plugin system.

Manifest Schema

The plugin.json manifest file describes your plugin.

Fields

FieldTypeRequiredDefaultDescription
namestringYesUnique plugin identifier. Must not contain /, \, or null characters.
versionstringYesSemantic version (e.g., "1.0.0")
descriptionstringNoHuman-readable description
capabilitiesstring[]No[]Plugin capabilities (see below)
fileTypesstring[]No[]File extensions to process (e.g., [".ts", ".js"])
mainstringNo"index.js"Entry point file path
authorstringNoPlugin author
licensestringNoLicense identifier

Example

{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "Does something useful",
  "capabilities": ["file-processor"],
  "fileTypes": [".ts", ".js"],
  "main": "index.js",
  "author": "Your Name",
  "license": "MIT"
}

Capabilities

Capabilities define what hooks a plugin provides. Currently implemented:

CapabilityDescription
file-processorProcesses file content during structure creation

Reserved Capabilities

The following capabilities are defined but not yet implemented:

CapabilityDescription
variable-transformerTransforms variable values
schema-validatorValidates schemas before creation
post-create-hookRuns after structure creation

PluginModule Interface

The plugin's JavaScript module must export a default object implementing this interface:

interface PluginModule {
  /** Plugin name (for logging) */
  name: string;

  /** File extensions to process (overrides manifest if provided) */
  fileTypes?: string[];

  /** Process file content */
  process: (content: string, context: ProcessorContext) => string | Promise<string>;
}

Example Implementation

export default {
  name: 'my-plugin',
  fileTypes: ['.ts', '.js'],

  process(content, context) {
    // Transform and return content
    return content;
  }
};

ProcessorContext Interface

Context passed to the process function:

interface ProcessorContext {
  /** Relative file path (e.g., "src/index.ts") */
  filePath: string;

  /** File extension with dot (e.g., ".ts") */
  extension: string;

  /** Variable values from the Variables panel */
  variables: Record<string, string>;

  /** Project name from the UI */
  projectName?: string;
}

Accessing Variables

Variables from the UI are available in context.variables:

process(content, context) {
  const author = context.variables.AUTHOR || 'Unknown';
  const year = context.variables.YEAR || new Date().getFullYear();
  // ...
}

Built-in Variables

These variables are always available in context.variables:

VariableDescriptionExample
PROJECT_NAMEProject name from the UImy-project
DATECurrent date (ISO format)2024-01-15
YEARCurrent year2024
MONTHCurrent month (01-12)01
DAYCurrent day (01-31)15

User-defined variables from the Variables panel are also available.

File Type Matching

Extension Matching

File types are matched by extension (case-insensitive):

// Matches files ending in .ts, .tsx
fileTypes: ['.ts', '.tsx']

Wildcard

Use "*" to match all text files:

// Matches all text files
fileTypes: ['*']

Priority

If both the manifest and module define fileTypes, the module's value takes precedence at runtime.

Error Handling

Plugin Load Errors

If a plugin fails to load (invalid manifest, missing files, syntax errors):

  • An error is logged to the console
  • The plugin is skipped
  • Other plugins continue to work

Process Errors

If process() throws an error:

  • The error is logged to the console
  • The file content is passed unchanged to the next plugin
  • Structure creation continues
process(content, context) {
  try {
    // Your processing logic
    return transformedContent;
  } catch (error) {
    console.error('Plugin error:', error);
    return content; // Return original on error
  }
}

Manifest Validation

The following validation rules are enforced when loading plugins:

RuleError
name is empty"Plugin name cannot be empty"
name contains /, \, or \0"Plugin name contains invalid characters"
version is empty"Plugin version cannot be empty"
Unknown capability"Unknown capability: X"
Main file doesn't exist"Main entry point not found: X"

Plugin Lifecycle

Loading

  1. On app start, Structure Creator scans ~/.structure-creator/plugins/
  2. For each directory with a valid plugin.json:
    • Manifest is parsed and validated
    • Plugin is registered in the database
  3. When structure creation starts:
    • Enabled file-processor plugins are loaded
    • Plugin code (index.js) is dynamically imported

Processing

  1. For each file in the schema:
    • Matching plugins are found by extension
    • Plugins are sorted by loadOrder
    • Content is passed through each plugin's process() function
    • Final content is sent to the backend

Unloading

  • Plugins are unloaded when no longer needed
  • Blob URLs used for dynamic imports are revoked

Plugin Storage

Directory Structure

~/.structure-creator/plugins/
└── plugin-name/
    ├── plugin.json    # Required: manifest
    ├── index.js       # Required: entry point (or custom main)
    └── ...            # Optional: additional files

Database

Plugin metadata is stored in SQLite (~/.structure-creator.db):

ColumnTypeDescription
idTEXTUnique identifier
nameTEXTPlugin name
versionTEXTVersion string
descriptionTEXTDescription
pathTEXTFilesystem path
capabilitiesTEXTJSON array of capabilities
file_typesTEXTJSON array of file types
user_settingsTEXTJSON object of user settings
is_enabledINTEGER1 if enabled, 0 if disabled
load_orderINTEGERProcessing order (lower = first)
installed_atTEXTISO timestamp
updated_atTEXTISO timestamp