Exec File Plugin

The exec-file plugin allows you to execute local or remote script files with full support for variable interpolation in file paths, arguments, parameters, and working directories.

Overview

Unlike the exec plugin which runs inline shell commands, exec-file executes external script files. This is useful for:

Configuration

interface ExecFileConfig {
  file: string; // Path to script (local or remote URL)
  runtime?: ExecFileRuntime; // 'node' | 'bash' | 'sh' | 'pwsh' | 'powershell' (auto-detected if omitted)
  args?: string[]; // Arguments to pass to the script
  parameters?: Record<string, string>; // Environment variables
  cwd?: string; // Working directory
  condition?: string; // Optional condition to execute
}

Configuration Fields

Runtime Auto-Detection

The plugin automatically detects the appropriate runtime based on the file extension:

{
  "type": "exec-file",
  "config": {
    "file": "scripts/setup.js"
    // Runtime automatically detected as 'node'
  }
}

Detection Rules:

Variable Interpolation

All string fields support `` interpolation:

Field Supports Interpolation Example
file βœ… Yes 'scripts/-setup.js'
args βœ… Yes (each arg) ['--name=']
parameters βœ… Yes (values) { "NAME": "" }
cwd βœ… Yes '-scripts'

Variables are resolved from:

Examples

Basic Node.js Script Execution

{
  "id": "run-setup",
  "name": "Run Setup Script",
  "type": "exec-file",
  "config": {
    "file": "scripts/setup.js",
    "runtime": "node"
  }
}

Script with Variable Interpolation

{
  "id": "run-project-setup",
  "name": "Run Project-Specific Setup",
  "type": "exec-file",
  "config": {
    "file": "scripts/-setup.js",
    "runtime": "node"
  }
}

Script with Arguments

{
  "id": "configure-project",
  "name": "Configure Project",
  "type": "exec-file",
  "config": {
    "file": "scripts/configure.js",
    "runtime": "node",
    "args": ["--name=", "--author=", "--license="]
  }
}

Script with Environment Variables

{
  "id": "build-project",
  "name": "Build Project",
  "type": "exec-file",
  "config": {
    "file": "scripts/build.js",
    "runtime": "node",
    "parameters": {
      "PROJECT_NAME": "",
      "BUILD_ENV": "",
      "AUTHOR": ""
    }
  }
}

Script with Custom Working Directory

{
  "id": "run-in-subdir",
  "name": "Run Script in Subdirectory",
  "type": "exec-file",
  "config": {
    "file": "scripts/build.js",
    "runtime": "node",
    "cwd": "packages/"
  }
}

Remote Script Execution

Execute a script from a remote URL:

{
  "id": "run-remote-setup",
  "name": "Run Remote Setup Script",
  "type": "exec-file",
  "config": {
    "file": "https://raw.githubusercontent.com/your-org/scripts/main/setup.js",
    "runtime": "node",
    "args": ["--project="]
  }
}

Note: Remote scripts are fetched, saved to a temporary file, executed, and then cleaned up automatically.

Conditional Execution

{
  "id": "optional-setup",
  "name": "Optional Setup Script",
  "type": "exec-file",
  "config": {
    "file": "scripts/optional-setup.js",
    "runtime": "node",
    "condition": "includeOptionalSetup === true"
  }
}

Bash Script Execution

{
  "id": "run-bash-script",
  "name": "Run Bash Setup",
  "type": "exec-file",
  "config": {
    "file": "scripts/setup.sh",
    "runtime": "bash",
    "args": [""]
  }
}

PowerShell Script Execution

{
  "id": "run-powershell-script",
  "name": "Run PowerShell Setup",
  "type": "exec-file",
  "config": {
    "file": "scripts/setup.ps1",
    "runtime": "pwsh",
    "parameters": {
      "ProjectName": ""
    }
  }
}

Complete Example with Prompts

{
  "prompts": [
    {
      "id": "projectName",
      "type": "input",
      "message": "What is your project name?",
      "default": "my-project"
    },
    {
      "id": "author",
      "type": "input",
      "message": "Author name?",
      "default": "Your Name"
    },
    {
      "id": "runSetup",
      "type": "confirm",
      "message": "Run setup script?",
      "default": true
    }
  ],
  "tasks": [
    {
      "id": "run-setup-script",
      "name": "Run Project Setup Script",
      "description": "Executes the project setup script with user-provided values",
      "required": true,
      "enabled": true,
      "type": "exec-file",
      "config": {
        "file": "scripts/setup.js",
        "runtime": "node",
        "args": ["--name=", "--author="],
        "parameters": {
          "PROJECT_NAME": "",
          "AUTHOR": ""
        },
        "condition": "runSetup === true"
      }
    }
  ]
}

Script Access to Variables

Via Command-Line Arguments

Scripts can access interpolated arguments:

Task config:

{
  "args": ["--name=", "--author="]
}

Node.js script:

const args = process.argv.slice(2);
// args = ['--name=my-project', '--author=John Doe']

Via Environment Variables

Scripts can access interpolated environment variables:

Task config:

{
  "parameters": {
    "PROJECT_NAME": "",
    "AUTHOR": ""
  }
}

Node.js script:

const projectName = process.env.PROJECT_NAME;
const author = process.env.AUTHOR;

Bash script:

#!/bin/bash
echo "Project: $PROJECT_NAME"
echo "Author: $AUTHOR"

Remote vs Local Scripts

Local Scripts

Remote Scripts

Comparison with exec Plugin

Feature exec Plugin exec-file Plugin
Inline commands βœ… Yes ❌ No
External script files ❌ No βœ… Yes
Remote scripts ❌ No βœ… Yes
Multiple runtimes ❌ No βœ… Yes
Variable interpolation βœ… Yes (in command) βœ… Yes (in file, args, params, cwd)
Environment variables βœ… Yes (inherited) βœ… Yes (custom parameters)

Use Cases

  1. Project Initialization Scripts

    {
      "file": "scripts/init-.js",
      "runtime": "node",
      "args": ["--name="]
    }
    
  2. Remote Configuration Scripts

    {
      "file": "https://example.com/configs/setup.js",
      "runtime": "node"
    }
    
  3. Cross-Platform Scripts

    {
      "file": "scripts/setup.ps1",
      "runtime": "pwsh",
      "parameters": { "Name": "" }
    }
    
  4. Conditional Setup

    {
      "file": "scripts/advanced-setup.js",
      "runtime": "node",
      "condition": "advancedMode === true"
    }
    

Using exec-file in Variables and Prompts

The exec-file plugin can also be used in variable values and prompt defaults to dynamically resolve values by executing script files.

In Variables

Execute a script file and use its output as a variable value:

{
  "variables": [
    {
      "id": "currentVersion",
      "value": {
        "type": "exec-file",
        "file": "scripts/get-version.js"
      }
    },
    {
      "id": "gitBranch",
      "value": {
        "type": "exec-file",
        "file": "scripts/get-branch.sh",
        "runtime": "bash"
      }
    },
    {
      "id": "envConfig",
      "value": {
        "type": "exec-file",
        "file": "scripts/get-config.js",
        "args": ["--env="],
        "parameters": {
          "CONFIG_PATH": ""
        }
      }
    }
  ]
}

Script Output Parsing:

Example script for version (scripts/get-version.js):

const package = require('./package.json');
console.log(package.version); // Output: "1.2.3"

In Prompt Defaults

Execute a script to provide dynamic default values for prompts:

{
  "prompts": [
    {
      "id": "projectName",
      "type": "input",
      "message": "Project name:",
      "default": {
        "type": "exec-file",
        "file": "scripts/suggest-name.js"
      }
    },
    {
      "id": "gitUser",
      "type": "input",
      "message": "Git username:",
      "default": {
        "type": "exec-file",
        "file": "scripts/get-git-user.sh",
        "runtime": "bash"
      }
    },
    {
      "id": "useTypeScript",
      "type": "confirm",
      "message": "Use TypeScript?",
      "default": {
        "type": "exec-file",
        "file": "scripts/detect-ts.js"
      }
    }
  ]
}

Example script for boolean default (scripts/detect-ts.js):

const fs = require('node:fs');

const hasTsConfig = fs.existsSync('tsconfig.json');
console.log(hasTsConfig); // Output: true or false

Runtime Auto-Detection in Values

Runtime is automatically detected from file extension, even in variables and prompts:

{
  "variables": [
    {
      "id": "nodePath",
      "value": {
        "type": "exec-file",
        "file": "scripts/find-node.sh"
        // Runtime automatically detected as 'bash' from .sh extension
      }
    }
  ]
}

Best Practices

  1. Use Relative Paths: Reference scripts relative to your configuration for portability
  2. Version Remote Scripts: Use versioned URLs or commit hashes for remote scripts
  3. Error Handling: Scripts should return appropriate exit codes
  4. Security: Only execute trusted scripts, especially from remote sources
  5. Cross-Platform: Use Node.js for cross-platform scripts when possible
  6. Documentation: Document what your scripts do and what arguments they accept

Error Handling

The plugin will throw an error if:

Security Considerations

See Also