just-bash 2.12.8 → 2.13.1
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 +332 -260
- package/dist/AGENTS.md +1 -1
- package/dist/Bash.d.ts +17 -0
- package/dist/bin/chunks/{awk2-J2PNSA7C.js → awk2-VTJMI54B.js} +1 -1
- package/dist/bin/chunks/{chunk-O5B6WWQQ.js → chunk-A3HQTYHR.js} +1 -1
- package/dist/bin/chunks/chunk-AAW7UMPO.js +9 -0
- package/dist/bin/chunks/{chunk-2V53PP6G.js → chunk-B3RU2PUI.js} +27 -27
- package/dist/bin/chunks/chunk-CQG2HEAL.js +5 -0
- package/dist/bin/chunks/chunk-DOXYBGNA.js +12 -0
- package/dist/bin/chunks/chunk-FBJJY4ZV.js +14 -0
- package/dist/bin/{shell/chunks/chunk-YAEF6X2N.js → chunks/chunk-GR23MPTT.js} +1 -1
- package/dist/bin/{shell/chunks/chunk-35JD7YEM.js → chunks/chunk-HJEHIH4P.js} +13 -13
- package/dist/bin/chunks/{chunk-UG4GMDQL.js → chunk-LGF54XJQ.js} +1 -1
- package/dist/bin/chunks/chunk-LIYVQA3X.js +2 -0
- package/dist/bin/chunks/{chunk-2BC3N3L2.js → chunk-ORUYSLP4.js} +4 -4
- package/dist/bin/chunks/{chunk-REGSV3X5.js → chunk-SDLWFYVT.js} +1 -1
- package/dist/bin/chunks/{chunk-STOAUD75.js → chunk-THNL3XFF.js} +8 -8
- package/dist/bin/chunks/chunk-TKTKRRAL.js +11 -0
- package/dist/bin/chunks/{chunk-ZJGIBTWD.js → chunk-V7ZOPVQS.js} +1 -1
- package/dist/bin/chunks/{chunk-ZYQQ6B7B.js → chunk-ZO5PSLKR.js} +2 -2
- package/dist/bin/chunks/curl-SRTMGOVV.js +26 -0
- package/dist/bin/chunks/env-NTPN5QYM.js +2 -0
- package/dist/bin/{shell/chunks/expansion-JBCP2CHQ.js → chunks/expansion-2RO5M3QC.js} +1 -1
- package/dist/bin/{shell/chunks/find-MTLF23HX.js → chunks/find-GAYRV4IF.js} +1 -1
- package/dist/bin/{shell/chunks/flag-coverage-CFWN3JJN.js → chunks/flag-coverage-A4G6STMS.js} +1 -1
- package/dist/bin/chunks/{help-4H52JYYC.js → help-DVG4AAGE.js} +1 -1
- package/dist/bin/{shell/chunks/jq-JFXEKNLN.js → chunks/jq-V7FYGIKO.js} +1 -1
- package/dist/bin/chunks/js-exec-JORCTVUT.js +97 -0
- package/dist/bin/chunks/js-exec-worker.js +4369 -0
- package/dist/bin/chunks/python3-PF7AHNQM.js +12 -0
- package/dist/bin/chunks/rg-C6KMBFNG.js +2 -0
- package/dist/bin/chunks/time-DDS6JJ23.js +2 -0
- package/dist/bin/chunks/{timeout-JJWIFL7W.js → timeout-Z24MNWOP.js} +1 -1
- package/dist/bin/chunks/worker.js +88 -33
- package/dist/bin/chunks/{xan-M6MLWZCU.js → xan-MOZFJGMY.js} +1 -1
- package/dist/bin/chunks/xargs-SCYIFXOW.js +2 -0
- package/dist/bin/chunks/{yq-YWUQUXJJ.js → yq-JJLSDDST.js} +1 -1
- package/dist/bin/just-bash.js +212 -211
- package/dist/bin/shell/chunks/{awk2-J2PNSA7C.js → awk2-VTJMI54B.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-O5B6WWQQ.js → chunk-A3HQTYHR.js} +1 -1
- package/dist/bin/shell/chunks/chunk-AAW7UMPO.js +9 -0
- package/dist/bin/shell/chunks/{chunk-2V53PP6G.js → chunk-B3RU2PUI.js} +27 -27
- package/dist/bin/shell/chunks/chunk-CQG2HEAL.js +5 -0
- package/dist/bin/shell/chunks/chunk-DOXYBGNA.js +12 -0
- package/dist/bin/shell/chunks/chunk-FBJJY4ZV.js +14 -0
- package/dist/bin/{chunks/chunk-YAEF6X2N.js → shell/chunks/chunk-GR23MPTT.js} +1 -1
- package/dist/bin/{chunks/chunk-35JD7YEM.js → shell/chunks/chunk-HJEHIH4P.js} +13 -13
- package/dist/bin/shell/chunks/{chunk-UG4GMDQL.js → chunk-LGF54XJQ.js} +1 -1
- package/dist/bin/shell/chunks/chunk-LIYVQA3X.js +2 -0
- package/dist/bin/shell/chunks/{chunk-2BC3N3L2.js → chunk-ORUYSLP4.js} +4 -4
- package/dist/bin/shell/chunks/{chunk-REGSV3X5.js → chunk-SDLWFYVT.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-STOAUD75.js → chunk-THNL3XFF.js} +8 -8
- package/dist/bin/shell/chunks/chunk-TKTKRRAL.js +11 -0
- package/dist/bin/shell/chunks/{chunk-ZJGIBTWD.js → chunk-V7ZOPVQS.js} +1 -1
- package/dist/bin/shell/chunks/{chunk-ZYQQ6B7B.js → chunk-ZO5PSLKR.js} +2 -2
- package/dist/bin/shell/chunks/curl-SRTMGOVV.js +26 -0
- package/dist/bin/shell/chunks/env-NTPN5QYM.js +2 -0
- package/dist/bin/{chunks/expansion-JBCP2CHQ.js → shell/chunks/expansion-2RO5M3QC.js} +1 -1
- package/dist/bin/{chunks/find-MTLF23HX.js → shell/chunks/find-GAYRV4IF.js} +1 -1
- package/dist/bin/{chunks/flag-coverage-CFWN3JJN.js → shell/chunks/flag-coverage-A4G6STMS.js} +1 -1
- package/dist/bin/shell/chunks/{help-4H52JYYC.js → help-DVG4AAGE.js} +1 -1
- package/dist/bin/{chunks/jq-JFXEKNLN.js → shell/chunks/jq-V7FYGIKO.js} +1 -1
- package/dist/bin/shell/chunks/js-exec-B6QNYHUL.js +97 -0
- package/dist/bin/shell/chunks/python3-J7DP4JBQ.js +12 -0
- package/dist/bin/shell/chunks/rg-C6KMBFNG.js +2 -0
- package/dist/bin/shell/chunks/time-DDS6JJ23.js +2 -0
- package/dist/bin/shell/chunks/{timeout-JJWIFL7W.js → timeout-Z24MNWOP.js} +1 -1
- package/dist/bin/shell/chunks/{xan-M6MLWZCU.js → xan-MOZFJGMY.js} +1 -1
- package/dist/bin/shell/chunks/xargs-SCYIFXOW.js +2 -0
- package/dist/bin/shell/chunks/{yq-YWUQUXJJ.js → yq-JJLSDDST.js} +1 -1
- package/dist/bin/shell/shell.js +212 -212
- package/dist/bundle/browser.js +600 -600
- package/dist/bundle/chunks/{awk2-FUVZGMX2.js → awk2-POPGKRAI.js} +1 -1
- package/dist/bundle/chunks/{chunk-DZZS6SJP.js → chunk-7TSDKFEO.js} +1 -1
- package/dist/bundle/chunks/{chunk-D4QDMGEB.js → chunk-BBXLRYSX.js} +2 -2
- package/dist/bundle/chunks/chunk-CWQS3NFK.js +1 -0
- package/dist/bundle/chunks/chunk-F5CMUULS.js +13 -0
- package/dist/bundle/chunks/{chunk-TRD56HID.js → chunk-FEIOJCZD.js} +1 -1
- package/dist/bundle/chunks/chunk-H2WXJGD7.js +10 -0
- package/dist/bundle/chunks/{chunk-D2FZX7A2.js → chunk-LPQPILI2.js} +8 -8
- package/dist/bundle/chunks/{chunk-2GOYXRRP.js → chunk-MLXIYONF.js} +4 -4
- package/dist/bundle/chunks/chunk-NAERJDUW.js +8 -0
- package/dist/bundle/chunks/{chunk-OKEHYWBE.js → chunk-NYQYO467.js} +13 -13
- package/dist/bundle/chunks/{chunk-JKLUDNMU.js → chunk-O2DBFL6Z.js} +1 -1
- package/dist/bundle/chunks/{chunk-JDMQDJYE.js → chunk-OARHFVLG.js} +1 -1
- package/dist/bundle/chunks/{chunk-AKVMAONP.js → chunk-RUF7WQ7U.js} +1 -1
- package/dist/bundle/chunks/chunk-TOMNU26N.js +4 -0
- package/dist/bundle/chunks/{chunk-ZLJ5TCLC.js → chunk-UNYNJIFU.js} +27 -27
- package/dist/bundle/chunks/chunk-YTNYSM6T.js +11 -0
- package/dist/bundle/chunks/curl-COE4TZE6.js +25 -0
- package/dist/bundle/chunks/env-5EPCWSXR.js +1 -0
- package/dist/bundle/chunks/{expansion-XG7G47TX.js → expansion-ENLSRCXJ.js} +1 -1
- package/dist/bundle/chunks/{find-DOIVMX6X.js → find-TPUOAIUQ.js} +1 -1
- package/dist/bundle/chunks/{flag-coverage-VML3BMJT.js → flag-coverage-G2R7PMYU.js} +1 -1
- package/dist/bundle/chunks/{help-IA5CMGR4.js → help-VVWX7SA5.js} +1 -1
- package/dist/bundle/chunks/{jq-SSCW4AAA.js → jq-DIRZBOTX.js} +1 -1
- package/dist/bundle/chunks/js-exec-YJSMH5AG.js +96 -0
- package/dist/bundle/chunks/js-exec-worker.js +4369 -0
- package/dist/bundle/chunks/python3-6HF56IYI.js +11 -0
- package/dist/bundle/chunks/rg-FOQSCCX3.js +1 -0
- package/dist/bundle/chunks/{time-XL42Z4U5.js → time-YG5BMRIQ.js} +1 -1
- package/dist/bundle/chunks/{timeout-QCU4INQT.js → timeout-VRKMCG72.js} +1 -1
- package/dist/bundle/chunks/worker.js +88 -33
- package/dist/bundle/chunks/{xan-K7XYDHFV.js → xan-BXDXYEIB.js} +1 -1
- package/dist/bundle/chunks/xargs-I6EZUCYF.js +1 -0
- package/dist/bundle/chunks/{yq-WTK3HUOR.js → yq-XMVSIL6Z.js} +1 -1
- package/dist/bundle/index.cjs +969 -870
- package/dist/bundle/index.js +151 -151
- package/dist/commands/curl/types.d.ts +1 -1
- package/dist/commands/js-exec/fetch-polyfill.d.ts +6 -0
- package/dist/commands/js-exec/js-exec.d.ts +11 -0
- package/dist/commands/js-exec/module-shims.d.ts +29 -0
- package/dist/commands/js-exec/path-polyfill.d.ts +6 -0
- package/dist/commands/js-exec/worker.d.ts +30 -0
- package/dist/commands/python3/worker.d.ts +1 -0
- package/dist/commands/query-engine/safe-object.d.ts +11 -0
- package/dist/commands/registry.d.ts +13 -2
- package/dist/commands/{python3/fs-bridge-handler.d.ts → worker-bridge/bridge-handler.d.ts} +25 -8
- package/dist/commands/{python3 → worker-bridge}/protocol.d.ts +6 -3
- package/dist/commands/{python3/sync-fs-backend.d.ts → worker-bridge/sync-backend.d.ts} +25 -4
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/interpreter/interpreter.d.ts +3 -0
- package/dist/interpreter/types.d.ts +8 -0
- package/dist/limits.d.ts +3 -1
- package/dist/network/allow-list.d.ts +5 -3
- package/dist/network/fetch.d.ts +1 -1
- package/dist/network/index.d.ts +1 -1
- package/dist/network/types.d.ts +32 -1
- package/dist/types.d.ts +12 -0
- package/package.json +13 -12
- package/dist/bin/chunks/chunk-47HZU3SY.js +0 -5
- package/dist/bin/chunks/chunk-CZFRRDQC.js +0 -12
- package/dist/bin/chunks/chunk-N4EU64Y4.js +0 -9
- package/dist/bin/chunks/chunk-QZNF3Y3J.js +0 -2
- package/dist/bin/chunks/chunk-VIYJJTN2.js +0 -14
- package/dist/bin/chunks/curl-3GMIPMCI.js +0 -26
- package/dist/bin/chunks/env-HOVBNLUR.js +0 -2
- package/dist/bin/chunks/python3-KI2FQWSN.js +0 -17
- package/dist/bin/chunks/rg-34GE6REQ.js +0 -2
- package/dist/bin/chunks/time-GZSHCM77.js +0 -2
- package/dist/bin/chunks/xargs-GBL6PZ2K.js +0 -2
- package/dist/bin/shell/chunks/chunk-47HZU3SY.js +0 -5
- package/dist/bin/shell/chunks/chunk-CZFRRDQC.js +0 -12
- package/dist/bin/shell/chunks/chunk-N4EU64Y4.js +0 -9
- package/dist/bin/shell/chunks/chunk-QZNF3Y3J.js +0 -2
- package/dist/bin/shell/chunks/chunk-VIYJJTN2.js +0 -14
- package/dist/bin/shell/chunks/curl-3GMIPMCI.js +0 -26
- package/dist/bin/shell/chunks/env-HOVBNLUR.js +0 -2
- package/dist/bin/shell/chunks/python3-E5X6WBBU.js +0 -17
- package/dist/bin/shell/chunks/rg-34GE6REQ.js +0 -2
- package/dist/bin/shell/chunks/time-GZSHCM77.js +0 -2
- package/dist/bin/shell/chunks/xargs-GBL6PZ2K.js +0 -2
- package/dist/bundle/chunks/chunk-3RA5L262.js +0 -8
- package/dist/bundle/chunks/chunk-EX62JIX3.js +0 -13
- package/dist/bundle/chunks/chunk-RH6GWZAJ.js +0 -1
- package/dist/bundle/chunks/chunk-WECLUBEQ.js +0 -11
- package/dist/bundle/chunks/chunk-ZSJYNBAF.js +0 -4
- package/dist/bundle/chunks/curl-KM2ZAUR6.js +0 -25
- package/dist/bundle/chunks/env-XZY4LKEO.js +0 -1
- package/dist/bundle/chunks/python3-2OHR6PZU.js +0 -16
- package/dist/bundle/chunks/rg-RAICUFGG.js +0 -1
- package/dist/bundle/chunks/xargs-2BBAQDTC.js +0 -1
package/README.md
CHANGED
|
@@ -1,96 +1,30 @@
|
|
|
1
1
|
# just-bash
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A virtual bash environment with an in-memory filesystem, written in TypeScript and designed for AI agents.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Broad support for standard unix commands and bash syntax with optional curl, Python, JS/TS, and sqlite support.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Note**: This is beta software. Use at your own risk and please provide feedback. See [security model](#security-model).
|
|
8
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
|
-
- [Execution Protection](#execution-protection)
|
|
29
|
-
- [AST Transform Plugins](#ast-transform-plugins)
|
|
30
|
-
- [Development](#development)
|
|
31
|
-
|
|
32
|
-
## Security model
|
|
33
|
-
|
|
34
|
-
- The shell only has access to the provided file system.
|
|
35
|
-
- 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.
|
|
36
|
-
- 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).
|
|
37
|
-
- There is no network access by default.
|
|
38
|
-
- 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
|
|
39
|
-
|
|
40
|
-
## Installation
|
|
9
|
+
## Quick Start
|
|
41
10
|
|
|
42
11
|
```bash
|
|
43
12
|
npm install just-bash
|
|
44
13
|
```
|
|
45
14
|
|
|
46
|
-
## Usage
|
|
47
|
-
|
|
48
|
-
### Basic API
|
|
49
|
-
|
|
50
15
|
```typescript
|
|
51
16
|
import { Bash } from "just-bash";
|
|
52
17
|
|
|
53
|
-
const
|
|
54
|
-
await
|
|
55
|
-
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");
|
|
56
21
|
console.log(result.stdout); // "Hello\n"
|
|
57
22
|
console.log(result.exitCode); // 0
|
|
58
|
-
console.log(result.env); // Final environment after execution
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Each `exec()` is isolated—env vars, functions, and cwd don't persist across calls (filesystem does).
|
|
62
|
-
|
|
63
|
-
### Configuration
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
const env = new Bash({
|
|
67
|
-
files: { "/data/file.txt": "content" }, // Initial files
|
|
68
|
-
env: { MY_VAR: "value" }, // Initial environment
|
|
69
|
-
cwd: "/app", // Starting directory (default: /home/user)
|
|
70
|
-
executionLimits: { maxCallDepth: 50 }, // See "Execution Protection"
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Per-exec overrides
|
|
74
|
-
await env.exec("echo $TEMP", { env: { TEMP: "value" }, cwd: "/tmp" });
|
|
75
23
|
```
|
|
76
24
|
|
|
77
|
-
|
|
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.
|
|
78
26
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
const env = new Bash({
|
|
83
|
-
files: {
|
|
84
|
-
"/data/config.json": () => JSON.stringify({ key: "value" }),
|
|
85
|
-
"/data/remote.txt": async () => (await fetch("https://example.com")).text(),
|
|
86
|
-
"/data/static.txt": "always loaded",
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
This is useful for large or expensive-to-compute content that may not be needed.
|
|
92
|
-
|
|
93
|
-
### Custom Commands
|
|
27
|
+
## Custom Commands
|
|
94
28
|
|
|
95
29
|
Extend just-bash with your own TypeScript commands using `defineCommand`:
|
|
96
30
|
|
|
@@ -112,17 +46,125 @@ await bash.exec("hello Alice"); // "Hello, Alice!\n"
|
|
|
112
46
|
await bash.exec("echo 'test' | upper"); // "TEST\n"
|
|
113
47
|
```
|
|
114
48
|
|
|
115
|
-
Custom commands receive
|
|
49
|
+
Custom commands receive a `CommandContext` with `fs`, `cwd`, `env`, `stdin`, and `exec` (for subcommands), and work with pipes, redirections, and all shell features.
|
|
116
50
|
|
|
117
|
-
|
|
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
|
|
118
59
|
|
|
119
|
-
|
|
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))
|
|
85
|
+
|
|
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
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const env = new Bash({
|
|
109
|
+
files: { "/data/file.txt": "content" }, // Initial files
|
|
110
|
+
env: { MY_VAR: "value" }, // Initial environment
|
|
111
|
+
cwd: "/app", // Starting directory (default: /home/user)
|
|
112
|
+
executionLimits: { maxCallDepth: 50 }, // See "Execution Protection"
|
|
113
|
+
python: true, // Enable python3/python commands
|
|
114
|
+
javascript: true, // Enable js-exec command
|
|
115
|
+
// Or with bootstrap: javascript: { bootstrap: "globalThis.X = 1;" }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Per-exec overrides
|
|
119
|
+
await env.exec("echo $TEMP", { env: { TEMP: "value" }, cwd: "/tmp" });
|
|
120
|
+
|
|
121
|
+
// Pass stdin to the script
|
|
122
|
+
await env.exec("cat", { stdin: "hello from stdin\n" });
|
|
123
|
+
|
|
124
|
+
// Start with a clean environment
|
|
125
|
+
await env.exec("env", { replaceEnv: true, env: { ONLY: "this" } });
|
|
126
|
+
|
|
127
|
+
// Pass arguments without shell escaping (like spawnSync)
|
|
128
|
+
await env.exec("grep", { args: ["-r", "TODO", "src/"] });
|
|
129
|
+
|
|
130
|
+
// Cancel long-running scripts
|
|
131
|
+
const controller = new AbortController();
|
|
132
|
+
setTimeout(() => controller.abort(), 5000);
|
|
133
|
+
await env.exec("while true; do sleep 1; done", { signal: controller.signal });
|
|
134
|
+
|
|
135
|
+
// Preserve leading whitespace (e.g., for heredocs)
|
|
136
|
+
await env.exec("cat <<EOF\n indented\nEOF", { rawScript: true });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`exec()` options:
|
|
140
|
+
|
|
141
|
+
| Option | Type | Description |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `env` | `Record<string, string>` | Environment variables for this execution only |
|
|
144
|
+
| `cwd` | `string` | Working directory for this execution only |
|
|
145
|
+
| `stdin` | `string` | Standard input passed to the script |
|
|
146
|
+
| `args` | `string[]` | Additional argv passed directly to the first command (bypasses shell parsing; does not change `$1`, `$2`, ...) |
|
|
147
|
+
| `replaceEnv` | `boolean` | Start with empty env instead of merging (default: `false`) |
|
|
148
|
+
| `signal` | `AbortSignal` | Cooperative cancellation; stops at next statement boundary |
|
|
149
|
+
| `rawScript` | `boolean` | Skip leading-whitespace normalization (default: `false`) |
|
|
150
|
+
|
|
151
|
+
## Filesystem Options
|
|
152
|
+
|
|
153
|
+
Four filesystem implementations:
|
|
120
154
|
|
|
121
155
|
**InMemoryFs** (default) - Pure in-memory filesystem, no disk access:
|
|
122
156
|
|
|
123
157
|
```typescript
|
|
124
158
|
import { Bash } from "just-bash";
|
|
125
|
-
|
|
159
|
+
|
|
160
|
+
const env = new Bash({
|
|
161
|
+
files: {
|
|
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",
|
|
165
|
+
"/data/remote.txt": async () => (await fetch("https://example.com")).text(),
|
|
166
|
+
},
|
|
167
|
+
});
|
|
126
168
|
```
|
|
127
169
|
|
|
128
170
|
**OverlayFs** - Copy-on-write over a real directory. Reads come from disk, writes stay in memory:
|
|
@@ -138,7 +180,7 @@ await env.exec("cat package.json"); // reads from disk
|
|
|
138
180
|
await env.exec('echo "modified" > package.json'); // stays in memory
|
|
139
181
|
```
|
|
140
182
|
|
|
141
|
-
**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:
|
|
142
184
|
|
|
143
185
|
```typescript
|
|
144
186
|
import { Bash } from "just-bash";
|
|
@@ -188,9 +230,191 @@ const fs = new MountableFs({
|
|
|
188
230
|
});
|
|
189
231
|
```
|
|
190
232
|
|
|
233
|
+
## Optional Capabilities
|
|
234
|
+
|
|
235
|
+
### Network Access
|
|
236
|
+
|
|
237
|
+
Network access is disabled by default. Enable it with the `network` option:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Allow specific URLs with GET/HEAD only (safest)
|
|
241
|
+
const env = new Bash({
|
|
242
|
+
network: {
|
|
243
|
+
allowedUrlPrefixes: [
|
|
244
|
+
"https://api.github.com/repos/myorg/",
|
|
245
|
+
"https://api.example.com",
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Allow specific URLs with additional methods
|
|
251
|
+
const env = new Bash({
|
|
252
|
+
network: {
|
|
253
|
+
allowedUrlPrefixes: ["https://api.example.com"],
|
|
254
|
+
allowedMethods: ["GET", "HEAD", "POST"], // Default: ["GET", "HEAD"]
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Inject credentials via header transforms (secrets never enter the sandbox)
|
|
259
|
+
const env = new Bash({
|
|
260
|
+
network: {
|
|
261
|
+
allowedUrlPrefixes: [
|
|
262
|
+
"https://public-api.com", // plain string — no transforms
|
|
263
|
+
{
|
|
264
|
+
url: "https://ai-gateway.vercel.sh",
|
|
265
|
+
transform: [{ headers: { Authorization: "Bearer secret" } }],
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Allow all URLs and methods (use with caution)
|
|
272
|
+
const env = new Bash({
|
|
273
|
+
network: { dangerouslyAllowFullInternetAccess: true },
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Note:** The `curl` command only exists when network is configured. Without network configuration, `curl` returns "command not found".
|
|
278
|
+
|
|
279
|
+
#### Allow-List Security
|
|
280
|
+
|
|
281
|
+
The allow-list enforces:
|
|
282
|
+
|
|
283
|
+
- **Origin matching**: URLs must match the exact origin (scheme + host + port)
|
|
284
|
+
- **Path prefix**: Only paths starting with the specified prefix are allowed
|
|
285
|
+
- **HTTP method restrictions**: Only GET and HEAD by default (configure `allowedMethods` for more)
|
|
286
|
+
- **Redirect protection**: Redirects to non-allowed URLs are blocked
|
|
287
|
+
- **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
|
|
288
|
+
|
|
289
|
+
#### Using curl
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Fetch and process data
|
|
293
|
+
curl -s https://api.example.com/data | grep pattern
|
|
294
|
+
|
|
295
|
+
# Download and convert HTML to Markdown
|
|
296
|
+
curl -s https://example.com | html-to-markdown
|
|
297
|
+
|
|
298
|
+
# POST JSON data
|
|
299
|
+
curl -X POST -H "Content-Type: application/json" \
|
|
300
|
+
-d '{"key":"value"}' https://api.example.com/endpoint
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### JavaScript Support
|
|
304
|
+
|
|
305
|
+
JavaScript and TypeScript execution via QuickJS is opt-in due to additional security surface. Enable with `javascript: true`:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
const env = new Bash({
|
|
309
|
+
javascript: true,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Execute JavaScript code
|
|
313
|
+
await env.exec('js-exec -c "console.log(1 + 2)"');
|
|
314
|
+
|
|
315
|
+
// Run script files (.js, .mjs, .ts, .mts)
|
|
316
|
+
await env.exec('js-exec script.js');
|
|
317
|
+
|
|
318
|
+
// ES module mode with imports
|
|
319
|
+
await env.exec('js-exec -m -c "import fs from \'fs\'; console.log(fs.readFileSync(\'/data/file.txt\', \'utf8\'))"');
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Bootstrap Code
|
|
323
|
+
|
|
324
|
+
Run setup code before every `js-exec` invocation with the `bootstrap` option:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const env = new Bash({
|
|
328
|
+
javascript: {
|
|
329
|
+
bootstrap: `
|
|
330
|
+
globalThis.API_BASE = "https://api.example.com";
|
|
331
|
+
globalThis.formatDate = (d) => new Date(d).toISOString();
|
|
332
|
+
`,
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
await env.exec('js-exec -c "console.log(API_BASE)"');
|
|
337
|
+
// Output: https://api.example.com
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### Node.js Compatibility
|
|
341
|
+
|
|
342
|
+
`js-exec` supports `require()` and `import` with these Node.js modules:
|
|
343
|
+
|
|
344
|
+
- **fs**: `readFileSync`, `writeFileSync`, `readdirSync`, `statSync`, `existsSync`, `mkdirSync`, `rmSync`, `fs.promises.*`
|
|
345
|
+
- **path**: `join`, `resolve`, `dirname`, `basename`, `extname`, `relative`, `normalize`
|
|
346
|
+
- **child_process**: `execSync`, `spawnSync`
|
|
347
|
+
- **process**: `argv`, `cwd()`, `exit()`, `env`, `platform`, `version`
|
|
348
|
+
- **Other modules**: `os`, `url`, `assert`, `util`, `events`, `buffer`, `stream`, `string_decoder`, `querystring`
|
|
349
|
+
- **Globals**: `console`, `fetch`, `Buffer`, `URL`, `URLSearchParams`
|
|
350
|
+
|
|
351
|
+
`fs.readFileSync()` returns a `Buffer` by default (matching Node.js). Pass an encoding like `'utf8'` to get a string.
|
|
352
|
+
|
|
353
|
+
**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).
|
|
354
|
+
|
|
355
|
+
### Python Support
|
|
356
|
+
|
|
357
|
+
Python (CPython compiled to WASM) is opt-in due to additional security surface. Enable with `python: true`:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
const env = new Bash({
|
|
361
|
+
python: true,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Execute Python code
|
|
365
|
+
await env.exec('python3 -c "print(1 + 2)"');
|
|
366
|
+
|
|
367
|
+
// Run Python scripts
|
|
368
|
+
await env.exec('python3 script.py');
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Note:** The `python3` and `python` commands only exist when `python: true` is configured. Python is not available in browser environments.
|
|
372
|
+
|
|
373
|
+
### SQLite Support
|
|
374
|
+
|
|
375
|
+
`sqlite3` uses sql.js (SQLite compiled to WASM), sandboxed from the real filesystem:
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
const env = new Bash();
|
|
379
|
+
|
|
380
|
+
// Query in-memory database
|
|
381
|
+
await env.exec('sqlite3 :memory: "SELECT 1 + 1"');
|
|
382
|
+
|
|
383
|
+
// Query file-based database
|
|
384
|
+
await env.exec('sqlite3 data.db "SELECT * FROM users"');
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**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.
|
|
388
|
+
|
|
389
|
+
## AST Transform Plugins
|
|
390
|
+
|
|
391
|
+
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.
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
import { Bash, BashTransformPipeline, TeePlugin, CommandCollectorPlugin } from "just-bash";
|
|
395
|
+
|
|
396
|
+
// Standalone pipeline — output can be run by any shell
|
|
397
|
+
const pipeline = new BashTransformPipeline()
|
|
398
|
+
.use(new TeePlugin({ outputDir: "/tmp/logs" }))
|
|
399
|
+
.use(new CommandCollectorPlugin());
|
|
400
|
+
const result = pipeline.transform("echo hello | grep hello");
|
|
401
|
+
result.script; // transformed bash string
|
|
402
|
+
result.metadata.commands; // ["echo", "grep", "tee"]
|
|
403
|
+
|
|
404
|
+
// Integrated API — exec() auto-applies transforms and returns metadata
|
|
405
|
+
const bash = new Bash();
|
|
406
|
+
bash.registerTransformPlugin(new CommandCollectorPlugin());
|
|
407
|
+
const execResult = await bash.exec("echo hello | grep hello");
|
|
408
|
+
execResult.metadata?.commands; // ["echo", "grep"]
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
See [src/transform/README.md](src/transform/README.md) for the full API, built-in plugins, and how to write custom plugins.
|
|
412
|
+
|
|
413
|
+
## Integrations
|
|
414
|
+
|
|
191
415
|
### AI SDK Tool
|
|
192
416
|
|
|
193
|
-
|
|
417
|
+
[`bash-tool`](https://github.com/vercel-labs/bash-tool) wraps just-bash as an [AI SDK](https://ai-sdk.dev/) tool:
|
|
194
418
|
|
|
195
419
|
```bash
|
|
196
420
|
npm install bash-tool
|
|
@@ -211,11 +435,11 @@ const result = await generateText({
|
|
|
211
435
|
});
|
|
212
436
|
```
|
|
213
437
|
|
|
214
|
-
See
|
|
438
|
+
See [bash-tool](https://github.com/vercel-labs/bash-tool) for more.
|
|
215
439
|
|
|
216
440
|
### Vercel Sandbox Compatible API
|
|
217
441
|
|
|
218
|
-
|
|
442
|
+
`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.
|
|
219
443
|
|
|
220
444
|
```typescript
|
|
221
445
|
import { Sandbox } from "just-bash";
|
|
@@ -244,9 +468,11 @@ await sandbox.mkDir("/app/logs", { recursive: true });
|
|
|
244
468
|
await sandbox.stop();
|
|
245
469
|
```
|
|
246
470
|
|
|
471
|
+
## CLI
|
|
472
|
+
|
|
247
473
|
### CLI Binary
|
|
248
474
|
|
|
249
|
-
|
|
475
|
+
Install globally (`npm install -g just-bash`) for a sandboxed CLI:
|
|
250
476
|
|
|
251
477
|
```bash
|
|
252
478
|
# Execute inline script
|
|
@@ -266,7 +492,9 @@ just-bash -c 'echo hello' --json
|
|
|
266
492
|
# Output: {"stdout":"hello\n","stderr":"","exitCode":0}
|
|
267
493
|
```
|
|
268
494
|
|
|
269
|
-
The CLI uses OverlayFS
|
|
495
|
+
The CLI uses OverlayFS — reads come from the real filesystem, but all writes stay in memory and are discarded after execution.
|
|
496
|
+
|
|
497
|
+
**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.
|
|
270
498
|
|
|
271
499
|
Options:
|
|
272
500
|
|
|
@@ -282,158 +510,12 @@ Options:
|
|
|
282
510
|
pnpm shell
|
|
283
511
|
```
|
|
284
512
|
|
|
285
|
-
The interactive shell has full internet access
|
|
513
|
+
The interactive shell has full internet access by default. Disable with `--no-network`:
|
|
286
514
|
|
|
287
515
|
```bash
|
|
288
516
|
pnpm shell --no-network
|
|
289
517
|
```
|
|
290
518
|
|
|
291
|
-
## Supported Commands
|
|
292
|
-
|
|
293
|
-
### File Operations
|
|
294
|
-
|
|
295
|
-
`cat`, `cp`, `file`, `ln`, `ls`, `mkdir`, `mv`, `readlink`, `rm`, `rmdir`, `split`, `stat`, `touch`, `tree`
|
|
296
|
-
|
|
297
|
-
### Text Processing
|
|
298
|
-
|
|
299
|
-
`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`
|
|
300
|
-
|
|
301
|
-
### Data Processing
|
|
302
|
-
|
|
303
|
-
`jq` (JSON), `python3`/`python` (Python via Pyodide; required opt-in), `sqlite3` (SQLite), `xan` (CSV), `yq` (YAML/XML/TOML/CSV)
|
|
304
|
-
|
|
305
|
-
### Compression & Archives
|
|
306
|
-
|
|
307
|
-
`gzip` (+ `gunzip`, `zcat`), `tar`
|
|
308
|
-
|
|
309
|
-
### Navigation & Environment
|
|
310
|
-
|
|
311
|
-
`basename`, `cd`, `dirname`, `du`, `echo`, `env`, `export`, `find`, `hostname`, `printenv`, `pwd`, `tee`
|
|
312
|
-
|
|
313
|
-
### Shell Utilities
|
|
314
|
-
|
|
315
|
-
`alias`, `bash`, `chmod`, `clear`, `date`, `expr`, `false`, `help`, `history`, `seq`, `sh`, `sleep`, `time`, `timeout`, `true`, `unalias`, `which`, `whoami`
|
|
316
|
-
|
|
317
|
-
### Network Commands
|
|
318
|
-
|
|
319
|
-
`curl`, `html-to-markdown`
|
|
320
|
-
|
|
321
|
-
All commands support `--help` for usage information.
|
|
322
|
-
|
|
323
|
-
## Shell Features
|
|
324
|
-
|
|
325
|
-
- **Pipes**: `cmd1 | cmd2`
|
|
326
|
-
- **Redirections**: `>`, `>>`, `2>`, `2>&1`, `<`
|
|
327
|
-
- **Command chaining**: `&&`, `||`, `;`
|
|
328
|
-
- **Variables**: `$VAR`, `${VAR}`, `${VAR:-default}`
|
|
329
|
-
- **Positional parameters**: `$1`, `$2`, `$@`, `$#`
|
|
330
|
-
- **Glob patterns**: `*`, `?`, `[...]`
|
|
331
|
-
- **If statements**: `if COND; then CMD; elif COND; then CMD; else CMD; fi`
|
|
332
|
-
- **Functions**: `function name { ... }` or `name() { ... }`
|
|
333
|
-
- **Local variables**: `local VAR=value`
|
|
334
|
-
- **Loops**: `for`, `while`, `until`
|
|
335
|
-
- **Symbolic links**: `ln -s target link`
|
|
336
|
-
- **Hard links**: `ln target link`
|
|
337
|
-
|
|
338
|
-
## Default Layout
|
|
339
|
-
|
|
340
|
-
When created without options, Bash provides a Unix-like directory structure:
|
|
341
|
-
|
|
342
|
-
- `/home/user` - Default working directory (and `$HOME`)
|
|
343
|
-
- `/bin` - Contains stubs for all built-in commands
|
|
344
|
-
- `/usr/bin` - Additional binary directory
|
|
345
|
-
- `/tmp` - Temporary files directory
|
|
346
|
-
|
|
347
|
-
Commands can be invoked by path (e.g., `/bin/ls`) or by name.
|
|
348
|
-
|
|
349
|
-
## Network Access
|
|
350
|
-
|
|
351
|
-
Network access (and the `curl` command) is disabled by default for security. To enable it, configure the `network` option:
|
|
352
|
-
|
|
353
|
-
```typescript
|
|
354
|
-
// Allow specific URLs with GET/HEAD only (safest)
|
|
355
|
-
const env = new Bash({
|
|
356
|
-
network: {
|
|
357
|
-
allowedUrlPrefixes: [
|
|
358
|
-
"https://api.github.com/repos/myorg/",
|
|
359
|
-
"https://api.example.com",
|
|
360
|
-
],
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
// Allow specific URLs with additional methods
|
|
365
|
-
const env = new Bash({
|
|
366
|
-
network: {
|
|
367
|
-
allowedUrlPrefixes: ["https://api.example.com"],
|
|
368
|
-
allowedMethods: ["GET", "HEAD", "POST"], // Default: ["GET", "HEAD"]
|
|
369
|
-
},
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// Allow all URLs and methods (use with caution)
|
|
373
|
-
const env = new Bash({
|
|
374
|
-
network: { dangerouslyAllowFullInternetAccess: true },
|
|
375
|
-
});
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
**Note:** The `curl` command only exists when network is configured. Without network configuration, `curl` returns "command not found".
|
|
379
|
-
|
|
380
|
-
## Python Support
|
|
381
|
-
|
|
382
|
-
Python support via Pyodide is opt-in due to additional security surface. Enable it explicitly, but be aware of the risk:
|
|
383
|
-
|
|
384
|
-
```typescript
|
|
385
|
-
const env = new Bash({
|
|
386
|
-
python: true,
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// Execute Python code
|
|
390
|
-
await env.exec('python3 -c "print(1 + 2)"');
|
|
391
|
-
|
|
392
|
-
// Run Python scripts
|
|
393
|
-
await env.exec('python3 script.py');
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
**Note:** The `python3` and `python` commands only exist when `python: true` is configured. Python is not available in browser environments.
|
|
397
|
-
|
|
398
|
-
## SQLite Support
|
|
399
|
-
|
|
400
|
-
The `sqlite3` command uses sql.js (WASM-based SQLite) which is fully sandboxed and cannot access the real filesystem:
|
|
401
|
-
|
|
402
|
-
```typescript
|
|
403
|
-
const env = new Bash();
|
|
404
|
-
|
|
405
|
-
// Query in-memory database
|
|
406
|
-
await env.exec('sqlite3 :memory: "SELECT 1 + 1"');
|
|
407
|
-
|
|
408
|
-
// Query file-based database
|
|
409
|
-
await env.exec('sqlite3 data.db "SELECT * FROM users"');
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
**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.
|
|
413
|
-
|
|
414
|
-
### Allow-List Security
|
|
415
|
-
|
|
416
|
-
The allow-list enforces:
|
|
417
|
-
|
|
418
|
-
- **Origin matching**: URLs must match the exact origin (scheme + host + port)
|
|
419
|
-
- **Path prefix**: Only paths starting with the specified prefix are allowed
|
|
420
|
-
- **HTTP method restrictions**: Only GET and HEAD by default (configure `allowedMethods` for more)
|
|
421
|
-
- **Redirect protection**: Redirects to non-allowed URLs are blocked
|
|
422
|
-
|
|
423
|
-
### Using curl
|
|
424
|
-
|
|
425
|
-
```bash
|
|
426
|
-
# Fetch and process data
|
|
427
|
-
curl -s https://api.example.com/data | grep pattern
|
|
428
|
-
|
|
429
|
-
# Download and convert HTML to Markdown
|
|
430
|
-
curl -s https://example.com | html-to-markdown
|
|
431
|
-
|
|
432
|
-
# POST JSON data
|
|
433
|
-
curl -X POST -H "Content-Type: application/json" \
|
|
434
|
-
-d '{"key":"value"}' https://api.example.com/endpoint
|
|
435
|
-
```
|
|
436
|
-
|
|
437
519
|
## Execution Protection
|
|
438
520
|
|
|
439
521
|
Bash protects against infinite loops and deep recursion with configurable limits:
|
|
@@ -450,45 +532,35 @@ const env = new Bash({
|
|
|
450
532
|
});
|
|
451
533
|
```
|
|
452
534
|
|
|
453
|
-
All limits have
|
|
535
|
+
All limits have defaults. Error messages tell you which limit was hit. Increase as needed for your workload.
|
|
454
536
|
|
|
455
|
-
##
|
|
537
|
+
## Security Model
|
|
456
538
|
|
|
457
|
-
|
|
539
|
+
- The shell only has access to the provided filesystem.
|
|
540
|
+
- 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.
|
|
541
|
+
- There is no network access by default. When enabled, requests are checked against URL prefix allow-lists and HTTP-method allow-lists.
|
|
542
|
+
- Python and JavaScript execution are off by default as they represent additional security surface.
|
|
543
|
+
- Execution is protected against infinite loops and deep recursion with configurable limits.
|
|
544
|
+
- Use [Vercel Sandbox](https://vercel.com/docs/vercel-sandbox) if you need a full VM with arbitrary binary execution.
|
|
458
545
|
|
|
459
|
-
|
|
460
|
-
import { Bash, BashTransformPipeline, TeePlugin, CommandCollectorPlugin } from "just-bash";
|
|
546
|
+
## Browser Support
|
|
461
547
|
|
|
462
|
-
|
|
463
|
-
const pipeline = new BashTransformPipeline()
|
|
464
|
-
.use(new TeePlugin({ outputDir: "/tmp/logs" }))
|
|
465
|
-
.use(new CommandCollectorPlugin());
|
|
466
|
-
const result = pipeline.transform("echo hello | grep hello");
|
|
467
|
-
result.script; // transformed bash string
|
|
468
|
-
result.metadata.commands; // ["echo", "grep", "tee"]
|
|
548
|
+
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).
|
|
469
549
|
|
|
470
|
-
|
|
471
|
-
const bash = new Bash();
|
|
472
|
-
bash.registerTransformPlugin(new CommandCollectorPlugin());
|
|
473
|
-
const execResult = await bash.exec("echo hello | grep hello");
|
|
474
|
-
execResult.metadata?.commands; // ["echo", "grep"]
|
|
475
|
-
```
|
|
550
|
+
## Default Layout
|
|
476
551
|
|
|
477
|
-
|
|
552
|
+
When created without options, Bash provides a Unix-like directory structure:
|
|
478
553
|
|
|
479
|
-
|
|
554
|
+
- `/home/user` - Default working directory (and `$HOME`)
|
|
555
|
+
- `/bin` - Contains stubs for all built-in commands
|
|
556
|
+
- `/usr/bin` - Additional binary directory
|
|
557
|
+
- `/tmp` - Temporary files directory
|
|
480
558
|
|
|
481
|
-
|
|
482
|
-
pnpm test # Run tests in watch mode
|
|
483
|
-
pnpm test:run # Run tests once
|
|
484
|
-
pnpm typecheck # Type check without emitting
|
|
485
|
-
pnpm build # Build TypeScript
|
|
486
|
-
pnpm shell # Run interactive shell
|
|
487
|
-
```
|
|
559
|
+
Commands can be invoked by path (e.g., `/bin/ls`) or by name.
|
|
488
560
|
|
|
489
561
|
## AI Agent Instructions
|
|
490
562
|
|
|
491
|
-
For AI agents,
|
|
563
|
+
For AI agents, [`bash-tool`](https://github.com/vercel-labs/bash-tool) provides additional guidance in its `AGENTS.md`:
|
|
492
564
|
|
|
493
565
|
```bash
|
|
494
566
|
cat node_modules/bash-tool/dist/AGENTS.md
|