CLI nodes in NebulaFlow execute shell commands and scripts via Node.js child_process. This guide covers configuration, usage, and best practices for CLI integration.
interface CLINode {
type: NodeType.CLI
data: {
title: string
content: string // Command to execute
active: boolean
mode?: 'command' | 'script'
shell?: 'bash' | 'sh' | 'zsh' | 'pwsh' | 'cmd'
safetyLevel?: 'safe' | 'advanced'
streamOutput?: boolean
stdin?: {
source?: 'none' | 'parents-all' | 'parent-index' | 'literal'
parentIndex?: number
literal?: string
stripCodeFences?: boolean
normalizeCRLF?: boolean
}
env?: {
exposeParents?: boolean
names?: string[]
static?: Record<string, string>
}
flags?: {
exitOnError?: boolean
unsetVars?: boolean
pipefail?: boolean
noProfile?: boolean
nonInteractive?: boolean
executionPolicyBypass?: boolean
}
}
}
{
type: NodeType.CLI,
data: {
title: 'Git Status',
content: 'git status',
active: true,
mode: 'command',
shell: 'bash',
streamOutput: true
}
}
{
type: NodeType.CLI,
data: {
title: 'Process File',
content: 'cat ${1} | grep "error"',
active: true,
mode: 'command',
stdin: {
source: 'parent-index',
parentIndex: 0
}
}
}
{
type: NodeType.CLI,
data: {
title: 'Run Script',
content: '#!/bin/bash\necho "Hello from script"\nls -la',
active: true,
mode: 'script',
shell: 'bash'
}
}
{
type: NodeType.CLI,
data: {
title: 'Build with Env',
content: 'npm run build',
active: true,
env: {
static: {
NODE_ENV: 'production',
API_KEY: '${apiKey}'
},
exposeParents: true,
names: ['PATH', 'HOME']
}
}
}
{
type: NodeType.CLI,
data: {
title: 'Delete Files',
content: 'rm -rf /tmp/temp-*',
active: true,
safetyLevel: 'safe',
needsUserApproval: true
}
}
{
type: NodeType.CLI,
data: {
title: 'System Cleanup',
content: 'sudo apt-get autoremove -y',
active: true,
safetyLevel: 'advanced',
flags: {
executionPolicyBypass: true
},
dangerouslyAllowAll: true
}
}
Default mode - Execute a single command:
{
data: {
mode: 'command',
content: 'git status'
}
}
Use when:
Execute multi-line scripts:
{
data: {
mode: 'script',
content: `#!/bin/bash
echo "Starting build..."
npm install
npm run build
echo "Build complete!"`
}
}
Use when:
| Shell | Platform | Use Case |
|---|---|---|
bash |
Linux/macOS | Default, feature-rich |
sh |
Unix | Minimal, portable |
zsh |
Linux/macOS | Advanced features |
pwsh |
Windows | PowerShell Core |
cmd |
Windows | Legacy Windows |
{
data: {
shell: 'bash' // Choose based on platform
}
}
Best practice: Use platform-appropriate shell:
// For cross-platform workflows
{
data: {
shell: process.platform === 'win32' ? 'cmd' : 'bash'
}
}
No stdin input:
{
data: {
stdin: {
source: 'none'
}
}
}
Input from specific parent node:
{
data: {
stdin: {
source: 'parent-index',
parentIndex: 0 // First parent
}
}
}
Input from all parent nodes:
{
data: {
stdin: {
source: 'parents-all'
}
}
}
Static input string:
{
data: {
stdin: {
source: 'literal',
literal: 'Hello, World!'
}
}
}
Remove markdown code fences:
{
data: {
stdin: {
source: 'parent-index',
parentIndex: 0,
stripCodeFences: true
}
}
}
Convert Windows line endings:
{
data: {
stdin: {
source: 'parent-index',
parentIndex: 0,
normalizeCRLF: true
}
}
}
Define variables directly:
{
data: {
env: {
static: {
NODE_ENV: 'production',
API_KEY: '${apiKey}',
PATH: '/usr/local/bin:${PATH}'
}
}
}
}
Inherit variables from parent nodes:
{
data: {
env: {
exposeParents: true
}
}
}
Select specific environment variables:
{
data: {
env: {
names: ['PATH', 'HOME', 'USER']
}
}
}
Use template variables in commands:
{
data: {
content: 'echo "Hello ${userName}"',
env: {
static: {
userName: '${user.name}'
}
}
}
}
Stop execution on command failure:
{
data: {
flags: {
exitOnError: true
}
}
}
Clear inherited variables:
{
data: {
flags: {
unsetVars: true
}
}
}
Fail if any command in pipe fails:
{
data: {
flags: {
pipefail: true
}
}
}
Skip shell profile loading:
{
data: {
flags: {
noProfile: true
}
}
}
Run in non-interactive mode:
{
data: {
flags: {
nonInteractive: true
}
}
}
Bypass safety checks (use with caution):
{
data: {
flags: {
executionPolicyBypass: true
},
dangerouslyAllowAll: true
}
}
Features:
Use when:
Example:
{
data: {
safetyLevel: 'safe',
needsUserApproval: true
}
}
Features:
Use when:
Example:
{
data: {
safetyLevel: 'advanced',
flags: {
executionPolicyBypass: true
},
dangerouslyAllowAll: true
}
}
pending_approvalThe dialog shows:
Warning: Only use in trusted environments.
{
data: {
dangerouslyAllowAll: true,
flags: {
executionPolicyBypass: true
}
}
}
Enable real-time output streaming:
{
data: {
streamOutput: true
}
}
Streaming output is sent via events:
{
type: 'node_output_chunk',
data: {
nodeId: 'cli-node-1',
chunk: 'Building project...\n',
stream: 'stdout'
}
}
stdout: Standard output
{ stream: 'stdout' }
stderr: Error output
{ stream: 'stderr' }
{
data: {
title: 'List Files',
content: 'ls -la',
streamOutput: true
}
}
{
data: {
title: 'Copy Files',
content: 'cp -r ${source} ${destination}',
env: {
static: {
source: '${sourcePath}',
destination: '${destPath}'
}
}
}
}
{
data: {
title: 'Search Files',
content: 'find . -name "*.js" -type f',
streamOutput: true
}
}
{
data: {
title: 'Git Status',
content: 'git status',
streamOutput: true
}
}
{
data: {
title: 'Git Commit',
content: 'git commit -m "${message}"',
env: {
static: {
message: '${commitMessage}'
}
}
}
}
{
data: {
title: 'Git Push',
content: 'git push origin ${branch}',
env: {
static: {
branch: '${gitBranch}'
}
}
}
}
{
data: {
title: 'Install Dependencies',
content: 'npm install',
streamOutput: true
}
}
{
data: {
title: 'Build Project',
content: 'npm run build',
env: {
static: {
NODE_ENV: 'production'
}
},
streamOutput: true
}
}
{
data: {
title: 'Run Tests',
content: 'npm test',
streamOutput: true
}
}
{
data: {
title: 'System Info',
content: 'uname -a && free -h && df -h',
streamOutput: true
}
}
{
data: {
title: 'List Processes',
content: 'ps aux | grep node',
streamOutput: true
}
}
{
data: {
title: 'Disk Usage',
content: 'du -sh * | sort -hr',
streamOutput: true
}
}
{
data: {
title: 'Fetch API Data',
content: 'curl https://api.example.com/data',
streamOutput: true
}
}
{
data: {
title: 'Send Data',
content: 'curl -X POST -H "Content-Type: application/json" -d \'${data}\' https://api.example.com/data',
stdin: {
source: 'parent-index',
parentIndex: 0
}
}
}
{
data: {
title: 'Authenticated Request',
content: 'curl -H "Authorization: Bearer ${apiKey}" https://api.example.com/protected',
env: {
static: {
apiKey: '${apiKey}'
}
}
}
}
CLI Node A (command 1)
└── CLI Node B (command 2)
└── CLI Node C (command 3)
Example:
npm install
└── npm run build
└── npm test
CLI Node A ──┐
CLI Node B ──┤ → CLI Node D
CLI Node C ──┘
Example:
Build A ──┐
Build B ──┤ → Deploy
Build C ──┘
Text Node (input)
└── CLI Node (process input)
└── Preview Node (result)
Example:
"File path: /path/to/file.txt"
└── cat ${1}
└── Display content
IF Node (condition)
├── True: CLI (command A)
└── False: CLI (command B)
Example:
IF file exists
├── True: cat file.txt
└── False: echo "File not found"
Loop Start (iterations=5)
└── CLI Node (process item ${i})
Loop End
Example:
Loop Start (i=0 to 4)
└── process item ${i}
Loop End
Never directly interpolate user input:
// Bad: Direct interpolation
content: "echo ${userInput}" // Risk of injection
// Good: Use stdin
stdin: {
source: 'parent-index',
parentIndex: 0
}
content: "cat"
Avoid or require approval:
rm -rf /sudoformatshutdownRestrict access:
{
data: {
flags: {
executionPolicyBypass: false
},
disabledTools: ['filesystem']
}
}
Don’t expose sensitive variables:
// Bad: Exposing all variables
env: { exposeParents: true }
// Good: Selective exposure
env: {
names: ['PATH', 'HOME']
}
Cause: Command not in PATH
Solution:
{
data: {
content: "/full/path/to/command",
env: { exposeParents: true }
}
}
Cause: Insufficient permissions
Solution:
{
data: {
content: "chmod +x script.sh && ./script.sh",
flags: { executionPolicyBypass: true }
}
}
Cause: Command taking too long
Solution:
{
data: {
content: "long-running-command",
flags: { exitOnError: true }
}
}
Cause: Command failed
Solution:
{
data: {
flags: { exitOnError: true }
}
}
Enable streaming:
{
data: {
streamOutput: true
}
}
Check exit codes:
// CLI nodes return exit code in result
// Check for non-zero exit codes
Log execution:
{
data: {
title: 'Debug Command',
content: 'set -x && your-command',
streamOutput: true
}
}
{
data: {
content: 'source ~/.bashrc && your-command',
shell: 'bash',
flags: {
noProfile: false // Load profile
}
}
}
{
data: {
content: 'long-running-command',
flags: {
exitOnError: true // Fail on timeout
}
}
}
{
data: {
content: 'resource-intensive-command',
env: {
static: {
NODE_OPTIONS: '--max-old-space-size=4096'
}
}
}
}
// Use workflow parallelism
// Set concurrency limits in workflow settings
{
data: {
content: 'build-command',
streamOutput: true
}
}