Architecture Guide
This guide explains ScriptIt's internal architecture, focusing on the unified script execution system and environment variable prompting capabilities introduced in recent versions.
Overview
ScriptIt is built with a modular architecture that separates concerns and enables code reuse across different interfaces (CLI and TUI). The core principle is to have shared execution logic with pluggable interface-specific components.
Core Architecture
┌─────────────────────────────────────────────────────────────────┐
│ ScriptIt Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ CLI │ │ TUI │ │
│ │ Interface │ │ Interface │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ │ │ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ CLI │ │ TUI │ │
│ │ Prompter │ │ Prompter │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ └─────────────────┬───────────────────────┘ │
│ │ │
│ ┌─────────────┐ │
│ │ Core Script │ │
│ │ Execution │ │
│ │ Engine │ │
│ └─────────────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Environment │ │ Script │ │ Console │ │
│ │ Management │ │ Executor │ │ Interceptor │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Core Components
1. Script Execution Engine (src/core/script-executor.ts
)
The heart of ScriptIt is the unified script execution engine that handles:
- Script Loading - Dynamic import with cache busting
- Lifecycle Management - tearUp → execute → tearDown
- Environment Preparation - Variable collection and injection
- Console Interception - Colored output and logging
- Error Handling - Comprehensive error reporting
Key Function: executeScriptWithEnvironment()
export async function executeScriptWithEnvironment(
options: ScriptExecutionOptions
): Promise<unknown>
This function orchestrates the entire script execution process:
- Script Validation - Ensures script file exists
- Environment Discovery - Loads script to detect variable requirements
- Variable Collection - Uses appropriate prompter for missing variables
- Environment Assembly - Merges all environment sources with proper precedence
- Script Execution - Runs script with enhanced context
- Result Handling - Processes and returns script results
2. Environment Prompter Interface
The prompter interface enables different UIs to collect environment variables:
export interface EnvironmentPrompter {
promptForVariables(
variables: VariableDefinition[],
existingEnv: Record<string, string | undefined>
): Promise<Record<string, string>>;
}
CLI Prompter (CLIEnvironmentPrompter
)
Uses Node.js readline for terminal-based prompting:
- Regular Input - Standard readline interface
- Password Input - Raw mode with character masking
- Interrupt Handling - Graceful Ctrl+C handling
- Progress Feedback - Colored status messages
TUI Prompter (TUIEnvironmentPrompter
)
Uses blessed widgets for modal-based prompting:
- Modal Dialogs - Centered, bordered input dialogs
- Visual Feedback - Icons and color coding for variable types
- Keyboard Navigation - Enter/Escape/Tab controls
- Integration - Seamless integration with TUI layout
3. Configuration System
Centralized configuration loading and management:
interface RunnerConfig {
scriptsDir: string;
tmpDir: string;
envFiles: string[];
excludePatterns: string[];
defaultParams: Record<string, unknown>;
loadedConfigPath?: string;
}
Environment Variable System
Variable Definition
Scripts can define required variables in multiple formats:
// Full definition with custom prompts and types
export const variables = [
{ name: 'API_KEY', message: 'Enter your API key:', type: 'password' },
{ name: 'USER_NAME', message: 'Enter your username:', type: 'input' },
];
// Shorthand definition for quick setup
export const variables = ['API_KEY', 'DATABASE_URL', 'SECRET_TOKEN'];
Variable Collection Flow
┌─────────────────────────────────────────────────────────────────┐
│ Variable Collection Process │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Load Script Module │
│ └─ Extract `variables` export │
│ │
│ 2. Merge Variable Sources │
│ ├─ CLI --env-prompts │
│ ├─ Script variables export │
│ └─ Remove duplicates (CLI takes precedence) │
│ │
│ 3. Load Base Environment │
│ ├─ .env files │
│ ├─ Config defaultParams │
│ └─ CLI --env arguments │
│ │
│ 4. Filter Missing Variables │
│ └─ Only prompt for variables not already set │
│ │
│ 5. Prompt for Missing Variables │
│ ├─ CLI: readline prompting │
│ └─ TUI: modal dialog prompting │
│ │
│ 6. Assemble Final Environment │
│ ├─ Base environment │
│ ├─ CLI-provided values │
│ ├─ Prompted values │
│ └─ Set in process.env │
│ │
│ 7. Execute Script │
│ └─ All variables available in context.env │
│ │
└─────────────────────────────────────────────────────────────────┘
Environment Precedence
ScriptIt follows a clear precedence order for environment variables:
- Prompted Variables - Collected interactively (Highest priority)
- CLI Arguments (
--env NAME=value
) - CLI-provided environment variables - Config Default Params - From runner.config.js
- Environment Files - .env, .env.local, etc. (Lowest priority)
Console Interception
ScriptIt provides colored console output through a sophisticated interception system:
Console Enhancement
interface EnhancedContext extends ScriptContext {
console: {
log: (...args: unknown[]) => void; // White
info: (...args: unknown[]) => void; // Blue
warn: (...args: unknown[]) => void; // Yellow
error: (...args: unknown[]) => void; // Red
debug: (...args: unknown[]) => void; // Gray
};
}
Safe Serialization
The console interceptor includes safe serialization to prevent circular reference errors:
- Primitive Types - Direct string conversion
- Objects - Safe JSON serialization with fallbacks
- Functions -
[Function]
placeholder - Circular References -
[Object]
placeholder - Error Objects - Special error message extraction
Interface Integration
CLI Integration (src/cli.ts
)
The CLI integrates with the core execution engine through:
- Centralized Options - Reusable option definitions in
CLI_OPTIONS
- Shared Execution - Uses
executeScriptWithEnvironment()
- CLI Prompter - Readline-based environment variable collection
- Error Handling - Process exit codes and colored error messages
TUI Integration (src/ui/blessed-ui.ts
)
The TUI integrates through:
- Modal Prompting - Blessed-based environment variable collection
- Real-time Logging - Live output streaming to TUI panels
- Shared Configuration - Uses same config system as CLI
- Event Handling - Keyboard navigation and script execution
Error Handling
Hierarchical Error Handling
- Script Level - Script-specific errors with context
- Execution Level - Environment and configuration errors
- Interface Level - CLI/TUI specific error display
- Process Level - Exit codes and termination
Error Types
- Configuration Errors - Invalid config or missing files
- Environment Errors - Missing directories or variables
- Script Errors - Runtime errors within scripts
- Interface Errors - TUI/CLI specific issues
Performance Considerations
Script Loading
- Dynamic Imports - Fresh script loading with cache busting
- Lazy Loading - Scripts loaded only when needed
- Error Isolation - Script errors don't crash the system
Memory Management
- Variable Cleanup - Prompted variables cleared after execution
- Module Caching - Careful cache management for script updates
- Resource Cleanup - Proper cleanup of temporary resources
Extension Points
The architecture is designed for extensibility:
New Prompter Implementations
class WebUIPrompter implements EnvironmentPrompter {
async promptForVariables(
variables: VariableDefinition[],
existingEnv: Record<string, string | undefined>
): Promise<Record<string, string>> {
// Web-based prompting implementation
}
}
Custom Execution Contexts
const customExecutor = createScriptExecutorInstance({
consoleInterception: {
enabled: true,
logFunction: customLogger,
useColors: false
}
});
Configuration Extensions
interface ExtendedConfig extends RunnerConfig {
customFeatures: {
enableMetrics: boolean;
apiEndpoint: string;
};
}
Best Practices
For Core Development
- Interface Abstraction - Keep UI-specific code out of core
- Error Propagation - Let errors bubble up with context
- Configuration Validation - Validate config early and clearly
- Type Safety - Use TypeScript interfaces consistently
For Interface Development
- Prompter Implementation - Implement consistent prompting behavior
- Error Display - Provide clear, actionable error messages
- User Feedback - Show progress and status information
- Resource Cleanup - Clean up UI resources properly
For Script Authors
- Variable Declaration - Declare required variables explicitly
- Error Handling - Provide meaningful error messages
- Context Usage - Use enhanced console for better output
- Type Annotations - Include TypeScript types for better DX
Migration Guide
From Previous Versions
The unified architecture is backward compatible, but new features are available:
// Old approach (still works)
export async function execute(context) {
console.log('Hello world');
}
// New approach (recommended)
export const variables = ['API_KEY'];
export async function execute(context) {
const console = context.console || global.console;
console.info('Using enhanced console with colors');
console.log('API Key:', context.env.API_KEY ? '***' : 'Not set');
}
Related Documentation
- Writing Scripts - Script development guide
- TUI Features - Terminal UI documentation
- CLI Commands - Command-line interface
- Environment Variables - Environment management