Processes
Run commands and capture stdout, stderr, and exit code.
Strapkit gives you two ways to run commands:
sk.exec(script, opts?)— run a script, capture{ stdout, stderr, exitCode }.sk.shellExec(command)— fire-and-forget into the interactive terminal.
sk.exec(script, opts?)
exec(
script: string,
opts?: {
env?: Record<string, string>;
cwd?: string;
stdin?: string;
args?: string[];
terminal?: Terminal;
onStdout?: (text: string) => void;
onStderr?: (text: string) => void;
},
): Promise<{ stdout: string; stderr: string; exitCode: number }>Runs script as a shell snippet. Returns the captured stdout, stderr,
and the exit code of the last command in the script.
const result = await sk.exec('echo hello');
console.log(result.stdout); // "hello\n"
console.log(result.exitCode); // 0Multi-line scripts work the same way, including pipes and chains:
await sk.exec(`
cd /app
echo "{ \\"name\\": \\"demo\\" }" > package.json
cat package.json | grep name
`);opts.env
Environment variables for this call only:
await sk.exec('echo $NODE_ENV', { env: { NODE_ENV: 'production' } });opts.cwd
Working directory for this call:
await sk.exec('npm install', { cwd: '/app' });opts.stdin (alias: opts.input)
Feed text to the script's stdin:
const { stdout } = await sk.exec('grep TODO', {
stdin: 'one\nTODO: two\nthree\n',
});input is accepted as an alias for stdin. When both are present,
stdin wins.
opts.args
Additional argv appended to the script, shell-quoted automatically. Use this when arguments come from user input — no escaping needed:
const search = document.querySelector('#search').value;
const { stdout } = await sk.exec('grep', {
args: ['-r', search, '/app/src'],
});opts.terminal
Mirror output live into an xterm.js Terminal as it streams in.
The terminal gets raw bytes (with ANSI colors and spinner animations);
the captured stdout/stderr are ANSI-stripped.
await sk.exec('npm install', { terminal: term });opts.onStdout / opts.onStderr
Per-chunk callbacks for streaming output. Called with raw bytes
(ANSI included), same as what terminal receives.
await sk.exec('npm install', {
onStdout: (chunk) => console.log(chunk),
});Calls run one at a time
exec calls are queued — a second call waits for the first to finish.
This is by design: the runtime has a small pool of child slots that
can be exhausted by big commands (npx create-next-app uses all of
them while it works).
If you want to run commands in parallel, run them as one script with
& and wait:
await sk.exec(`
long-task-1 &
long-task-2 &
wait
`);Limitations
- Long-running servers block.
exec("node server.js")won't resolve until the server exits. For servers, useshellExecand watchonPortOpen. - Each call starts fresh. A
cdinside oneexecdoesn't carry over to the next (unless you useopts.cwd). Put related commands in the same script if you need shared state.
sk.shellExec(command)
shellExec(command: string): voidType command into the running shell, followed by a newline — exactly
as if the user had pressed enter at the prompt. Output goes to the
xterm.js terminal (or wherever the shell's output is wired); nothing
is returned. Throws if no shell is running.
This is the right tool for long-running or interactive flows: starting a dev server, running a TUI, or wiring a "run this" button in your UI.
sk.shellExec('npm run dev');For everything else, prefer exec — you get the output back as a
value instead of having to scrape it from the terminal.