just-bash 2.13.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +302 -314
- package/dist/AGENTS.md +2 -0
- package/dist/bin/chunks/{chunk-N6KA6G3Q.js → chunk-3KAVXQP4.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-OQV5J23L.js → chunks/chunk-7G3MC56B.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-YX7OOTPO.js → chunks/chunk-AZ3RUDR2.js} +1 -1
- package/dist/bin/chunks/{chunk-UPUMZYZE.js → chunk-CM4532DS.js} +18 -18
- package/dist/bin/{shell/chunks/chunk-R2LDP472.js → chunks/chunk-EPPBDXOG.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-LGF54XJQ.js → chunks/chunk-L2JBII6Z.js} +1 -1
- package/dist/bin/chunks/chunk-LIYVQA3X.js +2 -0
- package/dist/bin/{shell/chunks/chunk-SYL34GE7.js → chunks/chunk-NAX7MTAR.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-EZS766DD.js → chunks/chunk-NLBRLRWD.js} +1 -1
- package/dist/bin/chunks/chunk-RLNOQILG.js +2 -0
- package/dist/bin/chunks/{chunk-VVFGRIJZ.js → chunk-RMQC3GS7.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-GR23MPTT.js → chunks/chunk-VHUYNUT7.js} +1 -1
- package/dist/bin/chunks/{chunk-3YMCKZTY.js → chunk-WXMBDX4P.js} +1 -1
- package/dist/bin/chunks/curl-SRTMGOVV.js +26 -0
- package/dist/bin/chunks/expr-4CJYC4LY.js +2 -0
- package/dist/bin/{shell/chunks/flag-coverage-IRM4GISL.js → chunks/flag-coverage-LBMWMYOO.js} +1 -1
- package/dist/bin/{shell/chunks/jq-V7FYGIKO.js → chunks/jq-FIV5Q5T4.js} +1 -1
- package/dist/bin/{shell/chunks/js-exec-VYG74FQ3.js → chunks/js-exec-BDQGEAU6.js} +8 -8
- package/dist/bin/chunks/js-exec-worker.js +1 -0
- package/dist/bin/{shell/chunks/ln-VAOSD4HK.js → chunks/ln-EGC4HRXZ.js} +1 -1
- package/dist/bin/chunks/{mkdir-CH7JGW4N.js → mkdir-Z47OISSR.js} +1 -1
- package/dist/bin/chunks/python3-VCIXXAXF.js +12 -0
- package/dist/bin/chunks/{rm-GWYJO4W7.js → rm-L3NZOLLG.js} +1 -1
- package/dist/bin/chunks/{sed-3C6IBX5L.js → sed-HALRQZKY.js} +1 -1
- package/dist/bin/chunks/{sqlite3-TZEE4O7U.js → sqlite3-CVNFMP3Z.js} +1 -1
- package/dist/bin/chunks/time-5R4QWCYF.js +2 -0
- package/dist/bin/{shell/chunks/tr-LZF57GYP.js → chunks/tr-4FPGAEVB.js} +1 -1
- package/dist/bin/chunks/worker.js +20 -7
- package/dist/bin/chunks/{yq-JJLSDDST.js → yq-Q47JUWL6.js} +1 -1
- package/dist/bin/just-bash.js +178 -178
- package/dist/bin/shell/chunks/{chunk-N6KA6G3Q.js → chunk-3KAVXQP4.js} +1 -1
- package/dist/bin/{chunks/chunk-OQV5J23L.js → shell/chunks/chunk-7G3MC56B.js} +1 -1
- package/dist/bin/{chunks/chunk-YX7OOTPO.js → shell/chunks/chunk-AZ3RUDR2.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-UPUMZYZE.js → chunk-CM4532DS.js} +18 -18
- package/dist/bin/{chunks/chunk-R2LDP472.js → shell/chunks/chunk-EPPBDXOG.js} +1 -1
- package/dist/bin/{chunks/chunk-LGF54XJQ.js → shell/chunks/chunk-L2JBII6Z.js} +1 -1
- package/dist/bin/shell/chunks/chunk-LIYVQA3X.js +2 -0
- package/dist/bin/{chunks/chunk-SYL34GE7.js → shell/chunks/chunk-NAX7MTAR.js} +1 -1
- package/dist/bin/{chunks/chunk-EZS766DD.js → shell/chunks/chunk-NLBRLRWD.js} +1 -1
- package/dist/bin/shell/chunks/chunk-RLNOQILG.js +2 -0
- package/dist/bin/shell/chunks/{chunk-VVFGRIJZ.js → chunk-RMQC3GS7.js} +1 -1
- package/dist/bin/{chunks/chunk-GR23MPTT.js → shell/chunks/chunk-VHUYNUT7.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-3YMCKZTY.js → chunk-WXMBDX4P.js} +1 -1
- package/dist/bin/shell/chunks/curl-SRTMGOVV.js +26 -0
- package/dist/bin/shell/chunks/expr-4CJYC4LY.js +2 -0
- package/dist/bin/{chunks/flag-coverage-IRM4GISL.js → shell/chunks/flag-coverage-LBMWMYOO.js} +1 -1
- package/dist/bin/{chunks/jq-V7FYGIKO.js → shell/chunks/jq-FIV5Q5T4.js} +1 -1
- package/dist/bin/{chunks/js-exec-YGYYZEEQ.js → shell/chunks/js-exec-HPXZV7UJ.js} +8 -8
- package/dist/bin/{chunks/ln-VAOSD4HK.js → shell/chunks/ln-EGC4HRXZ.js} +1 -1
- package/dist/bin/shell/chunks/{mkdir-CH7JGW4N.js → mkdir-Z47OISSR.js} +1 -1
- package/dist/bin/shell/chunks/python3-KFZH67GD.js +12 -0
- package/dist/bin/shell/chunks/{rm-GWYJO4W7.js → rm-L3NZOLLG.js} +1 -1
- package/dist/bin/shell/chunks/{sed-3C6IBX5L.js → sed-HALRQZKY.js} +1 -1
- package/dist/bin/shell/chunks/{sqlite3-TZEE4O7U.js → sqlite3-CVNFMP3Z.js} +1 -1
- package/dist/bin/shell/chunks/time-5R4QWCYF.js +2 -0
- package/dist/bin/{chunks/tr-LZF57GYP.js → shell/chunks/tr-4FPGAEVB.js} +1 -1
- package/dist/bin/shell/chunks/{yq-JJLSDDST.js → yq-Q47JUWL6.js} +1 -1
- package/dist/bin/shell/shell.js +180 -180
- package/dist/bundle/browser.js +485 -485
- package/dist/bundle/chunks/chunk-3THT3N7L.js +1 -0
- package/dist/bundle/chunks/{chunk-XXZ46GOX.js → chunk-62RKD26F.js} +1 -1
- package/dist/bundle/chunks/chunk-CWQS3NFK.js +1 -0
- package/dist/bundle/chunks/{chunk-IUWCBQII.js → chunk-HWBSOZZR.js} +18 -18
- package/dist/bundle/chunks/{chunk-64CW2LGZ.js → chunk-MDDMCKUK.js} +1 -1
- package/dist/bundle/chunks/{chunk-IP7G3BNA.js → chunk-MIZPJHVH.js} +1 -1
- package/dist/bundle/chunks/{chunk-V3IEYMEA.js → chunk-OL3S66CO.js} +1 -1
- package/dist/bundle/chunks/{chunk-FGALERPA.js → chunk-PBXLG62G.js} +1 -1
- package/dist/bundle/chunks/{chunk-MJWMXCEJ.js → chunk-S4EYC6T6.js} +1 -1
- package/dist/bundle/chunks/{chunk-O2DBFL6Z.js → chunk-XORM457F.js} +1 -1
- package/dist/bundle/chunks/{chunk-RUF7WQ7U.js → chunk-YCFVLTST.js} +1 -1
- package/dist/bundle/chunks/{chunk-RVT3MU3A.js → chunk-YFG2CMIF.js} +1 -1
- package/dist/bundle/chunks/{chunk-JCMONG3T.js → chunk-Z6LRHWXI.js} +1 -1
- package/dist/bundle/chunks/curl-COE4TZE6.js +25 -0
- package/dist/bundle/chunks/expr-5T3UU5KE.js +1 -0
- package/dist/bundle/chunks/{flag-coverage-SPT2DN2I.js → flag-coverage-LMTH7T5F.js} +1 -1
- package/dist/bundle/chunks/{jq-DIRZBOTX.js → jq-ODXZBPLY.js} +1 -1
- package/dist/bundle/chunks/{js-exec-R2LSP7M4.js → js-exec-4CW5N6RM.js} +8 -8
- package/dist/bundle/chunks/js-exec-worker.js +1 -0
- package/dist/bundle/chunks/{ln-UJ6YJVBK.js → ln-4TRFBYAT.js} +1 -1
- package/dist/bundle/chunks/{mkdir-F6XHPXZC.js → mkdir-TDEMSB6C.js} +1 -1
- package/dist/bundle/chunks/python3-SG3DOKBZ.js +11 -0
- package/dist/bundle/chunks/{rm-FYNVTQIU.js → rm-RTZG23RL.js} +1 -1
- package/dist/bundle/chunks/{sed-DISNI47D.js → sed-VFTTATXJ.js} +1 -1
- package/dist/bundle/chunks/{sqlite3-7F22DOIP.js → sqlite3-56UMWEY3.js} +1 -1
- package/dist/bundle/chunks/time-DEUO3QV2.js +1 -0
- package/dist/bundle/chunks/{tr-GVTWMRZB.js → tr-2HXZRDSW.js} +1 -1
- package/dist/bundle/chunks/worker.js +20 -7
- package/dist/bundle/chunks/{yq-XMVSIL6Z.js → yq-MJMAR36V.js} +1 -1
- package/dist/bundle/index.cjs +771 -771
- package/dist/bundle/index.js +185 -185
- package/dist/commands/curl/types.d.ts +1 -1
- package/dist/fs/sanitize-error.d.ts +9 -6
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/network/allow-list.d.ts +8 -5
- package/dist/network/fetch.d.ts +1 -1
- package/dist/network/index.d.ts +1 -1
- package/dist/network/types.d.ts +35 -1
- package/package.json +2 -2
- package/dist/bin/chunks/chunk-QZNF3Y3J.js +0 -2
- package/dist/bin/chunks/chunk-SYG3IW7P.js +0 -2
- package/dist/bin/chunks/curl-B64SIJOD.js +0 -26
- package/dist/bin/chunks/expr-VEFRBJT4.js +0 -2
- package/dist/bin/chunks/python3-EIXZW3LO.js +0 -12
- package/dist/bin/chunks/time-VSKBXRQH.js +0 -2
- package/dist/bin/shell/chunks/chunk-QZNF3Y3J.js +0 -2
- package/dist/bin/shell/chunks/chunk-SYG3IW7P.js +0 -2
- package/dist/bin/shell/chunks/curl-B64SIJOD.js +0 -26
- package/dist/bin/shell/chunks/expr-VEFRBJT4.js +0 -2
- package/dist/bin/shell/chunks/python3-WO3WFGMS.js +0 -12
- package/dist/bin/shell/chunks/time-VSKBXRQH.js +0 -2
- package/dist/bundle/chunks/chunk-CCNMISUL.js +0 -1
- package/dist/bundle/chunks/chunk-RH6GWZAJ.js +0 -1
- package/dist/bundle/chunks/curl-FCIO57JJ.js +0 -25
- package/dist/bundle/chunks/expr-74QHYJL5.js +0 -1
- package/dist/bundle/chunks/python3-DH2SBOI3.js +0 -11
- package/dist/bundle/chunks/time-FABCOJJU.js +0 -1
package/README.md
CHANGED
|
@@ -1,68 +1,108 @@
|
|
|
1
1
|
# just-bash
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Table of Contents
|
|
12
|
-
|
|
13
|
-
- [Security model](#security-model)
|
|
14
|
-
- [Installation](#installation)
|
|
15
|
-
- [Usage](#usage)
|
|
16
|
-
- [Basic API](#basic-api)
|
|
17
|
-
- [Configuration](#configuration)
|
|
18
|
-
- [Custom Commands](#custom-commands)
|
|
19
|
-
- [Filesystem Options](#filesystem-options)
|
|
20
|
-
- [AI SDK Tool](#ai-sdk-tool)
|
|
21
|
-
- [Vercel Sandbox Compatible API](#vercel-sandbox-compatible-api)
|
|
22
|
-
- [CLI Binary](#cli-binary)
|
|
23
|
-
- [Interactive Shell](#interactive-shell)
|
|
24
|
-
- [Supported Commands](#supported-commands)
|
|
25
|
-
- [Shell Features](#shell-features)
|
|
26
|
-
- [Default Layout](#default-layout)
|
|
27
|
-
- [Network Access](#network-access)
|
|
28
|
-
- [JavaScript Support](#javascript-support)
|
|
29
|
-
- [Execution Protection](#execution-protection)
|
|
30
|
-
- [AST Transform Plugins](#ast-transform-plugins)
|
|
31
|
-
- [Development](#development)
|
|
32
|
-
|
|
33
|
-
## Security model
|
|
34
|
-
|
|
35
|
-
- The shell only has access to the provided file system.
|
|
36
|
-
- Execution is protected against infinite loops or recursion. However, Bash is not fully robust against DOS from input. If you need to be robust against this, use process isolation at the OS level.
|
|
37
|
-
- Binaries or even WASM are inherently unsupported (Use [Vercel Sandbox](https://vercel.com/docs/vercel-sandbox) or a similar product if a full VM is needed).
|
|
38
|
-
- There is no network access by default.
|
|
39
|
-
- Network access can be enabled, but requests are checked against URL prefix allow-lists and HTTP-method allow-lists. See [network access](#network-access) for details.
|
|
40
|
-
- Python and JS execution are off by default as they may represent additional security surface.
|
|
41
|
-
|
|
42
|
-
## Installation
|
|
3
|
+
A virtual bash environment with an in-memory filesystem, written in TypeScript and designed for AI agents.
|
|
4
|
+
|
|
5
|
+
Broad support for standard unix commands and bash syntax with optional curl, Python, JS/TS, and sqlite support.
|
|
6
|
+
|
|
7
|
+
**Note**: This is beta software. Use at your own risk and please provide feedback. See [security model](#security-model).
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
43
10
|
|
|
44
11
|
```bash
|
|
45
12
|
npm install just-bash
|
|
46
13
|
```
|
|
47
14
|
|
|
48
|
-
## Usage
|
|
49
|
-
|
|
50
|
-
### Basic API
|
|
51
|
-
|
|
52
15
|
```typescript
|
|
53
16
|
import { Bash } from "just-bash";
|
|
54
17
|
|
|
55
|
-
const
|
|
56
|
-
await
|
|
57
|
-
const result = await
|
|
18
|
+
const bash = new Bash();
|
|
19
|
+
await bash.exec('echo "Hello" > greeting.txt');
|
|
20
|
+
const result = await bash.exec("cat greeting.txt");
|
|
58
21
|
console.log(result.stdout); // "Hello\n"
|
|
59
22
|
console.log(result.exitCode); // 0
|
|
60
|
-
console.log(result.env); // Final environment after execution
|
|
61
23
|
```
|
|
62
24
|
|
|
63
|
-
Each `exec()`
|
|
25
|
+
Each `exec()` call gets its own isolated shell state — environment variables, functions, and working directory reset between calls. The **filesystem is shared** across calls, so files written in one `exec()` are visible in the next.
|
|
26
|
+
|
|
27
|
+
## Custom Commands
|
|
28
|
+
|
|
29
|
+
Extend just-bash with your own TypeScript commands using `defineCommand`:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { Bash, defineCommand } from "just-bash";
|
|
33
|
+
|
|
34
|
+
const hello = defineCommand("hello", async (args, ctx) => {
|
|
35
|
+
const name = args[0] || "world";
|
|
36
|
+
return { stdout: `Hello, ${name}!\n`, stderr: "", exitCode: 0 };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const upper = defineCommand("upper", async (args, ctx) => {
|
|
40
|
+
return { stdout: ctx.stdin.toUpperCase(), stderr: "", exitCode: 0 };
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const bash = new Bash({ customCommands: [hello, upper] });
|
|
44
|
+
|
|
45
|
+
await bash.exec("hello Alice"); // "Hello, Alice!\n"
|
|
46
|
+
await bash.exec("echo 'test' | upper"); // "TEST\n"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Custom commands receive a `CommandContext` with `fs`, `cwd`, `env`, `stdin`, and `exec` (for subcommands), and work with pipes, redirections, and all shell features.
|
|
50
|
+
|
|
51
|
+
<details>
|
|
52
|
+
<summary><h2>Supported Commands</h2></summary>
|
|
53
|
+
|
|
54
|
+
### File Operations
|
|
55
|
+
|
|
56
|
+
`cat`, `cp`, `file`, `ln`, `ls`, `mkdir`, `mv`, `readlink`, `rm`, `rmdir`, `split`, `stat`, `touch`, `tree`
|
|
57
|
+
|
|
58
|
+
### Text Processing
|
|
59
|
+
|
|
60
|
+
`awk`, `base64`, `column`, `comm`, `cut`, `diff`, `expand`, `fold`, `grep` (+ `egrep`, `fgrep`), `head`, `join`, `md5sum`, `nl`, `od`, `paste`, `printf`, `rev`, `rg`, `sed`, `sha1sum`, `sha256sum`, `sort`, `strings`, `tac`, `tail`, `tr`, `unexpand`, `uniq`, `wc`, `xargs`
|
|
61
|
+
|
|
62
|
+
### Data Processing
|
|
63
|
+
|
|
64
|
+
`jq` (JSON), `sqlite3` (SQLite), `xan` (CSV), `yq` (YAML/XML/TOML/CSV)
|
|
65
|
+
|
|
66
|
+
### Optional Runtimes
|
|
67
|
+
|
|
68
|
+
`js-exec` (JavaScript/TypeScript via QuickJS; requires `javascript: true`), `python3`/`python` (Python via CPython; requires `python: true`)
|
|
69
|
+
|
|
70
|
+
### Compression & Archives
|
|
71
|
+
|
|
72
|
+
`gzip` (+ `gunzip`, `zcat`), `tar`
|
|
73
|
+
|
|
74
|
+
### Navigation & Environment
|
|
75
|
+
|
|
76
|
+
`basename`, `cd`, `dirname`, `du`, `echo`, `env`, `export`, `find`, `hostname`, `printenv`, `pwd`, `tee`
|
|
77
|
+
|
|
78
|
+
### Shell Utilities
|
|
79
|
+
|
|
80
|
+
`alias`, `bash`, `chmod`, `clear`, `date`, `expr`, `false`, `help`, `history`, `seq`, `sh`, `sleep`, `time`, `timeout`, `true`, `unalias`, `which`, `whoami`
|
|
81
|
+
|
|
82
|
+
### Network
|
|
83
|
+
|
|
84
|
+
`curl`, `html-to-markdown` (require [network configuration](#network-access))
|
|
64
85
|
|
|
65
|
-
|
|
86
|
+
All commands support `--help` for usage information.
|
|
87
|
+
|
|
88
|
+
### Shell Features
|
|
89
|
+
|
|
90
|
+
- **Pipes**: `cmd1 | cmd2`
|
|
91
|
+
- **Redirections**: `>`, `>>`, `2>`, `2>&1`, `<`
|
|
92
|
+
- **Command chaining**: `&&`, `||`, `;`
|
|
93
|
+
- **Variables**: `$VAR`, `${VAR}`, `${VAR:-default}`
|
|
94
|
+
- **Positional parameters**: `$1`, `$2`, `$@`, `$#`
|
|
95
|
+
- **Glob patterns**: `*`, `?`, `[...]`
|
|
96
|
+
- **If statements**: `if COND; then CMD; elif COND; then CMD; else CMD; fi`
|
|
97
|
+
- **Functions**: `function name { ... }` or `name() { ... }`
|
|
98
|
+
- **Local variables**: `local VAR=value`
|
|
99
|
+
- **Loops**: `for`, `while`, `until`
|
|
100
|
+
- **Symbolic links**: `ln -s target link`
|
|
101
|
+
- **Hard links**: `ln target link`
|
|
102
|
+
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
## Configuration
|
|
66
106
|
|
|
67
107
|
```typescript
|
|
68
108
|
const env = new Bash({
|
|
@@ -108,57 +148,25 @@ await env.exec("cat <<EOF\n indented\nEOF", { rawScript: true });
|
|
|
108
148
|
| `signal` | `AbortSignal` | Cooperative cancellation; stops at next statement boundary |
|
|
109
149
|
| `rawScript` | `boolean` | Skip leading-whitespace normalization (default: `false`) |
|
|
110
150
|
|
|
111
|
-
|
|
151
|
+
## Filesystem Options
|
|
112
152
|
|
|
113
|
-
|
|
153
|
+
Four filesystem implementations:
|
|
154
|
+
|
|
155
|
+
**InMemoryFs** (default) - Pure in-memory filesystem, no disk access:
|
|
114
156
|
|
|
115
157
|
```typescript
|
|
158
|
+
import { Bash } from "just-bash";
|
|
159
|
+
|
|
116
160
|
const env = new Bash({
|
|
117
161
|
files: {
|
|
118
|
-
"/data/config.json":
|
|
162
|
+
"/data/config.json": '{"key": "value"}',
|
|
163
|
+
// Lazy: called on first read, cached. Never called if written before read.
|
|
164
|
+
"/data/large.csv": () => "col1,col2\na,b\n",
|
|
119
165
|
"/data/remote.txt": async () => (await fetch("https://example.com")).text(),
|
|
120
|
-
"/data/static.txt": "always loaded",
|
|
121
166
|
},
|
|
122
167
|
});
|
|
123
168
|
```
|
|
124
169
|
|
|
125
|
-
This is useful for large or expensive-to-compute content that may not be needed.
|
|
126
|
-
|
|
127
|
-
### Custom Commands
|
|
128
|
-
|
|
129
|
-
Extend just-bash with your own TypeScript commands using `defineCommand`:
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
import { Bash, defineCommand } from "just-bash";
|
|
133
|
-
|
|
134
|
-
const hello = defineCommand("hello", async (args, ctx) => {
|
|
135
|
-
const name = args[0] || "world";
|
|
136
|
-
return { stdout: `Hello, ${name}!\n`, stderr: "", exitCode: 0 };
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const upper = defineCommand("upper", async (args, ctx) => {
|
|
140
|
-
return { stdout: ctx.stdin.toUpperCase(), stderr: "", exitCode: 0 };
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
const bash = new Bash({ customCommands: [hello, upper] });
|
|
144
|
-
|
|
145
|
-
await bash.exec("hello Alice"); // "Hello, Alice!\n"
|
|
146
|
-
await bash.exec("echo 'test' | upper"); // "TEST\n"
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Custom commands receive the full `CommandContext` with access to `fs`, `cwd`, `env`, `stdin`, and `exec` for running subcommands.
|
|
150
|
-
|
|
151
|
-
### Filesystem Options
|
|
152
|
-
|
|
153
|
-
Four filesystem implementations are available:
|
|
154
|
-
|
|
155
|
-
**InMemoryFs** (default) - Pure in-memory filesystem, no disk access:
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
import { Bash } from "just-bash";
|
|
159
|
-
const env = new Bash(); // Uses InMemoryFs by default
|
|
160
|
-
```
|
|
161
|
-
|
|
162
170
|
**OverlayFs** - Copy-on-write over a real directory. Reads come from disk, writes stay in memory:
|
|
163
171
|
|
|
164
172
|
```typescript
|
|
@@ -172,7 +180,7 @@ await env.exec("cat package.json"); // reads from disk
|
|
|
172
180
|
await env.exec('echo "modified" > package.json'); // stays in memory
|
|
173
181
|
```
|
|
174
182
|
|
|
175
|
-
**ReadWriteFs** - Direct read-write access to a real directory. Use this if you want the agent to be
|
|
183
|
+
**ReadWriteFs** - Direct read-write access to a real directory. Use this if you want the agent to be able to write to your disk:
|
|
176
184
|
|
|
177
185
|
```typescript
|
|
178
186
|
import { Bash } from "just-bash";
|
|
@@ -184,6 +192,8 @@ const env = new Bash({ fs: rwfs });
|
|
|
184
192
|
await env.exec('echo "hello" > file.txt'); // writes to real filesystem
|
|
185
193
|
```
|
|
186
194
|
|
|
195
|
+
Keep `ReadWriteFs` pointed at a workspace directory, not at the installed `just-bash` package or any other trusted runtime code. Guest-writable roots should stay separate from trusted code.
|
|
196
|
+
|
|
187
197
|
**MountableFs** - Mount multiple filesystems at different paths. Combines read-only and read-write filesystems into a unified namespace:
|
|
188
198
|
|
|
189
199
|
```typescript
|
|
@@ -222,167 +232,11 @@ const fs = new MountableFs({
|
|
|
222
232
|
});
|
|
223
233
|
```
|
|
224
234
|
|
|
225
|
-
|
|
235
|
+
## Optional Capabilities
|
|
226
236
|
|
|
227
|
-
|
|
237
|
+
### Network Access
|
|
228
238
|
|
|
229
|
-
|
|
230
|
-
npm install bash-tool
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
```typescript
|
|
234
|
-
import { createBashTool } from "bash-tool";
|
|
235
|
-
import { generateText } from "ai";
|
|
236
|
-
|
|
237
|
-
const bashTool = createBashTool({
|
|
238
|
-
files: { "/data/users.json": '[{"name": "Alice"}, {"name": "Bob"}]' },
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const result = await generateText({
|
|
242
|
-
model: "anthropic/claude-sonnet-4",
|
|
243
|
-
tools: { bash: bashTool },
|
|
244
|
-
prompt: "Count the users in /data/users.json",
|
|
245
|
-
});
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
See the [bash-tool documentation](https://github.com/vercel-labs/bash-tool) for more details and examples.
|
|
249
|
-
|
|
250
|
-
### Vercel Sandbox Compatible API
|
|
251
|
-
|
|
252
|
-
Bash provides a `Sandbox` class that's API-compatible with [`@vercel/sandbox`](https://vercel.com/docs/vercel-sandbox), making it easy to swap implementations. You can start with Bash and switch to a real sandbox when you need the power of a full VM (e.g. to run node, python, or custom binaries).
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
import { Sandbox } from "just-bash";
|
|
256
|
-
|
|
257
|
-
// Create a sandbox instance
|
|
258
|
-
const sandbox = await Sandbox.create({ cwd: "/app" });
|
|
259
|
-
|
|
260
|
-
// Write files to the virtual filesystem
|
|
261
|
-
await sandbox.writeFiles({
|
|
262
|
-
"/app/script.sh": 'echo "Hello World"',
|
|
263
|
-
"/app/data.json": '{"key": "value"}',
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// Run commands and get results
|
|
267
|
-
const cmd = await sandbox.runCommand("bash /app/script.sh");
|
|
268
|
-
const output = await cmd.stdout(); // "Hello World\n"
|
|
269
|
-
const exitCode = (await cmd.wait()).exitCode; // 0
|
|
270
|
-
|
|
271
|
-
// Read files back
|
|
272
|
-
const content = await sandbox.readFile("/app/data.json");
|
|
273
|
-
|
|
274
|
-
// Create directories
|
|
275
|
-
await sandbox.mkDir("/app/logs", { recursive: true });
|
|
276
|
-
|
|
277
|
-
// Clean up (no-op for Bash, but API-compatible)
|
|
278
|
-
await sandbox.stop();
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
### CLI Binary
|
|
282
|
-
|
|
283
|
-
After installing globally (`npm install -g just-bash`), use the `just-bash` command as a secure alternative to `bash` for AI agents:
|
|
284
|
-
|
|
285
|
-
```bash
|
|
286
|
-
# Execute inline script
|
|
287
|
-
just-bash -c 'ls -la && cat package.json | head -5'
|
|
288
|
-
|
|
289
|
-
# Execute with specific project root
|
|
290
|
-
just-bash -c 'grep -r "TODO" src/' --root /path/to/project
|
|
291
|
-
|
|
292
|
-
# Pipe script from stdin
|
|
293
|
-
echo 'find . -name "*.ts" | wc -l' | just-bash
|
|
294
|
-
|
|
295
|
-
# Execute a script file
|
|
296
|
-
just-bash ./scripts/deploy.sh
|
|
297
|
-
|
|
298
|
-
# Get JSON output for programmatic use
|
|
299
|
-
just-bash -c 'echo hello' --json
|
|
300
|
-
# Output: {"stdout":"hello\n","stderr":"","exitCode":0}
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
The CLI uses OverlayFS - reads come from the real filesystem, but all writes stay in memory and are discarded after execution. The project root is mounted at `/home/user/project`.
|
|
304
|
-
|
|
305
|
-
Options:
|
|
306
|
-
|
|
307
|
-
- `-c <script>` - Execute script from argument
|
|
308
|
-
- `--root <path>` - Root directory (default: current directory)
|
|
309
|
-
- `--cwd <path>` - Working directory in sandbox
|
|
310
|
-
- `-e, --errexit` - Exit on first error
|
|
311
|
-
- `--json` - Output as JSON
|
|
312
|
-
|
|
313
|
-
### Interactive Shell
|
|
314
|
-
|
|
315
|
-
```bash
|
|
316
|
-
pnpm shell
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
The interactive shell has full internet access enabled by default, allowing you to use `curl` to fetch data from any URL. Use `--no-network` to disable this:
|
|
320
|
-
|
|
321
|
-
```bash
|
|
322
|
-
pnpm shell --no-network
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
## Supported Commands
|
|
326
|
-
|
|
327
|
-
### File Operations
|
|
328
|
-
|
|
329
|
-
`cat`, `cp`, `file`, `ln`, `ls`, `mkdir`, `mv`, `readlink`, `rm`, `rmdir`, `split`, `stat`, `touch`, `tree`
|
|
330
|
-
|
|
331
|
-
### Text Processing
|
|
332
|
-
|
|
333
|
-
`awk`, `base64`, `column`, `comm`, `cut`, `diff`, `expand`, `fold`, `grep` (+ `egrep`, `fgrep`), `head`, `join`, `md5sum`, `nl`, `od`, `paste`, `printf`, `rev`, `rg`, `sed`, `sha1sum`, `sha256sum`, `sort`, `strings`, `tac`, `tail`, `tr`, `unexpand`, `uniq`, `wc`, `xargs`
|
|
334
|
-
|
|
335
|
-
### Data Processing
|
|
336
|
-
|
|
337
|
-
`jq` (JSON), `js-exec` (JavaScript/TypeScript via QuickJS; requires opt-in), `python3`/`python` (Python via WASM/CPython; requires opt-in), `sqlite3` (SQLite), `xan` (CSV), `yq` (YAML/XML/TOML/CSV)
|
|
338
|
-
|
|
339
|
-
### Compression & Archives
|
|
340
|
-
|
|
341
|
-
`gzip` (+ `gunzip`, `zcat`), `tar`
|
|
342
|
-
|
|
343
|
-
### Navigation & Environment
|
|
344
|
-
|
|
345
|
-
`basename`, `cd`, `dirname`, `du`, `echo`, `env`, `export`, `find`, `hostname`, `printenv`, `pwd`, `tee`
|
|
346
|
-
|
|
347
|
-
### Shell Utilities
|
|
348
|
-
|
|
349
|
-
`alias`, `bash`, `chmod`, `clear`, `date`, `expr`, `false`, `help`, `history`, `seq`, `sh`, `sleep`, `time`, `timeout`, `true`, `unalias`, `which`, `whoami`
|
|
350
|
-
|
|
351
|
-
### Network Commands
|
|
352
|
-
|
|
353
|
-
`curl`, `html-to-markdown`
|
|
354
|
-
|
|
355
|
-
All commands support `--help` for usage information.
|
|
356
|
-
|
|
357
|
-
## Shell Features
|
|
358
|
-
|
|
359
|
-
- **Pipes**: `cmd1 | cmd2`
|
|
360
|
-
- **Redirections**: `>`, `>>`, `2>`, `2>&1`, `<`
|
|
361
|
-
- **Command chaining**: `&&`, `||`, `;`
|
|
362
|
-
- **Variables**: `$VAR`, `${VAR}`, `${VAR:-default}`
|
|
363
|
-
- **Positional parameters**: `$1`, `$2`, `$@`, `$#`
|
|
364
|
-
- **Glob patterns**: `*`, `?`, `[...]`
|
|
365
|
-
- **If statements**: `if COND; then CMD; elif COND; then CMD; else CMD; fi`
|
|
366
|
-
- **Functions**: `function name { ... }` or `name() { ... }`
|
|
367
|
-
- **Local variables**: `local VAR=value`
|
|
368
|
-
- **Loops**: `for`, `while`, `until`
|
|
369
|
-
- **Symbolic links**: `ln -s target link`
|
|
370
|
-
- **Hard links**: `ln target link`
|
|
371
|
-
|
|
372
|
-
## Default Layout
|
|
373
|
-
|
|
374
|
-
When created without options, Bash provides a Unix-like directory structure:
|
|
375
|
-
|
|
376
|
-
- `/home/user` - Default working directory (and `$HOME`)
|
|
377
|
-
- `/bin` - Contains stubs for all built-in commands
|
|
378
|
-
- `/usr/bin` - Additional binary directory
|
|
379
|
-
- `/tmp` - Temporary files directory
|
|
380
|
-
|
|
381
|
-
Commands can be invoked by path (e.g., `/bin/ls`) or by name.
|
|
382
|
-
|
|
383
|
-
## Network Access
|
|
384
|
-
|
|
385
|
-
Network access (and the `curl` command) is disabled by default for security. To enable it, configure the `network` option:
|
|
239
|
+
Network access is disabled by default. Enable it with the `network` option:
|
|
386
240
|
|
|
387
241
|
```typescript
|
|
388
242
|
// Allow specific URLs with GET/HEAD only (safest)
|
|
@@ -403,6 +257,19 @@ const env = new Bash({
|
|
|
403
257
|
},
|
|
404
258
|
});
|
|
405
259
|
|
|
260
|
+
// Inject credentials via header transforms (secrets never enter the sandbox)
|
|
261
|
+
const env = new Bash({
|
|
262
|
+
network: {
|
|
263
|
+
allowedUrlPrefixes: [
|
|
264
|
+
"https://public-api.com", // plain string — no transforms
|
|
265
|
+
{
|
|
266
|
+
url: "https://ai-gateway.vercel.sh",
|
|
267
|
+
transform: [{ headers: { Authorization: "Bearer secret" } }],
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
|
|
406
273
|
// Allow all URLs and methods (use with caution)
|
|
407
274
|
const env = new Bash({
|
|
408
275
|
network: { dangerouslyAllowFullInternetAccess: true },
|
|
@@ -411,27 +278,33 @@ const env = new Bash({
|
|
|
411
278
|
|
|
412
279
|
**Note:** The `curl` command only exists when network is configured. Without network configuration, `curl` returns "command not found".
|
|
413
280
|
|
|
414
|
-
|
|
281
|
+
#### Allow-List Security
|
|
415
282
|
|
|
416
|
-
|
|
283
|
+
The allow-list enforces:
|
|
417
284
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
285
|
+
- **Origin matching**: URLs must match the exact origin (scheme + host + port)
|
|
286
|
+
- **Path prefix**: Only paths starting with the specified prefix are allowed
|
|
287
|
+
- **HTTP method restrictions**: Only GET and HEAD by default (configure `allowedMethods` for more)
|
|
288
|
+
- **Redirect protection**: Redirects to non-allowed URLs are blocked
|
|
289
|
+
- **Header transforms**: Firewall headers are injected at the fetch boundary and override any user-supplied headers with the same name, preventing credential substitution from inside the sandbox. Headers are re-evaluated on each redirect so credentials are never leaked to non-transform hosts
|
|
422
290
|
|
|
423
|
-
|
|
424
|
-
await env.exec('python3 -c "print(1 + 2)"');
|
|
291
|
+
#### Using curl
|
|
425
292
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
293
|
+
```bash
|
|
294
|
+
# Fetch and process data
|
|
295
|
+
curl -s https://api.example.com/data | grep pattern
|
|
429
296
|
|
|
430
|
-
|
|
297
|
+
# Download and convert HTML to Markdown
|
|
298
|
+
curl -s https://example.com | html-to-markdown
|
|
431
299
|
|
|
432
|
-
|
|
300
|
+
# POST JSON data
|
|
301
|
+
curl -X POST -H "Content-Type: application/json" \
|
|
302
|
+
-d '{"key":"value"}' https://api.example.com/endpoint
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### JavaScript Support
|
|
433
306
|
|
|
434
|
-
JavaScript and TypeScript execution via QuickJS is opt-in
|
|
307
|
+
JavaScript and TypeScript execution via QuickJS is opt-in due to additional security surface. Enable with `javascript: true`:
|
|
435
308
|
|
|
436
309
|
```typescript
|
|
437
310
|
const env = new Bash({
|
|
@@ -448,9 +321,9 @@ await env.exec('js-exec script.js');
|
|
|
448
321
|
await env.exec('js-exec -m -c "import fs from \'fs\'; console.log(fs.readFileSync(\'/data/file.txt\', \'utf8\'))"');
|
|
449
322
|
```
|
|
450
323
|
|
|
451
|
-
|
|
324
|
+
#### Bootstrap Code
|
|
452
325
|
|
|
453
|
-
|
|
326
|
+
Run setup code before every `js-exec` invocation with the `bootstrap` option:
|
|
454
327
|
|
|
455
328
|
```typescript
|
|
456
329
|
const env = new Bash({
|
|
@@ -466,9 +339,9 @@ await env.exec('js-exec -c "console.log(API_BASE)"');
|
|
|
466
339
|
// Output: https://api.example.com
|
|
467
340
|
```
|
|
468
341
|
|
|
469
|
-
|
|
342
|
+
#### Node.js Compatibility
|
|
470
343
|
|
|
471
|
-
`js-exec`
|
|
344
|
+
`js-exec` supports `require()` and `import` with these Node.js modules:
|
|
472
345
|
|
|
473
346
|
- **fs**: `readFileSync`, `writeFileSync`, `readdirSync`, `statSync`, `existsSync`, `mkdirSync`, `rmSync`, `fs.promises.*`
|
|
474
347
|
- **path**: `join`, `resolve`, `dirname`, `basename`, `extname`, `relative`, `normalize`
|
|
@@ -479,11 +352,29 @@ await env.exec('js-exec -c "console.log(API_BASE)"');
|
|
|
479
352
|
|
|
480
353
|
`fs.readFileSync()` returns a `Buffer` by default (matching Node.js). Pass an encoding like `'utf8'` to get a string.
|
|
481
354
|
|
|
482
|
-
**Note:** The `js-exec` command only exists when `javascript` is configured. It is not available in browser environments. Execution runs in a QuickJS WASM sandbox with a 64 MB memory limit and configurable timeout (default: 10s, 60s with network).
|
|
355
|
+
**Note:** The `js-exec` command only exists when `javascript` is configured. It is not available in browser environments. Execution runs in a QuickJS WASM sandbox with a 64 MB memory limit and configurable timeout (default: 10s, 60s with network).
|
|
356
|
+
|
|
357
|
+
### Python Support
|
|
358
|
+
|
|
359
|
+
Python (CPython compiled to WASM) is opt-in due to additional security surface. Enable with `python: true`:
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
const env = new Bash({
|
|
363
|
+
python: true,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Execute Python code
|
|
367
|
+
await env.exec('python3 -c "print(1 + 2)"');
|
|
368
|
+
|
|
369
|
+
// Run Python scripts
|
|
370
|
+
await env.exec('python3 script.py');
|
|
371
|
+
```
|
|
483
372
|
|
|
484
|
-
|
|
373
|
+
**Note:** The `python3` and `python` commands only exist when `python: true` is configured. Python is not available in browser environments.
|
|
374
|
+
|
|
375
|
+
### SQLite Support
|
|
485
376
|
|
|
486
|
-
|
|
377
|
+
`sqlite3` uses sql.js (SQLite compiled to WASM), sandboxed from the real filesystem:
|
|
487
378
|
|
|
488
379
|
```typescript
|
|
489
380
|
const env = new Bash();
|
|
@@ -497,27 +388,134 @@ await env.exec('sqlite3 data.db "SELECT * FROM users"');
|
|
|
497
388
|
|
|
498
389
|
**Note:** SQLite is not available in browser environments. Queries run in a worker thread with a configurable timeout (default: 5 seconds) to prevent runaway queries from blocking execution.
|
|
499
390
|
|
|
500
|
-
|
|
391
|
+
## AST Transform Plugins
|
|
501
392
|
|
|
502
|
-
|
|
393
|
+
Parse bash scripts into an AST, transform them, and serialize back to bash. Good for instrumenting scripts (e.g., capturing per-command stdout/stderr) or extracting metadata before execution.
|
|
503
394
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
- **HTTP method restrictions**: Only GET and HEAD by default (configure `allowedMethods` for more)
|
|
507
|
-
- **Redirect protection**: Redirects to non-allowed URLs are blocked
|
|
395
|
+
```typescript
|
|
396
|
+
import { Bash, BashTransformPipeline, TeePlugin, CommandCollectorPlugin } from "just-bash";
|
|
508
397
|
|
|
509
|
-
|
|
398
|
+
// Standalone pipeline — output can be run by any shell
|
|
399
|
+
const pipeline = new BashTransformPipeline()
|
|
400
|
+
.use(new TeePlugin({ outputDir: "/tmp/logs" }))
|
|
401
|
+
.use(new CommandCollectorPlugin());
|
|
402
|
+
const result = pipeline.transform("echo hello | grep hello");
|
|
403
|
+
result.script; // transformed bash string
|
|
404
|
+
result.metadata.commands; // ["echo", "grep", "tee"]
|
|
405
|
+
|
|
406
|
+
// Integrated API — exec() auto-applies transforms and returns metadata
|
|
407
|
+
const bash = new Bash();
|
|
408
|
+
bash.registerTransformPlugin(new CommandCollectorPlugin());
|
|
409
|
+
const execResult = await bash.exec("echo hello | grep hello");
|
|
410
|
+
execResult.metadata?.commands; // ["echo", "grep"]
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
See [src/transform/README.md](src/transform/README.md) for the full API, built-in plugins, and how to write custom plugins.
|
|
414
|
+
|
|
415
|
+
## Integrations
|
|
416
|
+
|
|
417
|
+
### AI SDK Tool
|
|
418
|
+
|
|
419
|
+
[`bash-tool`](https://github.com/vercel-labs/bash-tool) wraps just-bash as an [AI SDK](https://ai-sdk.dev/) tool:
|
|
510
420
|
|
|
511
421
|
```bash
|
|
512
|
-
|
|
513
|
-
|
|
422
|
+
npm install bash-tool
|
|
423
|
+
```
|
|
514
424
|
|
|
515
|
-
|
|
516
|
-
|
|
425
|
+
```typescript
|
|
426
|
+
import { createBashTool } from "bash-tool";
|
|
427
|
+
import { generateText } from "ai";
|
|
517
428
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
429
|
+
const bashTool = createBashTool({
|
|
430
|
+
files: { "/data/users.json": '[{"name": "Alice"}, {"name": "Bob"}]' },
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
const result = await generateText({
|
|
434
|
+
model: "anthropic/claude-sonnet-4",
|
|
435
|
+
tools: { bash: bashTool },
|
|
436
|
+
prompt: "Count the users in /data/users.json",
|
|
437
|
+
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
See [bash-tool](https://github.com/vercel-labs/bash-tool) for more.
|
|
441
|
+
|
|
442
|
+
### Vercel Sandbox Compatible API
|
|
443
|
+
|
|
444
|
+
`Sandbox` is a drop-in replacement for [`@vercel/sandbox`](https://vercel.com/docs/vercel-sandbox) — same API, but runs entirely in-process with the virtual filesystem. Start with just-bash for development and testing, swap in a real sandbox when you need a full VM.
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
import { Sandbox } from "just-bash";
|
|
448
|
+
|
|
449
|
+
// Create a sandbox instance
|
|
450
|
+
const sandbox = await Sandbox.create({ cwd: "/app" });
|
|
451
|
+
|
|
452
|
+
// Write files to the virtual filesystem
|
|
453
|
+
await sandbox.writeFiles({
|
|
454
|
+
"/app/script.sh": 'echo "Hello World"',
|
|
455
|
+
"/app/data.json": '{"key": "value"}',
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
// Run commands and get results
|
|
459
|
+
const cmd = await sandbox.runCommand("bash /app/script.sh");
|
|
460
|
+
const output = await cmd.stdout(); // "Hello World\n"
|
|
461
|
+
const exitCode = (await cmd.wait()).exitCode; // 0
|
|
462
|
+
|
|
463
|
+
// Read files back
|
|
464
|
+
const content = await sandbox.readFile("/app/data.json");
|
|
465
|
+
|
|
466
|
+
// Create directories
|
|
467
|
+
await sandbox.mkDir("/app/logs", { recursive: true });
|
|
468
|
+
|
|
469
|
+
// Clean up (no-op for Bash, but API-compatible)
|
|
470
|
+
await sandbox.stop();
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## CLI
|
|
474
|
+
|
|
475
|
+
### CLI Binary
|
|
476
|
+
|
|
477
|
+
Install globally (`npm install -g just-bash`) for a sandboxed CLI:
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
# Execute inline script
|
|
481
|
+
just-bash -c 'ls -la && cat package.json | head -5'
|
|
482
|
+
|
|
483
|
+
# Execute with specific project root
|
|
484
|
+
just-bash -c 'grep -r "TODO" src/' --root /path/to/project
|
|
485
|
+
|
|
486
|
+
# Pipe script from stdin
|
|
487
|
+
echo 'find . -name "*.ts" | wc -l' | just-bash
|
|
488
|
+
|
|
489
|
+
# Execute a script file
|
|
490
|
+
just-bash ./scripts/deploy.sh
|
|
491
|
+
|
|
492
|
+
# Get JSON output for programmatic use
|
|
493
|
+
just-bash -c 'echo hello' --json
|
|
494
|
+
# Output: {"stdout":"hello\n","stderr":"","exitCode":0}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
The CLI uses OverlayFS — reads come from the real filesystem, but all writes stay in memory and are discarded after execution.
|
|
498
|
+
|
|
499
|
+
**Important**: The project root is mounted at `/home/user/project`. Use this path (or relative paths from the default cwd) to access your files inside the sandbox.
|
|
500
|
+
|
|
501
|
+
Options:
|
|
502
|
+
|
|
503
|
+
- `-c <script>` - Execute script from argument
|
|
504
|
+
- `--root <path>` - Root directory (default: current directory)
|
|
505
|
+
- `--cwd <path>` - Working directory in sandbox
|
|
506
|
+
- `-e, --errexit` - Exit on first error
|
|
507
|
+
- `--json` - Output as JSON
|
|
508
|
+
|
|
509
|
+
### Interactive Shell
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
pnpm shell
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
The interactive shell has full internet access by default. Disable with `--no-network`:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
pnpm shell --no-network
|
|
521
519
|
```
|
|
522
520
|
|
|
523
521
|
## Execution Protection
|
|
@@ -536,45 +534,35 @@ const env = new Bash({
|
|
|
536
534
|
});
|
|
537
535
|
```
|
|
538
536
|
|
|
539
|
-
All limits have
|
|
537
|
+
All limits have defaults. Error messages tell you which limit was hit. Increase as needed for your workload.
|
|
540
538
|
|
|
541
|
-
##
|
|
539
|
+
## Security Model
|
|
542
540
|
|
|
543
|
-
|
|
541
|
+
- The shell only has access to the provided filesystem.
|
|
542
|
+
- All execution happens without VM isolation. This does introduce additional risk. The code base was designed to be robust against prototype-pollution attacks and other break outs to the host JS engine and filesystem.
|
|
543
|
+
- There is no network access by default. When enabled, requests are checked against URL prefix allow-lists and HTTP-method allow-lists.
|
|
544
|
+
- Python and JavaScript execution are off by default as they represent additional security surface.
|
|
545
|
+
- Execution is protected against infinite loops and deep recursion with configurable limits.
|
|
546
|
+
- Use [Vercel Sandbox](https://vercel.com/docs/vercel-sandbox) if you need a full VM with arbitrary binary execution.
|
|
544
547
|
|
|
545
|
-
|
|
546
|
-
import { Bash, BashTransformPipeline, TeePlugin, CommandCollectorPlugin } from "just-bash";
|
|
548
|
+
## Browser Support
|
|
547
549
|
|
|
548
|
-
|
|
549
|
-
const pipeline = new BashTransformPipeline()
|
|
550
|
-
.use(new TeePlugin({ outputDir: "/tmp/logs" }))
|
|
551
|
-
.use(new CommandCollectorPlugin());
|
|
552
|
-
const result = pipeline.transform("echo hello | grep hello");
|
|
553
|
-
result.script; // transformed bash string
|
|
554
|
-
result.metadata.commands; // ["echo", "grep", "tee"]
|
|
550
|
+
The core shell (parsing, execution, filesystem, and all built-in commands) works in browser environments. The following features require Node.js and are unavailable in browsers: `python3`/`python`, `sqlite3`, `js-exec`, and `OverlayFs`/`ReadWriteFs` (which access the real filesystem).
|
|
555
551
|
|
|
556
|
-
|
|
557
|
-
const bash = new Bash();
|
|
558
|
-
bash.registerTransformPlugin(new CommandCollectorPlugin());
|
|
559
|
-
const execResult = await bash.exec("echo hello | grep hello");
|
|
560
|
-
execResult.metadata?.commands; // ["echo", "grep"]
|
|
561
|
-
```
|
|
552
|
+
## Default Layout
|
|
562
553
|
|
|
563
|
-
|
|
554
|
+
When created without options, Bash provides a Unix-like directory structure:
|
|
564
555
|
|
|
565
|
-
|
|
556
|
+
- `/home/user` - Default working directory (and `$HOME`)
|
|
557
|
+
- `/bin` - Contains stubs for all built-in commands
|
|
558
|
+
- `/usr/bin` - Additional binary directory
|
|
559
|
+
- `/tmp` - Temporary files directory
|
|
566
560
|
|
|
567
|
-
|
|
568
|
-
pnpm test # Run tests in watch mode
|
|
569
|
-
pnpm test:run # Run tests once
|
|
570
|
-
pnpm typecheck # Type check without emitting
|
|
571
|
-
pnpm build # Build TypeScript
|
|
572
|
-
pnpm shell # Run interactive shell
|
|
573
|
-
```
|
|
561
|
+
Commands can be invoked by path (e.g., `/bin/ls`) or by name.
|
|
574
562
|
|
|
575
563
|
## AI Agent Instructions
|
|
576
564
|
|
|
577
|
-
For AI agents,
|
|
565
|
+
For AI agents, [`bash-tool`](https://github.com/vercel-labs/bash-tool) provides additional guidance in its `AGENTS.md`:
|
|
578
566
|
|
|
579
567
|
```bash
|
|
580
568
|
cat node_modules/bash-tool/dist/AGENTS.md
|